commit 15b4b787b6d7dfaecb2335fb117274d9fc9ba1f1 Author: savagebidoof Date: Mon Jul 3 08:44:24 2023 +0200 push functional python code 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 0000000..cbd8ddc Binary files /dev/null and b/bot/__pycache__/Classes.cpython-311.pyc differ diff --git a/bot/__pycache__/DiscordBot.cpython-311.pyc b/bot/__pycache__/DiscordBot.cpython-311.pyc new file mode 100644 index 0000000..781ec44 Binary files /dev/null and b/bot/__pycache__/DiscordBot.cpython-311.pyc differ diff --git a/bot/__pycache__/TwitterFixer.cpython-311.pyc b/bot/__pycache__/TwitterFixer.cpython-311.pyc new file mode 100644 index 0000000..39d8ea6 Binary files /dev/null and b/bot/__pycache__/TwitterFixer.cpython-311.pyc differ diff --git a/bot/main.py b/bot/main.py new file mode 100644 index 0000000..1bb2936 --- /dev/null +++ b/bot/main.py @@ -0,0 +1,9 @@ +#!/bin/python3 + +from DiscordBot import Bot, DiscordConf + + +if __name__ == '__main__': + disconf = DiscordConf() + client = Bot(conf=disconf) + client.run()