diff --git a/README.md b/README.md index 8a31cf2d..0c124de1 100755 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Currently the CI/CD pipeline has workers running as Kubernetes pods and dispatch * You can see a diagram of how it all works by running the following command from the root of the repo: ```bash -docker run --rm -v $(pwd):/tmp/python python sh -c "apt-get update && apt-get install -y graphviz; pip install diagrams --user; cd /tmp/python; python dalebot-overview.py" +docker run --rm -v $(pwd):/tmp/python python sh -c "apt-get update && apt-get install -y graphviz; pip install diagrams; cd /tmp/python; python /tmp/python/dalebot-overview.py" ``` ### What is this repository for? ### diff --git a/app/bot.py b/app/bot.py index 2170176f..dc51e7b5 100755 --- a/app/bot.py +++ b/app/bot.py @@ -1,8 +1,8 @@ #!/usr/local/bin/python from discord.ext import commands -import core_utils import discord import os +import requests_cache intents = discord.Intents.default() intents.message_content = True @@ -19,7 +19,6 @@ cogfiles = [ for cogfile in cogfiles: bot.load_extension(cogfile) -import requests_cache requests_cache.install_cache(expire_after=300) @@ -112,7 +111,7 @@ async def convert_heic_to_jpg(ctx): jpg_file = "/tmp/%s.jpg" % time.time() await attachment.save(fp=file_path) - img = cmagick.convert(file_path, jpg_file) + cmagick.convert(file_path, jpg_file) try: await ctx.delete() @@ -133,8 +132,8 @@ async def fix_social_media_links(ctx): "https://www.x.com": "vxtwitter", "https://twitter.com": "vxtwitter", "https://www.twitter.com": "vxtwitter", - # "https://tiktok.com": "vxtiktok", - # "https://www.tiktok.com": "vxtiktok", + "https://tiktok.com": "vxtiktok", + "https://www.tiktok.com": "vxtiktok", } if ctx.author.id == bot.user.id: return diff --git a/app/cogs/actual_utils.py b/app/cogs/actual_utils.py index 5573767c..11b16317 100755 --- a/app/cogs/actual_utils.py +++ b/app/cogs/actual_utils.py @@ -2,7 +2,6 @@ from discord.ext import commands from discord import option import discord import os -import core_utils class ActualUtils(commands.Cog): @@ -54,26 +53,6 @@ class ActualUtils(commands.Cog): await ctx.defer() await ctx.followup.send(result) - @commands.slash_command( - guild_ids=core_utils.my_guilds, - name="issue", - description="Files an issue on gitlab", - ) - @option(name="title", requried=True, description="The title of the issue") - @option(name="description", require=True, description="The body of the issue") - async def issue(self, ctx: commands.Context): - post_args = {"title": title, "description": description} - - headers = {"PRIVATE-TOKEN": os.getenv("gitlab_token")} - - r = requests.post( - "https://git.luker.fr/api/v4/projects/3/issues", - data=post_args, - headers=headers, - ) - - await ctx.respond(r.json()["web_url"]) - @commands.slash_command( guild_ids=None, name="define", diff --git a/app/cogs/anime_girls.py b/app/cogs/anime_girls.py index fea0ea72..ace60427 100755 --- a/app/cogs/anime_girls.py +++ b/app/cogs/anime_girls.py @@ -7,26 +7,6 @@ class AnimeGirls(commands.Cog): def __init__(self, bot): self.bot: commands.Bot = bot - # @commands.slash_command(guild_ids=None, name="wink", description="Posts a gif of an anime girl winking") - # async def wink(self, ctx: commands.Context): - # await ctx.respond( - # embed=core_utils.generate_embed( - # embed_url=requests.get("https://some-random-api.ml/animu/wink").json()[ - # "link" - # ] - # ) - # ) - - @commands.slash_command( - guild_ids=None, name="pout", description="Posts a gif of an anime girl pouting" - ) - async def pout(self, ctx: commands.Context): - await ctx.respond( - embed=core_utils.generate_embed( - embed_url=core_utils.waifu_pics(endpoint="blush") - ) - ) - @commands.slash_command( guild_ids=None, name="yeet", description="Posts a gif of an anime girl yeeting" ) diff --git a/app/cogs/game_apis.py b/app/cogs/game_apis.py index d1dcaa6c..02f8ec48 100755 --- a/app/cogs/game_apis.py +++ b/app/cogs/game_apis.py @@ -30,9 +30,6 @@ class Games(commands.Cog): response = requests.get(url) soup = BeautifulSoup(response.text, "html.parser") - # Find all elements with class "world-list__world_name" - world_name_elements = soup.find_all(class_="world-list__world_name") - # Loop through each element and extract its contents worlds = [ element.get_text(strip=True) diff --git a/app/cogs/gpt.py b/app/cogs/gpt.py deleted file mode 100755 index e957c88c..00000000 --- a/app/cogs/gpt.py +++ /dev/null @@ -1,51 +0,0 @@ -import openai -import os -from discord import option -from discord.ext import commands -import discord -import requests - - -class Gpt(commands.Cog): - def __init__(self, bot): - self.bot: commands.Bot = bot - - @commands.slash_command( - guld_ids=None, - name="gpt", - description="Talk to an LLM", - ) - @option(name="question", description="The question to ask", required=True) - async def gpt( - self, - ctx, - question: str, - ): - openai.api_key = os.getenv("OPENAI_API_KEY") - - completion = openai.ChatCompletion.create( - model="gpt-3.5-turbo", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "Hello!"}, - ], - ) - - embed = discord.Embed( - description=completion.choices[0].message, - color=discord.Color.green(), - type="rich", - ) - - embed.set_ - - embed.set_author( - name="You asked me: %s" % question, - icon_url="https://upload.wikimedia.org/wikipedia/commons/thumb/0/04/ChatGPT_logo.svg/2048px-ChatGPT_logo.svg.png", - ) - - await ctx.followup.send(embed=embed) - - -def setup(bot): - bot.add_cog(Gpt(bot)) diff --git a/app/cogs/markov.py b/app/cogs/markov.py index 25a4059c..282c834c 100755 --- a/app/cogs/markov.py +++ b/app/cogs/markov.py @@ -27,7 +27,7 @@ class Markov(commands.Cog): # Make the model user_model = markovify.Text(". ".join(authors_mesages)) - model_json = user_model.to_json() + user_model.to_json() dummy = [] for i in range(random.randint(3, 9)): diff --git a/app/cogs/palworld.py b/app/cogs/palworld.py deleted file mode 100755 index af53c225..00000000 --- a/app/cogs/palworld.py +++ /dev/null @@ -1,197 +0,0 @@ -from discord import option -from discord.ext import commands, tasks -import discord -import requests -from bs4 import BeautifulSoup -import re -import os - - -class PalWorld(commands.Cog): - def __init__(self, bot): - self.bot: commands.Bot = bot - # self.poll_server_population.start() - - palworld = discord.SlashCommandGroup("palworld", "Palworld related commands") - - async def get_all_pals(ctx: discord.AutocompleteContext): - """ - returns a list of all pals in the game, which can then be passed to the /ship command for auto complete - """ - import requests - from bs4 import BeautifulSoup - - all_pals = [] - - url = "https://paldex.io/palworld/pals/" - response = requests.get(url) - - soup = BeautifulSoup(response.text, "html.parser") - - x = soup.find_all( - "p", - class_="text-base lg:text-lg group-hover:underline underline-offset-4 text-center", - ) - for pal in x: - all_pals.append(pal.text) - - return sorted(set(all_pals)) - - @palworld.command( - guild_ids=None, - name="paldeck", - description="Looks up data about a pal", - ) - async def pal_lookup( - self, - ctx: commands.Context, - pal: discord.Option( - str, - autocomplete=discord.utils.basic_autocomplete(get_all_pals), - description="Pal to look up", - ), - ): - pal_url = "https://paldex.io/palworld/pals/%s/" % pal.lower().replace(" ", "-") - response = requests.get(pal_url) - soup = BeautifulSoup(response.text, "html.parser") - - elements = {} - - pal_elements = soup.find("div", class_="flex flex-row flex-wrap gap-3") - for div in pal_elements: - pal_element_badge = div.find("img", class_="rounded-full w-12 px-2 py-2") - element_type = pal_element_badge.find_next("p").text - element_icon = "https://paldex.io" + pal_element_badge["src"] - elements[element_type] = element_icon - - primary_element = list(elements.keys())[0] - - # https://discordpy.readthedocs.io/en/latest/api.html?highlight=colour#discord.Colour - color_lookup = { - "Dark": discord.Color.dark_purple(), - "Dragon": discord.Color.purple(), - "Earth": discord.Color.greyple(), - "Electricity": discord.Color.yellow(), - "Fire": discord.Color.red(), - "Leaf": discord.Color.green(), - "Ice": discord.Color.blue(), - "Normal": discord.Color.lighter_grey(), - "Water": discord.Color.dark_blue(), - } - - embed = discord.Embed( - description="-------", - color=color_lookup[primary_element], - type="rich", - title=pal.capitalize(), - ) - - embed.set_author( - name=", ".join(elements.keys()), - icon_url=elements[primary_element], - url=pal_url, - ) - - embed.set_thumbnail( - url=soup.find( - "img", - class_="rounded-full w-32 sm:w-auto border-2 border-amber-500 aspect-square", - )["src"] - ) - - # embed.add_field(name="Work Skills", value="-----", inline=False) - # work skills - skills_emojis = { - "Cooling": "❄️", - "Farming": "🚜", - "Gathering": "🍃", - "Generating Electricity": "⚡️", - "Handwork": "🤚", - "Kindling": "🔥", - "Lumbering": "🪵", - "Medicine Production": "💉", - "Mining": "⛏️", - "Planting": "🌱", - "Transporting": "📦", - "Watering": "💦", - } - - skill_table = soup.find("div", class_="flex flex-col gap-2") - for div in skill_table.find_all( - "div", class_=re.compile(".*border-amber-300\s+break-all") - ): - skill_name = div.find("p", class_="text-base sm:text-lg").text - skill_level = div.find( - "p", class_="text-base sm:text-lg mr-2 md:mr-4" - ).text.split("Lv")[-1] - - embed.add_field( - name=skills_emojis[skill_name] + " " + skill_name, - value="%s" % (int(skill_level) * "⭐️"), - inline=True, - ) - - # Partner Skill - embed.add_field(name="Partner Skill", value="-----", inline=False) - skill_name = soup.find("h2", string="Partner Skill").find_next( - "p", class_=re.compile(".*text-xl.*") - ) - skill_description = skill_name.find_next("p", class_="text-lg mr-4").text - embed.add_field( - name=skill_name.text, - value=skill_description, - inline=False, - ) - - # Drops - embed.add_field(name="Drops", value="-----", inline=False) - for div in soup.find_all( - "div", - class_="inline-flex flex-col gap-1 items-center bg-black-300 border border-amber-300 break-all p-2", - ): - item = div.text - item_name = item.split("Quantity")[0].split("Drop Chance") - amount = item.split("Quantity")[-1].split("Drop Chance") - embed.add_field( - name=" ".join(item_name), - value="", - inline=False, - ) - - await ctx.defer() - await ctx.send_followup(embed=embed) - - @palworld.command( - guild_ids=None, - name="elements", - description="Posts an infographic about which Pal elements are weak/strong against which", - ) - async def post_medpen_guide(self, ctx: commands.Context): - await ctx.respond( - "https://img.game8.co/3822502/5ae8382d16bd390dd19f343e87680d51.png/show" - ) - - # @tasks.loop(seconds=60) - # async def poll_server_population(self): - # # Wait until the bot is ready before we actually start executing code - # await self.bot.wait_until_ready() - - # from source_rcon import SourceRcon - # from loguru import logger - - # logger.disable("source_rcon") - - # rcon = SourceRcon("192.168.1.200", 25575, os.getenv("pal_rcon_pass")) - # num_players = len(rcon.send_command("ShowPlayers").split("\n")[1:-1]) - - # # channel = self.bot.get_channel(1201389692759842816) # test server - # channel = self.bot.get_channel(1199397770746925239) - - # if str(num_players) in channel.name.split("/")[0]: - # return - - # await channel.edit(name="Palworlders (%s/16 online)" % num_players) - - -def setup(bot): - bot.add_cog(PalWorld(bot)) diff --git a/app/cogs/server_utils.py b/app/cogs/server_utils.py index c7a40a29..67bed8a0 100755 --- a/app/cogs/server_utils.py +++ b/app/cogs/server_utils.py @@ -21,7 +21,7 @@ class ServerUtils(commands.Cog): type=bool, default=False, ) - async def invite(self, ctx: commands.Context, temp): + async def invite(self, ctx: commands.Context, temp: bool): # Default to creating the invite to the channel the message was sent in # if the user is in a voice channel, create the invite there invite_channel = ctx.channel @@ -32,13 +32,13 @@ class ServerUtils(commands.Cog): except AttributeError: pass - if temporary_invite: + if temp: await ctx.author.send("Here is your temporary invite") invite = await invite_channel.create_invite( max_uses=1, max_age=3600, - temporary=temporary_invite, + temporary=temp, ) await ctx.respond("Check your DMs") await ctx.author.send(invite) @@ -98,7 +98,7 @@ class ServerUtils(commands.Cog): for role in ctx.guild.roles: try: if role.name != "@everyone": - await bot.add_roles(ctx.author, role) + await self.bot.add_roles(ctx.author, role) except Exception: pass @@ -247,10 +247,10 @@ class ServerUtils(commands.Cog): ), } - voice_channel = await ctx.guild.create_voice_channel( + await ctx.guild.create_voice_channel( name=channel_role_name, bitrate=96000, overwrites=overwrites ) - text_channel = await ctx.guild.create_text_channel( + await ctx.guild.create_text_channel( name=channel_role_name, overwrites=overwrites ) diff --git a/app/cogs/stable_diffusion.py b/app/cogs/stable_diffusion.py index f46f7770..c8c6f342 100755 --- a/app/cogs/stable_diffusion.py +++ b/app/cogs/stable_diffusion.py @@ -64,7 +64,7 @@ class StableDiffusion(commands.Cog): s.settimeout(1) try: s.connect((ip, int(port))) - except: + except Exception: ip = "192.168.1.52" try: await ctx.defer() diff --git a/app/cogs/trackdays.py b/app/cogs/trackdays.py new file mode 100755 index 00000000..623f9983 --- /dev/null +++ b/app/cogs/trackdays.py @@ -0,0 +1,46 @@ +from discord.ext import commands +import discord +import requests +from bs4 import BeautifulSoup + + +class TrackDays(commands.Cog): + def __init__(self, bot): + self.bot: commands.Bot = bot + + async def get_all_tracks(ctx: discord.AutocompleteContext): + """ + returns a list of all the cali tracks for use in auto-complete + """ + url = "https://www.trackpinata.com/" + + response = requests.get(url).text + soup = BeautifulSoup(response, "html.parser") + + return [x.text for x in soup.find_all("h2", class_="thumbnail-header")] + + @commands.slash_command( + guild_ids=None, + name="trackdays", + description="Look up upcoming trackdays", + ) + async def trackdays_lookup( + self, + ctx: commands.Context, + track: discord.Option( + str, + autocomplete=discord.utils.basic_autocomplete(get_all_tracks), + description="Track to look up days for", + ), + ): + track = track.replace(" ", "-").lower() + base_url = f"https://www.trackpinata.com/tracks/{track}" + + response = requests.get(base_url) + soup = BeautifulSoup(response.text, "html.parser") + + soup.find_all("a", class_="list-item w-inline-block") + + +def setup(bot): + bot.add_cog(TrackDays(bot)) diff --git a/app/ffxiv.py b/app/ffxiv.py index 790b6269..8153f43e 100755 --- a/app/ffxiv.py +++ b/app/ffxiv.py @@ -44,7 +44,7 @@ def make_request(name, server): free_company = player_blob["FreeCompany"] fc_member_count = free_company["ActiveMemberCount"] fc_name = free_company["Name"] - fc_slogan = free_company["Slogan"] + # fc_slogan = free_company["Slogan"] fc_tag = free_company["Tag"] fc_rank = free_company["Rank"] fc_estate = free_company["Estate"] diff --git a/app/river_stats.py b/app/river_stats.py index 437e0679..bb385501 100755 --- a/app/river_stats.py +++ b/app/river_stats.py @@ -12,7 +12,7 @@ def get_river_stats(river_id): soup = BeautifulSoup(url.content, "lxml") river_name = " ".join(soup.find("h2").text.split()[2:]) table = soup.find("table", border=1, align="left") - title = table.find("caption").text.strip().split("--")[0].strip() + # title = table.find("caption").text.strip().split("--")[0].strip() for rows in table.findAll("tr"): flow_value = rows.findAll("td", {"class": "highlight2"}) diff --git a/app/stable_diffusion.py b/app/stable_diffusion.py index e5740145..8dc7ef6f 100755 --- a/app/stable_diffusion.py +++ b/app/stable_diffusion.py @@ -1,4 +1,3 @@ -from bs4 import BeautifulSoup import base64 import httpx import tempfile diff --git a/app/star_citizen.py b/app/star_citizen.py index 752ba731..66b2a3d7 100755 --- a/app/star_citizen.py +++ b/app/star_citizen.py @@ -66,11 +66,11 @@ async def rsi_find(player): if "avatar_default_big" not in profile_photo: profile_photo = base_url + profile_photo - handle = ( - soup.find("span", class_="label", string="Handle name") - .findNext("strong", class_="value") - .text - ) + # handle = ( + # soup.find("span", class_="label", string="Handle name") + # .findNext("strong", class_="value") + # .text + # ) citizen_number = ( soup.find("span", class_="label", string="UEE Citizen Record") @@ -222,14 +222,14 @@ async def get_ship(ship_name): item_uuid = "N/A" embed.set_footer(text="item UUID: %s" % item_uuid) - try: - description = ( - soup.find("section", {"class": "citizen-section-collapsible"}) - .findNext("p") - .text - ) - except Exception: - description = "N/A" + # try: + # description = ( + # soup.find("section", {"class": "citizen-section-collapsible"}) + # .findNext("p") + # .text + # ) + # except Exception: + # description = "N/A" # embed.add_field(name="**Description**", #value=description, inline=False) ship_image = (soup.find("a", {"class": "mw-file-description"})).img["src"] @@ -242,7 +242,7 @@ async def get_ship(ship_name): .findNext("a") .text ) - except: + except Exception: manufacturer = "" embed.set_thumbnail( @@ -260,7 +260,7 @@ async def get_ship(ship_name): .findNext("div") .text ) - except: + except Exception: ship_role = "" embed.add_field(name="**Role**", value=ship_role) @@ -289,7 +289,7 @@ async def get_ship(ship_name): if "Not available" in ingame_price: price = "N/A" - except: + except Exception: price = "N/A" embed.add_field( diff --git a/app/stock.py b/app/stock.py index f63e66ec..88eab06e 100755 --- a/app/stock.py +++ b/app/stock.py @@ -1,5 +1,4 @@ import discord -import requests import yfinance as yf import os @@ -10,7 +9,7 @@ def parse_message(symbols, verbose): for s in symbols.split(): try: embeds.append(get_stock(s, verbose=verbose)) - except Exception as e: + except Exception: bad_tickers.append(s) if bad_tickers: embeds.append(_make_error_embed(bad_tickers)) @@ -90,17 +89,9 @@ def get_stock(share_name, verbose=False, fast=False): try: os.mkdir("/root/.cache/py-yfinance") - except OSError as error: + except OSError: pass - change_symbol = "+" - embed_color = 2067276 - meme_url = "https://i.ytimg.com/vi/if-2M3K1tqk/hqdefault.jpg" - - embed = discord.Embed(description="-------", color=embed_color, type="rich") - embed.set_thumbnail(url=meme_url) - embed.set_author(name=share_name) - try: if fast: request = yf.Ticker(share_name).fast_info @@ -110,16 +101,22 @@ def get_stock(share_name, verbose=False, fast=False): request = yf.Ticker(share_name).info current_change = request["currentPrice"] - request["open"] current_price = request["currentPrice"] - except Exception as e: + except Exception: raise ValueError("Invalid symbol %s: empty response from Yahoo" % share_name) - # If stock price has gone down since open, use red and a sad stonk meme - # current_change = request["lastPrice"] - request["open"] + # If stock price has gone down since open, use red and a sad stonk meme + # change_symbol = "+" + embed_color = 2067276 + meme_url = "https://i.ytimg.com/vi/if-2M3K1tqk/hqdefault.jpg" if current_change < 0: - change_symbol = "-" + # change_symbol = "-" embed_color = 15158332 meme_url = "https://i.kym-cdn.com/photos/images/facebook/002/021/567/635.png" + embed = discord.Embed(description="-------", color=embed_color, type="rich") + embed.set_thumbnail(url=meme_url) + embed.set_author(name=share_name) + embed.add_field( name="Current price", value="$" + format(current_price, ",.2f"), diff --git a/app/trackdays.py b/app/trackdays.py deleted file mode 100755 index 7e169e27..00000000 --- a/app/trackdays.py +++ /dev/null @@ -1,78 +0,0 @@ -from datetime import datetime -import json -import httpx -import xmltodict - - -async def get_msreg(track): - base_url = "https://api.motorsportreg.com/rest/calendars/organization" - orgs = { - "turn8": "F3469266-BEFF-E329-4FD6C4B189ACE2A8", - "speedventures": "DF7453ED-BF33-DC17-2C9BFD84C1F05E86", - "speedsf": "072A885E-AD68-6F64-E88C19E4D0D21DFB", - "speeddistrict": "2E22740B-E8C9-9FB9-21406A496429A28B", - "socaldriversclub": "B4FC0113-C903-E9D3-68562D6765806945", - "ongrid": "06277C99-00C9-23EB-FD08FE5275BCC0C5", - "nextlevel": "CC23AEA4-AAB1-D087-4A10818D229DAFD2", - "lightspeed": "BC6417B8-0ED9-DD48-28BA1463C2C14322", - "fast_toys": "F2829F4E-91A1-30B9-919956FB1BE3CFB4", - "drive_tracktime": "F8940175-D299-85F5-4BFFE1243A2D0B88", - "trackedllc": "22332933-D95D-7DD2-A81CE491A98854D5", - } - events = {} - client = httpx.AsyncClient() - - if track == "Both": - tracks_we_care_about = ["buttonwillow", "thunderhill"] - else: - tracks_we_care_about = [track.lower()] - - for org_name, org_id in orgs.items(): - xml_blob = await client.get( - "%s/%s?exclude_cancelled=true&postalcode=94549&radius=500" - % (base_url, org_id) - ) - awaited_xml_blob = xml_blob.text - json_blob = json.loads( - json.dumps(xmltodict.parse(awaited_xml_blob)["response"]["events"]) - ) - - # prints for debug - import pprint - - pp = pprint.PrettyPrinter(indent=4) - - # If an organizer only has one upcoming event on MSReg, it is a dict, otherwise its a list of dicts - # My code assumes list of dicts, so wrap the event dict in a list of 1 item - if json_blob and isinstance(json_blob["event"], dict): - json_blob["event"] = [json_blob["event"]] - - try: - for event in json_blob["event"]: - if any( - x in event["venue"]["name"].lower() for x in tracks_we_care_about - ): - event_object = { - "event_organizer": event["organization"]["name"], - "event_name": event["name"], - "event_url": event["detailuri"].split("?utm")[0], - "event_date": event["start"], - } - track = event["venue"]["name"] - if track not in events: - events[track] = [] - events[track].append(event_object) - for track, track_events in events.items(): - events[track] = sorted( - track_events, - key=lambda event: datetime.fromisoformat( - event["event_date"] - ), - ) - - except Exception as e: - print("Errored on %s" % org_name) - print(e) - pass - - return events diff --git a/dalebot-overview.py b/dalebot-overview.py index f4370aa6..1b31bfd4 100755 --- a/dalebot-overview.py +++ b/dalebot-overview.py @@ -6,7 +6,6 @@ from diagrams.generic.os import LinuxGeneral from diagrams.k8s.compute import Pod from diagrams.onprem.container import Docker from diagrams.onprem.compute import Server -from diagrams.k8s.compute import Pod from diagrams.k8s.podconfig import Secret