diff options
Diffstat (limited to 'bot/seasons/evergreen/space.py')
| -rw-r--r-- | bot/seasons/evergreen/space.py | 240 | 
1 files changed, 0 insertions, 240 deletions
diff --git a/bot/seasons/evergreen/space.py b/bot/seasons/evergreen/space.py deleted file mode 100644 index 89b31e87..00000000 --- a/bot/seasons/evergreen/space.py +++ /dev/null @@ -1,240 +0,0 @@ -import logging -import random -from datetime import datetime -from typing import Any, Dict, Optional, Union -from urllib.parse import urlencode - -from discord import Embed -from discord.ext import tasks -from discord.ext.commands import BadArgument, Cog, Context, Converter, group - -from bot.bot import SeasonalBot -from bot.constants import Tokens - -logger = logging.getLogger(__name__) - -NASA_BASE_URL = "https://api.nasa.gov" -NASA_IMAGES_BASE_URL = "https://images-api.nasa.gov" -NASA_EPIC_BASE_URL = "https://epic.gsfc.nasa.gov" - - -class DateConverter(Converter): -    """Parse SOL or earth date (in format YYYY-MM-DD) into `int` or `datetime`. When invalid input, raise error.""" - -    async def convert(self, ctx: Context, argument: str) -> Union[int, datetime]: -        """Parse date (SOL or earth) into `datetime` or `int`. When invalid value, raise error.""" -        if argument.isdigit(): -            return int(argument) -        try: -            date = datetime.strptime(argument, "%Y-%m-%d") -        except ValueError: -            raise BadArgument(f"Can't convert `{argument}` to `datetime` in format `YYYY-MM-DD` or `int` in SOL.") -        return date - - -class Space(Cog): -    """Space Cog contains commands, that show images, facts or other information about space.""" - -    def __init__(self, bot: SeasonalBot): -        self.bot = bot -        self.http_session = bot.http_session - -        self.rovers = {} -        self.get_rovers.start() - -    def cog_unload(self) -> None: -        """Cancel `get_rovers` task when Cog will unload.""" -        self.get_rovers.cancel() - -    @tasks.loop(hours=24) -    async def get_rovers(self) -> None: -        """Get listing of rovers from NASA API and info about their start and end dates.""" -        data = await self.fetch_from_nasa("mars-photos/api/v1/rovers") - -        for rover in data["rovers"]: -            self.rovers[rover["name"].lower()] = { -                "min_date": rover["landing_date"], -                "max_date": rover["max_date"], -                "max_sol": rover["max_sol"] -            } - -    @group(name="space", invoke_without_command=True) -    async def space(self, ctx: Context) -> None: -        """Head command that contains commands about space.""" -        await ctx.send_help("space") - -    @space.command(name="apod") -    async def apod(self, ctx: Context, date: Optional[str] = None) -> None: -        """ -        Get Astronomy Picture of Day from NASA API. Date is optional parameter, what formatting is YYYY-MM-DD. - -        If date is not specified, this will get today APOD. -        """ -        params = {} -        # Parse date to params, when provided. Show error message when invalid formatting -        if date: -            try: -                params["date"] = datetime.strptime(date, "%Y-%m-%d").date().isoformat() -            except ValueError: -                await ctx.send(f"Invalid date {date}. Please make sure your date is in format YYYY-MM-DD.") -                return - -        result = await self.fetch_from_nasa("planetary/apod", params) - -        await ctx.send( -            embed=self.create_nasa_embed( -                f"Astronomy Picture of the Day - {result['date']}", -                result["explanation"], -                result["url"] -            ) -        ) - -    @space.command(name="nasa") -    async def nasa(self, ctx: Context, *, search_term: Optional[str] = None) -> None: -        """Get random NASA information/facts + image. Support `search_term` parameter for more specific search.""" -        params = { -            "media_type": "image" -        } -        if search_term: -            params["q"] = search_term - -        # Don't use API key, no need for this. -        data = await self.fetch_from_nasa("search", params, NASA_IMAGES_BASE_URL, use_api_key=False) -        if len(data["collection"]["items"]) == 0: -            await ctx.send(f"Can't find any items with search term `{search_term}`.") -            return - -        item = random.choice(data["collection"]["items"]) - -        await ctx.send( -            embed=self.create_nasa_embed( -                item["data"][0]["title"], -                item["data"][0]["description"], -                item["links"][0]["href"] -            ) -        ) - -    @space.command(name="epic") -    async def epic(self, ctx: Context, date: Optional[str] = None) -> None: -        """Get one of latest random image of earth from NASA EPIC API. Support date parameter, format is YYYY-MM-DD.""" -        if date: -            try: -                show_date = datetime.strptime(date, "%Y-%m-%d").date().isoformat() -            except ValueError: -                await ctx.send(f"Invalid date {date}. Please make sure your date is in format YYYY-MM-DD.") -                return -        else: -            show_date = None - -        # Don't use API key, no need for this. -        data = await self.fetch_from_nasa( -            f"api/natural{f'/date/{show_date}' if show_date else ''}", -            base=NASA_EPIC_BASE_URL, -            use_api_key=False -        ) -        if len(data) < 1: -            await ctx.send("Can't find any images in this date.") -            return - -        item = random.choice(data) - -        year, month, day = item["date"].split(" ")[0].split("-") -        image_url = f"{NASA_EPIC_BASE_URL}/archive/natural/{year}/{month}/{day}/jpg/{item['image']}.jpg" - -        await ctx.send( -            embed=self.create_nasa_embed( -                "Earth Image", item["caption"], image_url, f" \u2022 Identifier: {item['identifier']}" -            ) -        ) - -    @space.group(name="mars", invoke_without_command=True) -    async def mars( -        self, -        ctx: Context, -        date: Optional[DateConverter] = None, -        rover: Optional[str] = "curiosity" -    ) -> None: -        """ -        Get random Mars image by date. Support both SOL (martian solar day) and earth date and rovers. - -        Earth date formatting is YYYY-MM-DD. Use `.space mars dates` to get all currently available rovers. -        """ -        rover = rover.lower() -        if rover not in self.rovers: -            await ctx.send( -                ( -                    f"Invalid rover `{rover}`.\n" -                    f"**Rovers:** `{'`, `'.join(f'{r.capitalize()}' for r in self.rovers)}`" -                ) -            ) -            return - -        # When date not provided, get random SOL date between 0 and rover's max. -        if date is None: -            date = random.randint(0, self.rovers[rover]["max_sol"]) - -        params = {} -        if isinstance(date, int): -            params["sol"] = date -        else: -            params["earth_date"] = date.date().isoformat() - -        result = await self.fetch_from_nasa(f"mars-photos/api/v1/rovers/{rover}/photos", params) -        if len(result["photos"]) < 1: -            err_msg = ( -                f"We can't find result in date " -                f"{date.date().isoformat() if isinstance(date, datetime) else f'{date} SOL'}.\n" -                f"**Note:** Dates must match with rover's working dates. Please use `{ctx.prefix}space mars dates` to " -                "see working dates for each rover." -            ) -            await ctx.send(err_msg) -            return - -        item = random.choice(result["photos"]) -        await ctx.send( -            embed=self.create_nasa_embed( -                f"{item['rover']['name']}'s {item['camera']['full_name']} Mars Image", "", item["img_src"], -            ) -        ) - -    @mars.command(name="dates", aliases=["d", "date", "rover", "rovers", "r"]) -    async def dates(self, ctx: Context) -> None: -        """Get current available rovers photo date ranges.""" -        await ctx.send("\n".join( -            f"**{r.capitalize()}:** {i['min_date']} **-** {i['max_date']}" for r, i in self.rovers.items() -        )) - -    async def fetch_from_nasa( -        self, -        endpoint: str, -        additional_params: Optional[Dict[str, Any]] = None, -        base: Optional[str] = NASA_BASE_URL, -        use_api_key: bool = True -    ) -> Dict[str, Any]: -        """Fetch information from NASA API, return result.""" -        params = {} -        if use_api_key: -            params["api_key"] = Tokens.nasa - -        # Add additional parameters to request parameters only when they provided by user -        if additional_params is not None: -            params.update(additional_params) - -        async with self.http_session.get(url=f"{base}/{endpoint}?{urlencode(params)}") as resp: -            return await resp.json() - -    def create_nasa_embed(self, title: str, description: str, image: str, footer: Optional[str] = "") -> Embed: -        """Generate NASA commands embeds. Required: title, description and image URL, footer (addition) is optional.""" -        return Embed( -            title=title, -            description=description -        ).set_image(url=image).set_footer(text="Powered by NASA API" + footer) - - -def setup(bot: SeasonalBot) -> None: -    """Load Space Cog.""" -    if not Tokens.nasa: -        logger.warning("Can't find NASA API key. Not loading Space Cog.") -        return - -    bot.add_cog(Space(bot))  |