From 15b4b787b6d7dfaecb2335fb117274d9fc9ba1f1 Mon Sep 17 00:00:00 2001 From: savagebidoof Date: Mon, 3 Jul 2023 08:44:24 +0200 Subject: [PATCH] push functional python code --- REAMDE.md | 3 + bot/Classes.py | 46 ++++++++++ bot/DiscordBot.py | 77 +++++++++++++++++ bot/TwitterFixer.py | 85 +++++++++++++++++++ bot/__pycache__/Classes.cpython-311.pyc | Bin 0 -> 2485 bytes bot/__pycache__/DiscordBot.cpython-311.pyc | Bin 0 -> 5424 bytes bot/__pycache__/TwitterFixer.cpython-311.pyc | Bin 0 -> 3768 bytes bot/main.py | 9 ++ 8 files changed, 220 insertions(+) create mode 100644 REAMDE.md create mode 100644 bot/Classes.py create mode 100644 bot/DiscordBot.py create mode 100644 bot/TwitterFixer.py create mode 100644 bot/__pycache__/Classes.cpython-311.pyc create mode 100644 bot/__pycache__/DiscordBot.cpython-311.pyc create mode 100644 bot/__pycache__/TwitterFixer.cpython-311.pyc create mode 100644 bot/main.py diff --git a/REAMDE.md b/REAMDE.md new file mode 100644 index 0000000..8cf12e9 --- /dev/null +++ b/REAMDE.md @@ -0,0 +1,3 @@ +# Disclaimer. + +I have no relation with `fxtwitter`, nor `vxtwitter`, or anything else being used there. \ No newline at end of file diff --git a/bot/Classes.py b/bot/Classes.py new file mode 100644 index 0000000..fa524fa --- /dev/null +++ b/bot/Classes.py @@ -0,0 +1,46 @@ +from dataclasses import dataclass, asdict +from datetime import datetime, timedelta +from os import getenv + + +@dataclass +class _CONFIG: + """ + Skell for other Services Configurations + """ + + def __hash__(self) -> dict: + return asdict(self) + + def load_envs(self) -> object: + """ + Loads variables from environment. + :return: + """ + raise NotImplementedError + + def __post_init__(self): + self = self.load_envs() + + +@dataclass +class DiscordConf(_CONFIG): + """ + Stores the configuration for the Discord Bot + + token: str + mc_url: str : Url to post on the discord embeds / messages + prefix: str : Prefix for the commands + description: str : Bot description to have + """ + token: str = None + # mc_url: str = None + prefix: str = "!" + description: str = "Don't u dare make me fix ur twitter links." + + def load_envs(self): + self.token = getenv("DISCORD_TOKEN") or self.token + # self.mc_url = getenv("DISCORD_MC_URL") or self.mc_url + self.prefix = getenv("DISCORD_PREFIX") or self.prefix + self.description = getenv("DISCORD_DESCRIPTION") or self.description + return self diff --git a/bot/DiscordBot.py b/bot/DiscordBot.py new file mode 100644 index 0000000..5e810f2 --- /dev/null +++ b/bot/DiscordBot.py @@ -0,0 +1,77 @@ +import discord.ext.commands +from discord.ext import commands +from discord import Embed, Intents +from Classes import DiscordConf +from TwitterFixer import TwLink +from validators import url as is_url + + +# Set some validator of vx, fx pages to flag as working or not working. + +class Bot(commands.Bot): + conf: DiscordConf = None + + def __init__(self, conf: DiscordConf = None, *args, **kwargs): + intents = Intents(messages=True, guilds=True, message_content=True) + super(commands.Bot, self).__init__(command_prefix=conf.prefix, description=conf.description, intents=intents, + self_bot=False) + self.config = conf + self.add_commands() + + def run(self, *args, **kwargs): + super(commands.Bot, self).run(self.config.token, *args, **kwargs) + + async def on_ready(self): + print('------') + print('Logged as') + print(self.user.name) + print(self.user.id) + print( + f'invite me with: {self.invite_url}') + print('------') + + @property + def invite_url(self) -> str: + return f"https://discord.com/oauth2/authorize?client_id={self.user.id}&permissions=84032&scope=bot" + + def scan_message(self, ctx: discord.Message): + """ + Scans the message for twitter links that aren't fxtweeted. + """ + + def is_command(self, ctx: discord.Message) -> bool: + __is_command: bool = ctx.content.startswith(self.command_prefix) + print(f'>> `{ctx.author.name}` message is a command? {__is_command}') + return __is_command + + async def on_message(self, ctx: discord.Message, /): + + __is_bot = ctx.author.bot + + print(f'>> `{ctx.author.name}` posted a new message, is it a bot? {__is_bot}') + if __is_bot: + print(f"*** ``{ctx.author.name}`` is a bot, skipping ...") + elif self.is_command(ctx): + await self.process_commands(ctx) + else: + + """ + Splits message by spaces. + + Iterates and validates each one of the words split + + If the "word" is flagged as valid URL, it will proceed with the URL fixing process, which in case of being a valid URL, will post a message. + """ + text_split = ctx.content.split(" ") + for word in text_split: + if is_url(word): + url = word + tw = TwLink(url=url) + if tw.__bool__(): + print(f"fixed URL from `{url}` to `{tw}`") + await ctx.reply(mention_author=False, content=f"Fixed Twitter Link! {tw}") + + def add_commands(self): + @self.command() + async def invite(ctx): + await ctx.reply(f"You can invite me to your server with: {self.invite_url}") diff --git a/bot/TwitterFixer.py b/bot/TwitterFixer.py new file mode 100644 index 0000000..aa720b8 --- /dev/null +++ b/bot/TwitterFixer.py @@ -0,0 +1,85 @@ +from urllib.parse import urlparse + + +class TwLink: + """ + Disclaimer. + + I have no relation with fxtwitter, nor vxtwitter, or anything else being used there. + """ + _user: str + _post_id: str + _url: str + _prefix: [str] # List of valid fxshit + _valid_url = False + + def __init__(self, url: str): + self._url = url + self.__review_url() + self._prefix = [ + "https://fxtwitter.com", + "https://vxtwitter.com" + ] + + pass + + def __review_url(self) -> None: + """ + Checks if twitter URL is a valid post. + + It requires: + - Twitter domain. + - /status/ + - Username + - Post ID + + :return: STR, returns "fixed" URL if given URL is valid. + Returns nothing if isn't valid. + """ + + valid_twitter_hosts = ["twitter.com"] + parsed_url = urlparse(url=self._url) + host = parsed_url.netloc + path: str | [str] = parsed_url.path + if path.startswith("/"): + # Remove initial / + path = path[1:] + path = path.split("/") + + if host not in valid_twitter_hosts \ + or len(path) > 3 \ + or path[1].lower() != "status": + print(f"URL '{self._url}' is NOT valid!") + else: + print(f"URL '{self._url}' is valid") + self._valid_url = True + self._user = path[0] + self._post_id = path[2] + + @property + def __return_url(self) -> str: + """ + Returns the URL if the class been flagged as valid URL. + + Retrusn an empty string if it's not flagged as valid URL. + :return: + """ + + if self._valid_url: + return f"{self._prefix[0]}/{self._user}/status/{self._post_id}" + else: + return "" + + def __str__(self) -> str: + return self.__return_url + + def __bool__(self) -> bool: + if self.__return_url is not None: + return True + + def __call__(self, *args, **kwargs) -> str: + return self.__str__() + + def __int__(self): + return len(self.__str__()) + diff --git a/bot/__pycache__/Classes.cpython-311.pyc b/bot/__pycache__/Classes.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cbd8ddce343afbc81f178b46b675b59f076444da GIT binary patch literal 2485 zcmZuy&2JM&6rWx1t{sPvKyZKt#E_y=x72P`sYNO6p?0Vus1sq3DqmI`&x9=5k91}o z+9*X<6;)}4RBqwOp-PLmaNtm>|AZsu5UoU2sp_FOqtFYdzBd~iJIQ$Wx9`1qGw;25 z^PYbl8p;wFKRkNGelZC78=20q_K4keAT|giO!J7Z)ihtP=^FC7m-17!lyB4w#iu;e zw`!I~xTcdY2s73QGdFcYp1_-oP53o8C#BIZao5F2829veI5@WGVVoAUW={UJmSG}eQ#s+>A1A}KCl~vlbXgz zO=nsy#dL1W>nycq)J&i)pbenY%v>Y2470$Ebey(JGnK2;U#xtPr7)_C-1F#sC}8nqQ3!%@8(ph$H^EsD=;e2tLac5S9cX&OL#d-Ie=q~4xGw1Q* zTo@Hgc!XRQmcETMw!PrU1>0U3*$b}FksN{DG{e6QuTm9jbkJhAJc!z5jHgp0mNIxj+>LY7<+20jm>LRWJ#Ij+gB08%XTX*_05W5JO-oIS4TfWIW)34IB29E5|w!bw#Kl@%lH(e_1j-(aM|`$AIk% z2XBcArvStTStXC)dvNq$)$gD!Ah9} zXp)`b(Vy@AbZ=|;-1hLfbpwCO*-Cx@(-t^Bx9vD<+kVIz9@0l_`|F0|?aicZn}u}{ z8(1j3s>G)9^p$o#wh}8V@07#fVniF1If7H)Sp?t| z?9+yz(Oox+po@8KuqX@hV9&;V<$;O8clS4ynBJzvwEm{GWUZ1r-4?b=>@MB6NBjWz&FPs+-VkYsQc#2mgf|iP^&C}AE4iM_Rp@q{Jm||W0icQI#vjgXn{apRqHov+r$<6}HC;t+7v^UU>E{hzFmKpKnckyfuD#d;D^1{QB?Z?JL*U zjqS`S=nCtDs%G+8aT2{bg>V|-4Fn1hr{H?V!?x`NK^P@}L$=)$fof1^Q61Y~QvK(U zLcndL1Ms@~o1|@|vHlT8$nmk})cS`lBL~lxk^Ad-u6cF6)a7?hmYUZdjJ6CAm9~sh z+c3=&*bnwYVjXQ_Qyc95y>lrred^y%m`GtqiuF(?`B05Y`P(1EtIU<88Ga@%!2-N) z@(+M^O4GC*l5ZXM?2xxxhdnza*Xn=T7SRXW`iKTS>>#{A*-L~MDbQOxooK$L){JTp U`$2ec@dZj>B6L^vsi`CS9~M|Z3jhEB literal 0 HcmV?d00001 diff --git a/bot/__pycache__/DiscordBot.cpython-311.pyc b/bot/__pycache__/DiscordBot.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..781ec44594c037c8e565716ef01388e994d1f8c6 GIT binary patch literal 5424 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