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