diff options
| -rw-r--r-- | .pre-commit-config.yaml | 2 | ||||
| -rw-r--r-- | bot/constants.py | 1 | ||||
| -rw-r--r-- | bot/exts/evergreen/snakes/_snakes_cog.py | 101 | ||||
| -rw-r--r-- | bot/exts/halloween/hacktoberstats.py | 45 | 
4 files changed, 81 insertions, 68 deletions
| diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index be57904e..a66bf97c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,6 +20,6 @@ repos:          name: Flake8          description: This hook runs flake8 within our project's pipenv environment.          entry: pipenv run flake8 -        language: python +        language: system          types: [python]          require_serial: true diff --git a/bot/constants.py b/bot/constants.py index ad850b92..fd4854b9 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -269,6 +269,7 @@ class Roles(NamedTuple):  class Tokens(NamedTuple):      giphy = environ.get("GIPHY_TOKEN") +    aoc_session_cookie = environ.get("AOC_SESSION_COOKIE")      omdb = environ.get("OMDB_API_KEY")      youtube = environ.get("YOUTUBE_API_KEY")      tmdb = environ.get("TMDB_API_KEY") diff --git a/bot/exts/evergreen/snakes/_snakes_cog.py b/bot/exts/evergreen/snakes/_snakes_cog.py index 4fa4dcd1..d5e4f206 100644 --- a/bot/exts/evergreen/snakes/_snakes_cog.py +++ b/bot/exts/evergreen/snakes/_snakes_cog.py @@ -15,6 +15,7 @@ import aiohttp  import async_timeout  from PIL import Image, ImageDraw, ImageFont  from discord import Colour, Embed, File, Member, Message, Reaction +from discord.errors import HTTPException  from discord.ext.commands import Bot, Cog, CommandError, Context, bot_has_permissions, group  from bot.constants import ERROR_REPLIES, Tokens @@ -151,6 +152,7 @@ class Snakes(Cog):          self.snake_idioms = utils.get_resource("snake_idioms")          self.snake_quizzes = utils.get_resource("snake_quiz")          self.snake_facts = utils.get_resource("snake_facts") +        self.num_movie_pages = None      # region: Helper methods      @staticmethod @@ -739,71 +741,68 @@ class Snakes(Cog):      @snakes_group.command(name='movie')      async def movie_command(self, ctx: Context) -> None:          """ -        Gets a random snake-related movie from OMDB. +        Gets a random snake-related movie from TMDB.          Written by Samuel.          Modified by gdude. +        Modified by Will Da Silva.          """ -        url = "http://www.omdbapi.com/" -        page = random.randint(1, 27) +        # Initially 8 pages are fetched. The actual number of pages is set after the first request. +        page = random.randint(1, self.num_movie_pages or 8) -        response = await self.bot.http_session.get( -            url, -            params={ -                "s": "snake", -                "page": page, -                "type": "movie", -                "apikey": Tokens.omdb -            } -        ) -        data = await response.json() -        movie = random.choice(data["Search"])["imdbID"] - -        response = await self.bot.http_session.get( -            url, -            params={ -                "i": movie, -                "apikey": Tokens.omdb -            } -        ) -        data = await response.json() - -        embed = Embed( -            title=data["Title"], -            color=SNAKE_COLOR -        ) - -        del data["Response"], data["imdbID"], data["Title"] - -        for key, value in data.items(): -            if not value or value == "N/A" or key in ("Response", "imdbID", "Title", "Type"): -                continue +        async with ctx.typing(): +            response = await self.bot.http_session.get( +                "https://api.themoviedb.org/3/search/movie", +                params={ +                    "query": "snake", +                    "page": page, +                    "language": "en-US", +                    "api_key": Tokens.tmdb, +                } +            ) +            data = await response.json() +            if self.num_movie_pages is None: +                self.num_movie_pages = data["total_pages"] +            movie = random.choice(data["results"])["id"] + +            response = await self.bot.http_session.get( +                f"https://api.themoviedb.org/3/movie/{movie}", +                params={ +                    "language": "en-US", +                    "api_key": Tokens.tmdb, +                } +            ) +            data = await response.json() -            if key == "Ratings":  # [{'Source': 'Internet Movie Database', 'Value': '7.6/10'}] -                rating = random.choice(value) +        embed = Embed(title=data["title"], color=SNAKE_COLOR) -                if rating["Source"] != "Internet Movie Database": -                    embed.add_field(name=f"Rating: {rating['Source']}", value=rating["Value"]) +        if data["poster_path"] is not None: +            embed.set_image(url=f"https://images.tmdb.org/t/p/original{data['poster_path']}") -                continue +        if data["overview"]: +            embed.add_field(name="Overview", value=data["overview"]) -            if key == "Poster": -                embed.set_image(url=value) -                continue +        if data["release_date"]: +            embed.add_field(name="Release Date", value=data["release_date"]) -            elif key == "imdbRating": -                key = "IMDB Rating" +        if data["genres"]: +            embed.add_field(name="Genres", value=", ".join([x["name"] for x in data["genres"]])) -            elif key == "imdbVotes": -                key = "IMDB Votes" +        if data["vote_count"]: +            embed.add_field(name="Rating", value=f"{data['vote_average']}/10 ({data['vote_count']} votes)", inline=True) -            embed.add_field(name=key, value=value, inline=True) +        if data["budget"] and data["revenue"]: +            embed.add_field(name="Budget", value=data["budget"], inline=True) +            embed.add_field(name="Revenue", value=data["revenue"], inline=True) -        embed.set_footer(text="Data provided by the OMDB API") +        embed.set_footer(text="This product uses the TMDb API but is not endorsed or certified by TMDb.") +        embed.set_thumbnail(url="https://i.imgur.com/LtFtC8H.png") -        await ctx.channel.send( -            embed=embed -        ) +        try: +            await ctx.channel.send(embed=embed) +        except HTTPException as err: +            await ctx.channel.send("An error occurred while fetching a snake-related movie!") +            raise err from None      @snakes_group.command(name='quiz')      @locked() diff --git a/bot/exts/halloween/hacktoberstats.py b/bot/exts/halloween/hacktoberstats.py index 84b75022..a1c55922 100644 --- a/bot/exts/halloween/hacktoberstats.py +++ b/bot/exts/halloween/hacktoberstats.py @@ -1,15 +1,16 @@  import logging +import random  import re  from collections import Counter  from datetime import datetime, timedelta -from typing import List, Tuple, Union +from typing import List, Optional, Tuple, Union  import aiohttp  import discord  from async_rediscache import RedisCache  from discord.ext import commands -from bot.constants import Channels, Month, Tokens, WHITELISTED_CHANNELS +from bot.constants import Channels, Month, NEGATIVE_REPLIES, Tokens, WHITELISTED_CHANNELS  from bot.utils.decorators import in_month, override_in_channel  log = logging.getLogger(__name__) @@ -125,18 +126,28 @@ class HacktoberStats(commands.Cog):          async with ctx.typing():              prs = await self.get_october_prs(github_username) +            if prs is None:  # Will be None if the user was not found +                await ctx.send( +                    embed=discord.Embed( +                        title=random.choice(NEGATIVE_REPLIES), +                        description=f"GitHub user `{github_username}` was not found.", +                        colour=discord.Colour.red() +                    ) +                ) +                return +              if prs:                  stats_embed = await self.build_embed(github_username, prs)                  await ctx.send('Here are some stats!', embed=stats_embed)              else: -                await ctx.send(f"No valid October GitHub contributions found for '{github_username}'") +                await ctx.send(f"No valid Hacktoberfest PRs found for '{github_username}'")      async def build_embed(self, github_username: str, prs: List[dict]) -> discord.Embed:          """Return a stats embed built from github_username's PRs."""          logging.info(f"Building Hacktoberfest embed for GitHub user: '{github_username}'")          in_review, accepted = await self._categorize_prs(prs) -        n = len(accepted) + len(in_review)  # total number of PRs +        n = len(accepted) + len(in_review)  # Total number of PRs          if n >= PRS_FOR_SHIRT:              shirtstr = f"**{github_username} is eligible for a T-shirt or a tree!**"          elif n == PRS_FOR_SHIRT - 1: @@ -162,7 +173,7 @@ class HacktoberStats(commands.Cog):              icon_url="https://avatars1.githubusercontent.com/u/35706162?s=200&v=4"          ) -        # this will handle when no PRs in_review or accepted +        # This will handle when no PRs in_review or accepted          review_str = self._build_prs_string(in_review, github_username) or "None"          accepted_str = self._build_prs_string(accepted, github_username) or "None"          stats_embed.add_field( @@ -178,7 +189,7 @@ class HacktoberStats(commands.Cog):          return stats_embed      @staticmethod -    async def get_october_prs(github_username: str) -> Union[List[dict], None]: +    async def get_october_prs(github_username: str) -> Optional[List[dict]]:          """          Query GitHub's API for PRs created during the month of October by github_username. @@ -198,7 +209,8 @@ class HacktoberStats(commands.Cog):              "number": int          } -        Otherwise, return None +        Otherwise, return empty list. +        None will be returned when the GitHub user was not found.          """          logging.info(f"Fetching Hacktoberfest Stats for GitHub user: '{github_username}'")          base_url = "https://api.github.com/search/issues?q=" @@ -226,14 +238,15 @@ class HacktoberStats(commands.Cog):              # Ignore logging non-existent users or users we do not have permission to see              if api_message == GITHUB_NONEXISTENT_USER_MESSAGE:                  logging.debug(f"No GitHub user found named '{github_username}'") +                return              else:                  logging.error(f"GitHub API request for '{github_username}' failed with message: {api_message}") -            return +            return []  # No October PRs were found due to error          if jsonresp["total_count"] == 0:              # Short circuit if there aren't any PRs -            logging.info(f"No Hacktoberfest PRs found for GitHub user: '{github_username}'") -            return +            logging.info(f"No October PRs found for GitHub user: '{github_username}'") +            return []          logging.info(f"Found {len(jsonresp['items'])} Hacktoberfest PRs for GitHub user: '{github_username}'")          outlist = []  # list of pr information dicts that will get returned @@ -250,7 +263,7 @@ class HacktoberStats(commands.Cog):                  "number": item["number"]              } -            # if the PR has 'invalid' or 'spam' labels, the PR must be +            # If the PR has 'invalid' or 'spam' labels, the PR must be              # either merged or approved for it to be included              if HacktoberStats._has_label(item, ["invalid", "spam"]):                  if not await HacktoberStats._is_accepted(itemdict): @@ -263,28 +276,28 @@ class HacktoberStats(commands.Cog):                  outlist.append(itemdict)                  continue -            # checking PR's labels for "hacktoberfest-accepted" +            # Checking PR's labels for "hacktoberfest-accepted"              if HacktoberStats._has_label(item, "hacktoberfest-accepted"):                  outlist.append(itemdict)                  continue -            # no need to query github if repo topics are fetched before already +            # No need to query GitHub if repo topics are fetched before already              if shortname in hackto_topics.keys():                  if hackto_topics[shortname]:                      outlist.append(itemdict)                      continue -            # fetch topics for the pr repo +            # Fetch topics for the PR's repo              topics_query_url = f"https://api.github.com/repos/{shortname}/topics"              logging.debug(f"Fetching repo topics for {shortname} with url: {topics_query_url}")              jsonresp2 = await HacktoberStats._fetch_url(topics_query_url, GITHUB_TOPICS_ACCEPT_HEADER)              if jsonresp2.get("names") is None:                  logging.error(f"Error fetching topics for {shortname}: {jsonresp2['message']}") -                return +                continue  # Assume the repo doesn't have the `hacktoberfest` topic if API  request errored              # PRs after oct 3 that doesn't have 'hacktoberfest-accepted' label              # must be in repo with 'hacktoberfest' topic              if "hacktoberfest" in jsonresp2["names"]: -                hackto_topics[shortname] = True  # cache result in the dict for later use if needed +                hackto_topics[shortname] = True  # Cache result in the dict for later use if needed                  outlist.append(itemdict)          return outlist | 
