meme dupe snitching/misc
This commit is contained in:
		| @@ -100,7 +100,7 @@ class Util: | ||||
|         top_formatted: str = "" | ||||
|         for x, item in enumerate(top): | ||||
|             top_formatted += ( | ||||
|                 f"{x+1}. **{discord.utils.escape_markdown(item[0])}**: *{item[1]}*\n" | ||||
|                 f"{x + 1}. **{discord.utils.escape_markdown(item[0])}**: *{item[1]}*\n" | ||||
|             ) | ||||
|         top_formatted = top_formatted.strip() | ||||
|         embed: discord.Embed = discord.Embed( | ||||
|   | ||||
							
								
								
									
										85
									
								
								cogs/meme.py
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								cogs/meme.py
									
									
									
									
									
								
							| @@ -4,6 +4,9 @@ import json | ||||
| import io | ||||
| import asyncio | ||||
| import random | ||||
| import copy | ||||
| from PIL import Image, UnidentifiedImageError | ||||
| import imagehash | ||||
| from typing import LiteralString, Optional, Any, Union | ||||
| import aiosqlite as sqlite3 | ||||
| import logging | ||||
| @@ -132,9 +135,12 @@ class Meme(commands.Cog): | ||||
|  | ||||
|     def __init__(self, bot: Havoc) -> None: | ||||
|         self.bot: Havoc = bot | ||||
|         self.stats_db_path: LiteralString = os.path.join( | ||||
|         self.stats_db_path: str = os.path.join( | ||||
|             "/usr/local/share", "sqlite_dbs", "stats.db" | ||||
|         ) | ||||
|         self.memedb_path: str = os.path.join( | ||||
|             "/usr/local/share", "sqlite_dbs", "meme.db" | ||||
|         ) | ||||
|         self.meme_choices: list = [] | ||||
|         self.meme_counter: int = 0 | ||||
|         self.THREADS: dict[str, dict[int, list]] = { | ||||
| @@ -243,6 +249,45 @@ class Meme(commands.Cog): | ||||
|                     count = result["count"] | ||||
|                     self.meme_leaderboard[uid] = count | ||||
|  | ||||
|     async def insert_meme( | ||||
|         self, discord_uid: int, timestamp: int, message_id: int, image_url: str | ||||
|     ) -> Optional[bool]: | ||||
|         """ | ||||
|         INSERT MEME -> SQLITE DB | ||||
|         """ | ||||
|         try: | ||||
|             _image: io.BytesIO = io.BytesIO( | ||||
|                 requests.get(image_url, stream=True, timeout=20).raw.read() | ||||
|             ) | ||||
|             image_copy = copy.deepcopy(_image) | ||||
|             image = Image.open(image_copy) | ||||
|         except UnidentifiedImageError: | ||||
|             return None | ||||
|         phash: str = str(imagehash.phash(image)) | ||||
|         query: str = "INSERT INTO memes(discord_uid, timestamp, image, message_ids, phash) VALUES(?, ?, ?, ?, ?)" | ||||
|         async with sqlite3.connect(self.memedb_path, timeout=2) as db_conn: | ||||
|             insert = await db_conn.execute_insert( | ||||
|                 query, (discord_uid, timestamp, _image.read(), message_id, phash) | ||||
|             ) | ||||
|             if insert: | ||||
|                 await db_conn.commit() | ||||
|                 return True | ||||
|             return None | ||||
|  | ||||
|     async def dupe_check(self, image) -> bool | int: | ||||
|         """ | ||||
|         CHECK DB FOR DUPLICATE MEMES! | ||||
|         """ | ||||
|         phash: str = str(imagehash.phash(image)) | ||||
|         query: str = "SELECT message_ids FROM memes WHERE phash = ? LIMIT 1" | ||||
|         async with sqlite3.connect(self.memedb_path, timeout=2) as db_conn: | ||||
|             db_conn.row_factory = sqlite3.Row | ||||
|             async with await db_conn.execute(query, (phash,)) as db_cursor: | ||||
|                 result = await db_cursor.fetchone() | ||||
|                 if result: | ||||
|                     return result["message_ids"] | ||||
|         return False | ||||
|  | ||||
|     @commands.Cog.listener() | ||||
|     async def on_ready(self) -> None: | ||||
|         """Run on Bot Ready""" | ||||
| @@ -644,6 +689,7 @@ class Meme(commands.Cog): | ||||
|         Also monitors for messages to #memes-top-10 to autodelete, only Havoc may post in #memes-top-10! | ||||
|         """ | ||||
|         lb_chanid: int = 1352373745108652145 | ||||
|         meme_chanid: int = 1147229098544988261 | ||||
|         if not self.bot.user:  # No valid client instance | ||||
|             return | ||||
|         if not isinstance(message.channel, discord.TextChannel): | ||||
| @@ -666,12 +712,37 @@ class Meme(commands.Cog): | ||||
|             return | ||||
|         if not message.guild: | ||||
|             return | ||||
|         if not message.channel.id == 1147229098544988261:  # Not meme channel | ||||
|         if message.channel.id not in [ | ||||
|             1157529874936909934, | ||||
|             meme_chanid, | ||||
|         ]:  # Not meme channel | ||||
|             return | ||||
|         if not message.attachments:  # No attachments to consider a meme | ||||
|             return | ||||
|  | ||||
|         await self.leaderboard_increment(message.author.id) | ||||
|         unique_memes: list = [] | ||||
|         for item in message.attachments: | ||||
|             if item.url and len(item.url) >= 20: | ||||
|                 image: io.BytesIO = io.BytesIO( | ||||
|                     requests.get(item.url, stream=True, timeout=20).raw.read() | ||||
|                 ) | ||||
|                 dupe_check = await self.dupe_check(Image.open(image)) | ||||
|                 if dupe_check: | ||||
|                     channel = message.channel | ||||
|                     original_message = await channel.fetch_message(dupe_check)  # type: ignore | ||||
|                     original_message_url = original_message.jump_url | ||||
|                     await message.add_reaction( | ||||
|                         emoji="<:quietscheentchen:1255956612804247635>" | ||||
|                     ) | ||||
|                     await message.reply(original_message_url) | ||||
|                 else: | ||||
|                     unique_memes.append(item.url) | ||||
|         if unique_memes: | ||||
|             await self.leaderboard_increment(message.author.id) | ||||
|             for meme_url in unique_memes: | ||||
|                 author_id: int = message.author.id | ||||
|                 timestamp: int = int(message.created_at.timestamp()) | ||||
|                 await self.insert_meme(author_id, timestamp, message.id, meme_url) | ||||
|  | ||||
|     async def get_top(self, n: int = 10) -> Optional[list[tuple]]: | ||||
|         """ | ||||
| @@ -686,9 +757,7 @@ class Meme(commands.Cog): | ||||
|             out_top: list[tuple[int, int]] = [] | ||||
|             async with sqlite3.connect(self.stats_db_path, timeout=2) as db_conn: | ||||
|                 db_conn.row_factory = sqlite3.Row | ||||
|                 query: str = ( | ||||
|                     "SELECT discord_uid, count FROM memes WHERE count > 0 ORDER BY count DESC" | ||||
|                 ) | ||||
|                 query: str = "SELECT discord_uid, count FROM memes WHERE count > 0 ORDER BY count DESC" | ||||
|                 async with db_conn.execute(query) as db_cursor: | ||||
|                     db_result = await db_cursor.fetchall() | ||||
|                     for res in db_result: | ||||
| @@ -734,9 +803,7 @@ class Meme(commands.Cog): | ||||
|             if not member: | ||||
|                 continue | ||||
|             display_name: str = member.display_name | ||||
|             top_formatted += ( | ||||
|                 f"{x+1}. **{discord.utils.escape_markdown(display_name)}**: *{count}*\n" | ||||
|             ) | ||||
|             top_formatted += f"{x + 1}. **{discord.utils.escape_markdown(display_name)}**: *{count}*\n" | ||||
|         top_formatted = top_formatted.strip() | ||||
|         embed: discord.Embed = discord.Embed( | ||||
|             title=f"Top {n} Memes", description=top_formatted, colour=0x25BD6B | ||||
|   | ||||
| @@ -215,9 +215,7 @@ class Misc(commands.Cog): | ||||
|                     logging.debug("Failed to add xmas reaction: %s", str(e)) | ||||
|                 await ctx.respond( | ||||
|                     f"Only {days} days, {hours} hours, {minutes} minutes,\ | ||||
|                     {seconds} seconds and {ms} ms left! (UTC)".translate( | ||||
|                         xmas_trans | ||||
|                     ) | ||||
|                     {seconds} seconds and {ms} ms left! (UTC)".translate(xmas_trans) | ||||
|                 ) | ||||
|         except Exception as e: | ||||
|             traceback.print_exc() | ||||
| @@ -1292,7 +1290,7 @@ class Misc(commands.Cog): | ||||
|         Satan(!?) | ||||
|         """ | ||||
|         out_msg: str = ( | ||||
|             "## There is no Satan\n" "### He isn't real.\n" "-# And neither are you." | ||||
|             "## There is no Satan\n### He isn't real.\n-# And neither are you." | ||||
|         ) | ||||
|         return await ctx.respond(out_msg) | ||||
|  | ||||
| @@ -1403,7 +1401,7 @@ class Misc(commands.Cog): | ||||
|         except Exception as e: | ||||
|             traceback.print_exc() | ||||
|             return await ctx.respond(f"Error: {str(e)}") | ||||
|          | ||||
|  | ||||
|     @bridge.bridge_command() | ||||
|     async def no(self, ctx) -> None: | ||||
|         """No (As A Service)""" | ||||
|   | ||||
							
								
								
									
										20
									
								
								cogs/sing.py
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								cogs/sing.py
									
									
									
									
									
								
							| @@ -94,9 +94,7 @@ class Sing(commands.Cog): | ||||
|                     search_result_src, | ||||
|                     search_result_confidence, | ||||
|                     search_result_time_taken, | ||||
|                 ) = search_result[ | ||||
|                     0 | ||||
|                 ]  #  First index is a tuple | ||||
|                 ) = search_result[0]  #  First index is a tuple | ||||
|                 search_result_wrapped: list[str] = search_result[ | ||||
|                     1 | ||||
|                 ]  # Second index is the wrapped lyrics | ||||
| @@ -124,9 +122,7 @@ class Sing(commands.Cog): | ||||
|                     # if ctx.guild.id == 1145182936002482196: | ||||
|                     #     section = section.upper() | ||||
|                     section = regex.sub(r"\p{Vert_Space}", " / ", section.strip()) | ||||
|                     msg: str = ( | ||||
|                         f"**{search_result_song}** by **{search_result_artist}**\n-# {section}\n{footer}" | ||||
|                     ) | ||||
|                     msg: str = f"**{search_result_song}** by **{search_result_artist}**\n-# {section}\n{footer}" | ||||
|                     if c > 1: | ||||
|                         msg = "\n".join(msg.split("\n")[1:]) | ||||
|                     out_messages.append(msg.strip()) | ||||
| @@ -159,9 +155,7 @@ class Sing(commands.Cog): | ||||
|                     f"No activity detected to read for {member_display}.", | ||||
|                     ephemeral=True, | ||||
|                 ) | ||||
|             member_id: int = ( | ||||
|                 member.id | ||||
|             )  # if not(member.id == PODY_ID) else 1234134345497837679 # Use Thomas for Pody! | ||||
|             member_id: int = member.id  # if not(member.id == PODY_ID) else 1234134345497837679 # Use Thomas for Pody! | ||||
|             activity: Optional[discord.Activity] = None | ||||
|             if IS_SPAMCHAN: | ||||
|                 await ctx.respond(f"***Reading activity of {member_display}...***") | ||||
| @@ -199,9 +193,7 @@ class Sing(commands.Cog): | ||||
|                     search_result_src, | ||||
|                     search_result_confidence, | ||||
|                     search_result_time_taken, | ||||
|                 ) = search_result[ | ||||
|                     0 | ||||
|                 ]  #  First index is a tuple | ||||
|                 ) = search_result[0]  #  First index is a tuple | ||||
|                 search_result_wrapped: list = search_result[ | ||||
|                     1 | ||||
|                 ]  # Second index is the wrapped lyrics | ||||
| @@ -230,9 +222,7 @@ class Sing(commands.Cog): | ||||
|                     # if ctx.guild.id == 1145182936002482196: | ||||
|                     #     section = section.upper() | ||||
|                     section = regex.sub(r"\p{Vert_Space}", " / ", section.strip()) | ||||
|                     msg: str = ( | ||||
|                         f"**{search_result_song}** by **{search_result_artist}**\n-# {section}\n{footer}" | ||||
|                     ) | ||||
|                     msg: str = f"**{search_result_song}** by **{search_result_artist}**\n-# {section}\n{footer}" | ||||
|                     if c > 1: | ||||
|                         msg = "\n".join(msg.split("\n")[1:]) | ||||
|                     out_messages.append(msg.strip()) | ||||
|   | ||||
| @@ -4,7 +4,7 @@ edge_tts==6.1.12 | ||||
| feedparser==6.0.11 | ||||
| Flask==3.0.3 | ||||
| nvdlib==0.7.7 | ||||
| openai==1.54.3 | ||||
| openai==1.54.3d | ||||
| requests_async==0.6.2 | ||||
| shazamio==0.7.0 | ||||
| streamrip==2.0.5 | ||||
|   | ||||
| @@ -52,9 +52,7 @@ class JesusMemeGenerator: | ||||
|             if len(top_line) < 1 or len(bottom_line) < 1: | ||||
|                 return None | ||||
|  | ||||
|             formed_url: str = ( | ||||
|                 f"{self.MEMEAPIURL}{meme}&top={top_line.strip()}&bottom={bottom_line.strip()}" | ||||
|             ) | ||||
|             formed_url: str = f"{self.MEMEAPIURL}{meme}&top={top_line.strip()}&bottom={bottom_line.strip()}" | ||||
|             formed_url = self.url_regex_1.sub( | ||||
|                 "+", self.url_regex_2.sub("%23", formed_url.strip()) | ||||
|             ) | ||||
|   | ||||
| @@ -257,7 +257,7 @@ class Util: | ||||
|         except Exception as e: | ||||
|             traceback.print_exc() | ||||
|             return (term, f"ERR: {str(e)}") | ||||
|          | ||||
|  | ||||
|     async def get_no(self) -> str: | ||||
|         try: | ||||
|             async with ClientSession() as session: | ||||
| @@ -266,19 +266,20 @@ class Util: | ||||
|                     headers={ | ||||
|                         "content-type": "application/json; charset=utf-8", | ||||
|                     }, | ||||
|                     timeout=ClientTimeout(connect=5, sock_read=5)                     | ||||
|                     timeout=ClientTimeout(connect=5, sock_read=5), | ||||
|                 ) as request: | ||||
|                     request.raise_for_status() | ||||
|                     response = await request.json() | ||||
|                     no: str = response.get('no', None) | ||||
|                     response = await request.json(encoding="utf-8") | ||||
|                     no: str = response.get("no", None) | ||||
|                     if not no: | ||||
|                         logging.debug("Incorrect response received, JSON keys: %s", | ||||
|                                       response.keys()) | ||||
|                         logging.debug( | ||||
|                             "Incorrect response received, JSON keys: %s", | ||||
|                             response.keys(), | ||||
|                         ) | ||||
|                         return "No." | ||||
|                     return no | ||||
|         except Exception as e: | ||||
|             logging.debug("Exception: %s", | ||||
|                           str(e)) | ||||
|             logging.debug("Exception: %s", str(e)) | ||||
|             return "No." | ||||
|  | ||||
|     async def get_insult(self, recipient: str) -> str: | ||||
| @@ -323,13 +324,11 @@ class Util: | ||||
|         if not whisky_db: | ||||
|             return None | ||||
|         async with sqlite3.connect(database=whisky_db, timeout=2) as db_conn: | ||||
|             db_query: str = ( | ||||
|                 "SELECT name, category, description FROM whiskeys ORDER BY random() LIMIT 1" | ||||
|             ) | ||||
|             db_query: str = "SELECT name, category, description FROM whiskeys ORDER BY random() LIMIT 1" | ||||
|             async with await db_conn.execute(db_query) as db_cursor: | ||||
|                 db_result: Optional[Union[sqlite3.Row, tuple]] = ( | ||||
|                     await db_cursor.fetchone() | ||||
|                 ) | ||||
|                 db_result: Optional[ | ||||
|                     Union[sqlite3.Row, tuple] | ||||
|                 ] = await db_cursor.fetchone() | ||||
|                 if not db_result: | ||||
|                     return None | ||||
|                 (name, category, description) = db_result | ||||
| @@ -398,9 +397,7 @@ class Util: | ||||
|         async with sqlite3.connect(database=strains_db, timeout=2) as db_conn: | ||||
|             db_params: Optional[tuple] = None | ||||
|             if not strain: | ||||
|                 db_query: str = ( | ||||
|                     "SELECT name, description FROM strains_w_desc ORDER BY random() LIMIT 1" | ||||
|                 ) | ||||
|                 db_query: str = "SELECT name, description FROM strains_w_desc ORDER BY random() LIMIT 1" | ||||
|             else: | ||||
|                 db_query = ( | ||||
|                     "SELECT name, description FROM strains_w_desc WHERE name LIKE ?" | ||||
| @@ -442,9 +439,7 @@ class Util: | ||||
|         if not rjokes_db: | ||||
|             return None | ||||
|         async with sqlite3.connect(database=rjokes_db, timeout=2) as db_conn: | ||||
|             db_query: str = ( | ||||
|                 "SELECT title, body, score FROM jokes WHERE score >= 100 ORDER BY RANDOM() LIMIT 1'" | ||||
|             ) | ||||
|             db_query: str = "SELECT title, body, score FROM jokes WHERE score >= 100 ORDER BY RANDOM() LIMIT 1'" | ||||
|             async with await db_conn.execute(db_query) as cursor: | ||||
|                 (title, body, score) = await cursor.fetchone() | ||||
|                 return (title, body, score) | ||||
|   | ||||
| @@ -82,7 +82,9 @@ class Utility: | ||||
|             if ( | ||||
|                 search_split_by == ":" and len(song.split(":")) > 2 | ||||
|             ):  # Support sub-search if : is used (per instructions) | ||||
|                 search_song = song.split(search_split_by)[ | ||||
|                 search_song = song.split( | ||||
|                     search_split_by | ||||
|                 )[ | ||||
|                     1 | ||||
|                 ].strip()  # Reduce search_song to only the 2nd split of : [the rest is meant to be lyric text] | ||||
|                 search_subsearch = "".join( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user