Pārlūkot izejas kodu

Building/sending embed messages for AniList feeds

Lucas Villeneuve 5 gadi atpakaļ
vecāks
revīzija
37410206f1
3 mainītis faili ar 120 papildinājumiem un 16 dzēšanām
  1. 109 9
      src/anilist.py
  2. 1 0
      src/globals.py
  3. 10 7
      src/myanimebot.py

+ 109 - 9
src/anilist.py

@@ -4,6 +4,8 @@ import datetime
 from enum import Enum
 
 import globals
+import myanimebot
+import utils
 
 ANILIST_GRAPHQL_URL = 'https://graphql.anilist.co'
 
@@ -21,6 +23,16 @@ class MediaType(Enum):
     ANIME="ANIME"
     MANGA="MANGA"
 
+    @staticmethod
+    def from_str(label: str):
+        if label.upper() in ('ANIME', 'ANIME_LIST'):
+            return MediaType.ANIME
+        elif label.upper() in ('MANGA', 'MANGA_LIST'):
+            return MediaType.MANGA
+        else:
+            raise NotImplementedError('Error: Cannot convert "{}" to a MediaType'.format(label))
+
+
 def get_mal_id_from_anilist_id(anilist_media_id, media_type: MediaType):
     """ Converts an AniList media ID to a MyAnimeList ID and returns it """
 
@@ -48,6 +60,27 @@ def get_mal_id_from_anilist_id(anilist_media_id, media_type: MediaType):
         print(e)
     return None
 
+def get_thumbnail_from_anilist_id(anilist_media_id, media_type: MediaType):
+    """ Returns the MAL thumbnail from an AniList media ID """
+
+    # TODO Catch exception or if is None
+    print("Trying to get MAL ID from AniList ID {}".format(anilist_media_id))
+    mal_id = get_mal_id_from_anilist_id(anilist_media_id, media_type)
+    print("Got MAL ID {} from AniList ID {}".format(mal_id, anilist_media_id))
+
+    # Building MyAnimeList URL
+    mal_url = globals.MAL_URL
+    if media_type == MediaType.ANIME:
+        mal_url += "anime/"
+    elif media_type == MediaType.MANGA:
+        mal_url += "manga/"
+    else:
+        raise Exception("Error when getting thumbnail from AniList ID {} : Unknown Mediatype {}".format(anilist_media_id, media_type))
+    mal_url += str(mal_id)
+
+    print("Getting thumbnail from URL '{}'".format(mal_url))
+    return utils.getThumbnail(mal_url)
+
 
 def get_anilist_userId_from_name(user_name : str):
     """ Searches an AniList user by its name and returns its ID """
@@ -162,6 +195,60 @@ def get_latest_activity(users_id):
     return None
 
 
+async def send_embed_to_channels(activity):
+
+    # Fetch user's data
+    try:
+        db_user = globals.conn.cursor(buffered=True)
+        db_user.execute("SELECT mal_user, servers FROM t_users")
+        data_user = db_user.fetchone()
+    except Exception as e:
+        # TODO Catch exception
+        globals.logger.critical("Database unavailable! (" + str(e) + ")")
+        quit()
+
+    # TODO Fetch and insert AniList thumbnail
+    # Fetch image's data
+    # cursor.execute("SELECT thumbnail FROM t_animes WHERE guid=%s LIMIT 1", [item.guid])
+    # data_img = cursor.fetchone()
+    
+    # if data_img is None:
+    try:
+        # TODO Directly send malId instead
+        image = get_thumbnail_from_anilist_id(activity["media"]["id"], MediaType.from_str(activity["type"]))
+        
+        globals.logger.info("First time seeing this " + activity["media"]["title"]["english"] + ", adding thumbnail into database: " + image)
+    except Exception as e:
+        globals.logger.warning("Error while getting the thumbnail: " + str(e))
+        image = ""
+            
+        # cursor.execute("INSERT INTO t_animes (guid, title, thumbnail, found, discoverer, media) VALUES (%s, %s, %s, NOW(), %s, %s)", [item.guid, item.title, image, user, media])
+        # globals.conn.commit()
+    # else: image = data_img[0]
+
+
+    for server in data_user[1].split(","):
+        db_srv = globals.conn.cursor(buffered=True)
+        db_srv.execute("SELECT channel FROM t_servers WHERE server = %s", [server])
+        data_channel = db_srv.fetchone()
+    
+        # FIXME 'Completed None'
+        while data_channel is not None:
+            for channel in data_channel:
+                await myanimebot.send_embed_wrapper(None,
+                                                    channel,
+                                                    globals.client,
+                                                    myanimebot.build_embed(activity["user"]["name"],
+                                                                            activity["media"]["title"]["english"],
+                                                                            activity["media"]["siteUrl"],
+                                                                            "{} {}".format(activity["status"], activity["progress"]),
+                                                                            datetime.datetime.fromtimestamp(activity["createdAt"]),
+                                                                            image))
+            
+            data_channel = db_srv.fetchone()
+
+
+
 def insert_feed_db(activity):
     cursor = globals.conn.cursor(buffered=True)
 
