From 9c14774edc04e028401e66c5b26a31288ef5f922 Mon Sep 17 00:00:00 2001 From: Tyler Perkins Date: Fri, 28 Oct 2022 14:21:47 -0400 Subject: [PATCH] Update file strcuture --- .gitignore | 6 +- make_venv.sh | 13 ++++ src/.env | 8 ++ src/main.py | 46 ++++++++++++ src/memes.py | 156 +++++++++++++++++++++++++++++++++++++++ src/on_message.py | 32 ++++++++ src/on_message_delete.py | 8 ++ src/plex.py | 0 src/requirements.txt | 22 ++++++ 9 files changed, 287 insertions(+), 4 deletions(-) create mode 100755 make_venv.sh create mode 100644 src/.env create mode 100755 src/main.py create mode 100644 src/memes.py create mode 100644 src/on_message.py create mode 100644 src/on_message_delete.py create mode 100644 src/plex.py create mode 100644 src/requirements.txt diff --git a/.gitignore b/.gitignore index e511126..577d148 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ *.swp -src/lib -!src/lib/.gitkeep src/.env -src/bin -!src/bin/active* +venv + diff --git a/make_venv.sh b/make_venv.sh new file mode 100755 index 0000000..c01a955 --- /dev/null +++ b/make_venv.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +mkdir ./venv 2> /dev/null + +python -m venv ./venv + +cp ./src/* ./venv/ +cp ./src/.env ./venv/.env 2> /dev/null + +cd ./venv +touch .env + +env $(cat .env | xargs) python ./main.py diff --git a/src/.env b/src/.env new file mode 100644 index 0000000..11e554d --- /dev/null +++ b/src/.env @@ -0,0 +1,8 @@ +DISCORD_TOKEN= +S3_URL= +S3_UN= +S3_PW= +S3_TLS=False +S3_BUCKET=memes +TAUTULLI_URL= +TAUTULLI_APIKEY= diff --git a/src/main.py b/src/main.py new file mode 100755 index 0000000..1e77eaf --- /dev/null +++ b/src/main.py @@ -0,0 +1,46 @@ +#!/usr/bin/python3 +import discord +import requests +import os, random, sys +from fuzzywuzzy import fuzz, process +from minio import Minio +from minio.error import S3Error + +from on_message_delete import message_delete +from on_message import parse_message + +#globals for discord +if 'DISCORD_TOKEN' not in os.environ: + raise Exception("DISCORD_TOKEN was not set!") +token = os.environ['DISCORD_TOKEN'] +client = discord.Client() + +############################################################################### +# Discord client code + + +# primary message handler +@client.event +async def on_message(message): + if message.author == client.user: + return + return await parse_message(client, message) + +# messege delete handler +@client.event +async def on_message_delete(message): + if message.author == client.user: + return + return await message_delete(client, message) + +@client.event +async def on_ready(): + print(f'{client.user} has connected to Discord!') + +def main() -> int: + print('Connecting client to discord...') + client.run(token) + dclient = client + +if __name__ == '__main__': + sys.exit(main()) diff --git a/src/memes.py b/src/memes.py new file mode 100644 index 0000000..8e710ea --- /dev/null +++ b/src/memes.py @@ -0,0 +1,156 @@ +import discord +import os, random, io +from datetime import datetime +from fuzzywuzzy import fuzz, process +from minio import Minio +from minio.error import S3Error +from catbox import Uploader + +# memes we have most recently gotten +last_memes = [] +last_memes_max = 20 + +# list of all current memes' names +all_memes = [] +last_checked_all_memes = datetime.strptime("2000-01-01 01:01:01", "%Y-%m-%d %H:%M:%S") + +S3_URL = "" +S3_UN = "" +S3_PW = "" +S3_TLS = True +S3_BUCKET = "" + +client = "" + +#returns the S3 client +def getClient(): + global client + global S3_URL + global S3_UN + global S3_PW + global S3_TLS + global S3_BUCKET + if client != "": + return client + + if "S3_URL" not in os.environ: + raise Exception("S3_URL is not set!") + S3_URL = os.environ["S3_URL"] + if "S3_UN" not in os.environ: + raise Exception("S3_UN is not set!") + S3_UN = os.environ["S3_UN"] + if "S3_PW" not in os.environ: + raise Exception("S3_PW is not set!") + S3_PW = os.environ["S3_PW"] + if "S3_BUCKET" not in os.environ: + raise Exception("S3_BUCKET is not set!") + S3_BUCKET = os.environ["S3_BUCKET"] + + # override defaults + if "S3_TLS" in os.environ: + S3_TLS = os.environ["S3_TLS"].lower() in ("yes", "true", "1", "t") + + if client == "": + client = Minio(S3_URL, + access_key=S3_UN, + secret_key=S3_PW, + secure=S3_TLS) + found = client.bucket_exists(S3_BUCKET) + if not found: + client.make_bucket(S3_BUCKET) + else: + print(f"Found bucket {S3_BUCKET}") + + return client + +############################################################################### +# Helper methods +# Methods to break up the calldict methods + +def getCurrentMemeList(): + global last_checked_all_memes + global all_memes + now = datetime.now() + # if no update in the past 5 mins + if (last_checked_all_memes - now).seconds / 60 > 5: + last_checked_all_memes = now + all_memes.clear() + myClient = getClient() + for obj in myClient.list_objects(S3_BUCKET): + if not obj.is_dir: + print(f'{obj.object_name}') + all_memes.append(obj.object_name) + return all_memes + +# given a file, we will return: +# A discord.File if its smaller than 8MB +# A catbox.moe link if its larger than 8mb +def getDiscordReadyObjectFromS3(file_name): + size = 0 + out_file_path = "/tmp/" + file_name + #get the file + client = getClient() + stream = "" + try: + obj = client.get_object(bucket_name=S3_BUCKET, + object_name=file_name) + stream = obj.read() + size = len(stream) + except: + return "No such file " + file_name + " !" + + # check the object size + if size >= 8000000: # to big, use catbox + catbox_uploader = Uploader(token='') + url = catbox_uploader.upload(file_raw=stream) + return url["file"] + else: #small enough, use discord + return discord.File(fp=io.BytesIO(stream), filename=file_name) + +# get the name of the user who uploaded the file +# their tag is always under the 'uploader' tag +def getMemeUploader(file_name): + client = getClient() + tags = client.get_object_tags(S3_BUCKET, file_name) + if tags != None: + uploader = tags.get("uploader") + if uploader != None: + return uploader + return "Unkown" + +############################################################################### +# Calldict methods + +# parse for a meme that is simliar to a given query +# There are two possibilities for parseMeme, as there is a somewhat +# complex syntax +# !meme [QUERY_STRING] +# With QUERY_STRING being optional +# due to this, we need to cover both cases +# NOTE QUERY_STRING can also be an exact filename, in which case we should +# return that instead +async def parseMeme(command, message, client): + if len(command) > 1: # if there is a query + query_string = ' '.join(command[1:]) #get QUERY_STRING + + all_memes = getCurrentMemeList() + #first, check if the exact meme exists + if query_string in all_memes: # found the exact meme, return it + return getDiscordReadyObjectFromS3(query_string) + + #if we get here then we didnt find the meme, lets find the closest meme + + else: #there is no query, get a random meme + pass + +# get all ememes that are similar to the given query +async def allMemes(command, message, client): + pass + +# get total number of memes stored +async def memeCount(command, message, client): + pass + +# get a set of random memes +async def memeDump(command, message, client): + pass diff --git a/src/on_message.py b/src/on_message.py new file mode 100644 index 0000000..c322560 --- /dev/null +++ b/src/on_message.py @@ -0,0 +1,32 @@ +#!/usr/bin/python3 +import requests +import os, random, sys +from memes import parseMeme, memeCount, memeDump, allMemes +import discord + +# dictionary associating +# a command to a function name +calldict = { + # S3 memes + "!meme" : parseMeme, + "!memecount" : memeCount, + "!memedump" : memeDump, + "!allmemes" : allMemes, + # plex + #"!plexleaderboard" : getTopUsers, +} + +# parse the message +async def parse_message(client, message): + command = message.content.split() + + # if i know this command + if command[0] in calldict.keys(): + print(f'{client.user} was passed a command I know! ({message.content})') + result = await calldict[command[0]](command, message, client) + if isinstance(result, discord.File): + return await message.channel.send(file=result) + else: + return await message.channel.send(result) + + pass diff --git a/src/on_message_delete.py b/src/on_message_delete.py new file mode 100644 index 0000000..20477d4 --- /dev/null +++ b/src/on_message_delete.py @@ -0,0 +1,8 @@ +#!/usr/bin/python3 + +async def message_delete(client, message): + response = "Cringe!" + + await message.channel.send(response) + + print(f'{client.user} replied to someone who deleted my message with {response}') diff --git a/src/plex.py b/src/plex.py new file mode 100644 index 0000000..e69de29 diff --git a/src/requirements.txt b/src/requirements.txt new file mode 100644 index 0000000..b3ccc3f --- /dev/null +++ b/src/requirements.txt @@ -0,0 +1,22 @@ +aiohttp==3.7.4.post0 +aiosignal==1.2.0 +async-timeout==3.0.1 +attrs==22.1.0 +certifi==2022.9.24 +chardet==4.0.0 +charset-normalizer==2.1.1 +discord==1.7.3 +discord.py==1.7.3 +frozenlist==1.3.1 +fuzzywuzzy==0.18.0 +idna==3.4 +Levenshtein==0.20.7 +minio==7.1.12 +multidict==6.0.2 +pycatbox==1.0.3 +python-Levenshtein==0.20.7 +rapidfuzz==2.12.0 +requests==2.28.1 +typing_extensions==4.4.0 +urllib3==1.26.12 +yarl==1.8.1