@@ -175,7 +262,7 @@ def insert_feed_db(activity):
     globals.conn.commit()
 
 
-def process_new_activities(last_activity_date):
+async def process_new_activities(last_activity_date):
     """ Fetch and process all newest activities """
     
     continue_fetching = True
@@ -194,15 +281,19 @@ def process_new_activities(last_activity_date):
 
             # Get time difference between now and activity creation date
             diffTime = datetime.datetime.now(globals.timezone) - datetime.datetime.fromtimestamp(activity["createdAt"], globals.timezone)
+
+            print("Time difference between feed and now = {}".format(diffTime))
             # If the activity is older than the last_activity_date, we processed all the newest activities
             # Also, if the time difference is bigger than the config's "secondMax", we can stop processing them
-            if activity["createdAt"] < last_activity_date or diffTime.total_seconds() > globals.secondMax:
+            if activity["createdAt"] <= last_activity_date or diffTime.total_seconds() > globals.secondMax:
+                # FIXME If two or more feeds are published at the same time, this would skip them
                 continue_fetching = False
                 break
             # Process activity
             # TODO Add logger infos
             insert_feed_db(activity)
             # TODO Create embed and send to channels
+            await send_embed_to_channels(activity)
 
         # Load next activities page
         # TODO How can I avoid duplicate if insertion in between? With storing ids?
@@ -213,18 +304,22 @@ def process_new_activities(last_activity_date):
 
 
 def get_last_activity_date_db():
+    # Refresh database
+    globals.conn.commit()
+
+    # Get last activity date
     cursor = globals.conn.cursor(buffered=True)
     cursor.execute("SELECT published FROM t_feeds WHERE service=%s ORDER BY published DESC LIMIT 1", [globals.SERVICE_ANILIST])
     data = cursor.fetchone()
 
-    print(data)
-    if data is None:
+    print("Getting last activity date : {}".format(data))
+    if data is None or len(data) == 0:
         return 0
     else:
-        return int(data)
+        return data[0].timestamp()
 
 
-def check_new_activities():
+async def check_new_activities():
     """ Check if there is new activities and process them """
     
     # last_activity_date = 1608340203 # TODO SELECT DATE IN DB
@@ -238,13 +333,18 @@ def check_new_activities():
         # If the latest activity is more recent than the last we stored
         if last_activity_date < latest_activity["createdAt"]:
             print("Latest activity is more recent")
-            process_new_activities(last_activity_date)
+            await process_new_activities(last_activity_date)
             
 
 # [x] Convertir AniList ID en MAL ID
 # [ ] Recuperer utilisateurs qui nous interessent
 # [X] Recuperer activites de ces users
 # [X] Traiter les donnees et les mettre en DB
-# [ ] Creer embed et envoyer messages
+# [X] Creer embed et envoyer messages
 # [ ] Faire task pour fetch automatiquement
-# [ ] Rajouter requests dans la liste de dependances pip (Site de Penta)
+# [ ] Rajouter requests dans la liste de dependances pip (Site de Penta)
+
+# TODO Changer titre (Pour l'instant c'est MAL de XXX)
+# TODO Bien renvoyer vers AniList (Liens/Liste/Anime)
+# TODO Recuperer image d'AniList
+# TODO Comment eviter doublons MAL/AniList

+ 1 - 0
src/globals.py

@@ -56,6 +56,7 @@ iconMAL=CONFIG.get("iconMAL", "https://cdn.myanimelist.net/img/sp/icon/apple-tou
 iconBot=CONFIG.get("iconBot", "http://myanimebot.pentou.eu/rsc/bot_avatar.jpg")
 SERVICE_ANILIST="AniList"
 SERVICE_MAL="mal"
+MAL_URL="https://myanimelist.net/"
 
 # class that send logs to DB
 class LogDBHandler(logging.Handler):

+ 10 - 7
src/myanimebot.py

@@ -41,9 +41,12 @@ if not sys.version_info[:2] >= (3, 7):
 	exit(1)
 
 # Function used to make the embed message related to the animes status
-def build_embed(user, item, channel, pubDate, image):
+def build_embed(user, item_title, item_link, item_description, pub_date, image):
 	try:	
-		embed = discord.Embed(colour=0xEED000, url=item.link, description="[" + utils.filter_name(item.title) + "](" + item.link + ")\n```" + item.description + "```", timestamp=pubDate.astimezone(pytz.timezone("utc")))
+		embed = discord.Embed(colour=0xEED000,
+								url=item_link,
+								description="[" + utils.filter_name(item_title) + "](" + item_link + ")\n```" + item_description + "```",
+								timestamp=pub_date.astimezone(pytz.timezone("utc")))
 		embed.set_thumbnail(url=image)
 		embed.set_author(name=user + "'s MyAnimeList", url="https://myanimelist.net/profile/" + user, icon_url=globals.iconMAL)
 		embed.set_footer(text="MyAnimeBot", icon_url=globals.iconBot)
@@ -134,7 +137,7 @@ async def background_check_feed(asyncioloop):
 								
 								if data_img is None:
 									try:
-										image = globals.utils.getThumbnail(item.link)
+										image = utils.getThumbnail(item.link)
 										
 										globals.logger.info("First time seeing this " + media + ", adding thumbnail into database: " + image)
 									except Exception as e:
@@ -156,7 +159,7 @@ async def background_check_feed(asyncioloop):
 									data_channel = db_srv.fetchone()
 									
 									while data_channel is not None:
-										for channel in data_channel: await send_embed_wrapper(asyncioloop, channel, globals.client, build_embed(user, item, channel, pubDateRaw, image))
+										for channel in data_channel: await send_embed_wrapper(asyncioloop, channel, globals.client, build_embed(user, item.title, item.link, item.description, pubDateRaw, image))
 										
 										data_channel = db_srv.fetchone()
 					if feed_type == 1:
@@ -173,12 +176,12 @@ async def background_check_feed(asyncioloop):
 			data_user = db_user.fetchone()
 
 
-def fetch_activities_anilist():
+async def fetch_activities_anilist():
 	print("Fetching activities")
 
 	feed = {'__typename': 'ListActivity', 'id': 150515141, 'type': 'ANIME_LIST', 'status': 'rewatched episode', 'progress': '10 - 12', 'isLocked': False, 'createdAt': 1608738377, 'user': {'id': 102213, 'name': 'lululekiddo'}, 'media': {'id': 5081, 'siteUrl': 'https://anilist.co/anime/5081', 'title': {'romaji': 'Bakemonogatari', 'english': 'Bakemonogatari'}}}
 
-	anilist.check_new_activities()
+	await anilist.check_new_activities()
 
 
 @globals.client.event
@@ -428,7 +431,7 @@ async def on_message(message):
 					await message.channel.send("You have to specify a group!")
 
 			elif words[1] == "fetch-debug":
-				fetch_activities_anilist()
+				await fetch_activities_anilist()
 
 	# If mentioned
 	elif globals.client.user in message.mentions: