diff --git a/.gitignore b/.gitignore index 155e588..492f3d9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ NerdyPy/*.dll NerdyPy/tmp/ NerdyPy/config.yaml NerdyPy/config_humanmusic.yaml +NerdyPy/weather_cache.sqlite NerpyBot.code-workspace ### macOS template diff --git a/NerdyPy/modules/admin.py b/NerdyPy/modules/admin.py index 00de150..f4d041a 100644 --- a/NerdyPy/modules/admin.py +++ b/NerdyPy/modules/admin.py @@ -7,6 +7,7 @@ from discord.app_commands import CommandSyncFailure, MissingApplicationID, TranslationError, checks from discord.ext.commands import Cog, Context, Greedy, command, group, guild_only from models.admin import GuildPrefix + from utils.errors import NerpyException diff --git a/NerdyPy/modules/moderation.py b/NerdyPy/modules/moderation.py index c647818..4111f32 100644 --- a/NerdyPy/modules/moderation.py +++ b/NerdyPy/modules/moderation.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- -from datetime import UTC, datetime, time, timedelta, timezone + +from datetime import UTC, datetime, time, timedelta from typing import Optional, Union from discord import Embed, Member, TextChannel @@ -7,15 +8,16 @@ from discord.ext import tasks from discord.ext.commands import Cog, Context, command, hybrid_command, hybrid_group from humanize import naturaldate -from models.moderation import AutoDelete, AutoKicker from pytimeparse2 import parse -from utils import format as fmt + +from models.moderation import AutoDelete, AutoKicker + +import utils.format as fmt from utils.errors import NerpyException from utils.helpers import empty_subcommand, send_hidden_message -utc = timezone.utc # If no tzinfo is given then UTC is assumed. -loop_run_time = time(hour=12, minute=30, tzinfo=utc) +LOOP_RUN_TIME = time(hour=12, minute=30, tzinfo=UTC) class Moderation(Cog): @@ -32,7 +34,7 @@ def cog_unload(self): self._autokicker_loop.cancel() self._autodeleter_loop.cancel() - @tasks.loop(time=loop_run_time) + @tasks.loop(time=LOOP_RUN_TIME) async def _autokicker_loop(self): self.bot.log.debug("Start Autokicker Loop!") try: @@ -49,9 +51,9 @@ async def _autokicker_loop(self): if len(member.roles) == 1: self.bot.log.debug(f"Found member without role: {member.display_name}") kick_reminder = datetime.now(UTC) - timedelta(seconds=(configuration.KickAfter / 2)) - kick_reminder = kick_reminder.replace(tzinfo=timezone.utc) + kick_reminder = kick_reminder.replace(tzinfo=UTC) kick_after = datetime.now(UTC) - timedelta(seconds=configuration.KickAfter) - kick_after = kick_after.replace(tzinfo=timezone.utc) + kick_after = kick_after.replace(tzinfo=UTC) if member.joined_at < kick_after: self.bot.log.debug(f"Kick member {member.display_name}!") @@ -85,7 +87,7 @@ async def _autodeleter_loop(self): list_before = None else: list_before = datetime.now(UTC) - timedelta(seconds=configuration.DeleteOlderThan) - list_before = list_before.replace(tzinfo=timezone.utc) + list_before = list_before.replace(tzinfo=UTC) channel = guild.get_channel(configuration.ChannelId) messages = [] diff --git a/NerdyPy/modules/music.py b/NerdyPy/modules/music.py index f8d2ea8..ea831e5 100644 --- a/NerdyPy/modules/music.py +++ b/NerdyPy/modules/music.py @@ -11,7 +11,8 @@ hybrid_command, hybrid_group, ) -from utils import format as fmt + +import utils.format as fmt from utils.audio import QueuedSong from utils.checks import is_connected_to_voice from utils.download import download, fetch_yt_infos diff --git a/NerdyPy/modules/raidplaner.py b/NerdyPy/modules/raidplaner.py index 2631217..2f40802 100644 --- a/NerdyPy/modules/raidplaner.py +++ b/NerdyPy/modules/raidplaner.py @@ -5,7 +5,9 @@ from discord import Embed from discord.ext.commands import Cog, Context, command + from models.raidplaner import RaidEncounter, RaidEncounterRole, RaidEvent, RaidTemplate + from utils.conversation import Conversation diff --git a/NerdyPy/modules/random.py b/NerdyPy/modules/random.py index 2aad844..81d7fb9 100644 --- a/NerdyPy/modules/random.py +++ b/NerdyPy/modules/random.py @@ -6,7 +6,8 @@ from aiohttp import ClientSession from discord import Embed from discord.ext.commands import Cog, Context, bot_has_permissions, hybrid_command -from utils import format as fmt + +import utils.format as fmt from utils.errors import NerpyException diff --git a/NerdyPy/modules/reminder.py b/NerdyPy/modules/reminder.py index 491b228..7bcb596 100644 --- a/NerdyPy/modules/reminder.py +++ b/NerdyPy/modules/reminder.py @@ -6,7 +6,9 @@ from discord import TextChannel from discord.ext import tasks from discord.ext.commands import Context, GroupCog, hybrid_command + from models.reminder import ReminderMessage + from utils.format import box, pagify from utils.helpers import send_hidden_message diff --git a/NerdyPy/modules/search.py b/NerdyPy/modules/search.py index 707d1c9..f92d6ed 100644 --- a/NerdyPy/modules/search.py +++ b/NerdyPy/modules/search.py @@ -11,7 +11,8 @@ from discord.ext.commands import Context, GroupCog, bot_has_permissions, hybrid_command from igdb.wrapper import IGDBWrapper from requests import post -from utils import format as fmt + +import utils.format as fmt from utils.errors import NerpyException from utils.helpers import youtube diff --git a/NerdyPy/modules/tagging.py b/NerdyPy/modules/tagging.py index 6f5246d..40a9dab 100644 --- a/NerdyPy/modules/tagging.py +++ b/NerdyPy/modules/tagging.py @@ -15,7 +15,8 @@ hybrid_group, ) from models.tagging import Tag, TagType, TagTypeConverter -from utils import format as fmt + +import utils.format as fmt from utils.audio import QueuedSong from utils.checks import is_connected_to_voice from utils.download import download diff --git a/NerdyPy/modules/utility.py b/NerdyPy/modules/utility.py index a79d363..a6fe1d3 100644 --- a/NerdyPy/modules/utility.py +++ b/NerdyPy/modules/utility.py @@ -2,10 +2,11 @@ from datetime import UTC, datetime -from aiohttp import ClientSession from discord import Embed, app_commands from discord.ext.commands import Cog, Context, bot_has_permissions, hybrid_command -from utils import format as fmt +from openweather.weather import OpenWeather + +import utils.format as fmt from utils.errors import NerpyException from utils.helpers import send_hidden_message @@ -16,7 +17,7 @@ def __init__(self, bot): bot.log.info(f"loaded {__name__}") self.bot = bot - self.weather_api_key = self.bot.config.get("utility", "openweather") + self.weather_api = OpenWeather(self.bot.config["utility"]["openweather"]) @hybrid_command(name="ping", hidden=True) @bot_has_permissions(send_messages=True) @@ -37,75 +38,62 @@ async def _uptime(self, ctx: Context): @bot_has_permissions(embed_links=True) async def _get_weather(self, ctx: Context, *, query: str): """outputs weather information""" - location_url = f"http://api.openweathermap.org/geo/1.0/direct?q={query}&appid={self.weather_api_key}" - - for umlaut in ["ä", "ö", "ü"]: - if umlaut in query: - await send_hidden_message(ctx, "Please use english names only!") - return - - async with ClientSession() as session: - async with session.get(location_url) as response: - if response.status != 200: - err = f"The api-webserver responded with a code: {response.status} - {response.reason}" - raise NerpyException(err) - location = await response.json() - - if location is None: - return - - lat = location[0].get("lat") - lon = location[0].get("lon") - weather_url = f"http://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={self.weather_api_key}&units=metric" - - async with ClientSession() as session: - async with session.get(weather_url) as response: - if response.status != 200: - err = f"The api-webserver responded with a code: {response.status} - {response.reason}" - raise NerpyException(err) - weather = await response.json() - - conditions = [] - for w in weather.get("weather", dict()): - conditions.append(w.get("main")) - - sunrise = datetime.fromtimestamp(int(weather.get("sys", dict()).get("sunrise"))).strftime("%H:%M") - sunset = datetime.fromtimestamp(int(weather.get("sys", dict()).get("sunset"))).strftime("%H:%M") - - emb = Embed() - emb.add_field( - name=f":earth_africa: {fmt.bold('location')}", - value=f"""[{weather.get("name")}, - {weather.get("sys", dict()).get("country")}](https://openweathermap.org/city/{weather.get("id")})""", - ) - emb.add_field( - name=f":thermometer: {fmt.bold('temperature')}", - value=f"{weather['main']['temp']}°C", - ) - emb.add_field( - name=f":cloud: {fmt.bold('condition')}", - value=str.join(", ", conditions), - ) - emb.add_field( - name=f":sweat_drops: {fmt.bold('humidity')}", - value=f"{weather['main']['humidity']}%", - ) - emb.add_field( - name=f":wind_chime: {fmt.bold('wind')}", - value=f"{weather['wind']['speed']} m/s", - ) - emb.add_field( - name=f"🔆 {fmt.bold('min-max')}", - value=f"{weather['main']['temp_min']}°C - {weather['main']['temp_max']}°C", - ) - emb.add_field(name=f":city_sunrise: {fmt.bold('sunrise')}", value=f"{sunrise} UTC") - emb.add_field(name=f":city_sunset: {fmt.bold('sunset')}", value=f"{sunset} UTC") - emb.set_footer( - text="Powered by openweathermap.org", - icon_url=f"http://openweathermap.org/img/w/{weather.get('weather', list())[0].get('icon')}.png", - ) - - await ctx.send(embed=emb) + try: + async with ctx.typing(): + for umlaut in ["ä", "ö", "ü"]: + if umlaut in query: + await send_hidden_message(ctx, "Please use english names only!") + return + + weather = self.weather_api.get_weather(city=query) + + conditions = [] + for w in weather.get("weather", dict()): + conditions.append(w.get("main")) + + sunrise = datetime.fromtimestamp(int(weather.get("sys", dict()).get("sunrise"))).strftime("%H:%M") + sunset = datetime.fromtimestamp(int(weather.get("sys", dict()).get("sunset"))).strftime("%H:%M") + + emb = Embed() + emb.add_field( + name=f":earth_africa: {fmt.bold('location')}", + value=f"""[{weather.get("name")}, + {weather.get("sys", dict()).get("country")}](https://openweathermap.org/city/{weather.get("id")})""", + ) + temp = self.weather_api.convert_temperature(weather["main"]["temp"]) + emb.add_field( + name=f":thermometer: {fmt.bold('temperature')}", + value=f"{temp:.2f}°C", + ) + emb.add_field( + name=f":cloud: {fmt.bold('condition')}", + value=str.join(", ", conditions), + ) + emb.add_field( + name=f":sweat_drops: {fmt.bold('humidity')}", + value=f"{weather['main']['humidity']}%", + ) + emb.add_field( + name=f":wind_chime: {fmt.bold('wind')}", + value=f"{weather['wind']['speed']} m/s", + ) + temp_min = self.weather_api.convert_temperature(weather["main"]["temp_min"]) + temp_max = self.weather_api.convert_temperature(weather["main"]["temp_max"]) + emb.add_field( + name=f"🔆 {fmt.bold('min-max')}", + value=f"{temp_min:.2f}°C - {temp_max:.2f}°C", + ) + emb.add_field(name=f":city_sunrise: {fmt.bold('sunrise')}", value=f"{sunrise} UTC") + emb.add_field(name=f":city_sunset: {fmt.bold('sunset')}", value=f"{sunset} UTC") + emb.set_footer( + text="Powered by openweathermap.org", + icon_url=f"http://openweathermap.org/img/w/{weather.get('weather', list())[0].get('icon')}.png", + ) + + await ctx.send(embed=emb) + except Exception as ex: + self.bot.log.error(f"Error while fetching weather: {ex}") + await send_hidden_message(ctx, "An error occurred while fetching the weather information.") async def setup(bot): diff --git a/NerdyPy/modules/wow.py b/NerdyPy/modules/wow.py index 4f04184..73a5087 100644 --- a/NerdyPy/modules/wow.py +++ b/NerdyPy/modules/wow.py @@ -9,9 +9,11 @@ from blizzapi import Language, Region, RetailClient from discord import Color, Embed from discord.ext.commands import Context, GroupCog, bot_has_permissions, hybrid_command, hybrid_group + from models.wow import WoW + from utils.errors import NerpyException -from utils.helpers import send_hidden_message +from utils.helpers import empty_subcommand, send_hidden_message class WowApiLanguage(Enum): @@ -125,8 +127,7 @@ def _get_best_mythic_keys(region, realm, name): @hybrid_group(name="language", aliases=["lang", "locale"]) async def _wow_language(self, ctx: Context): - if ctx.invoked_subcommand is None: - await ctx.send_help(ctx.command) + empty_subcommand(ctx) @_wow_language.command(name="get") async def _wow_language_get(self, ctx: Context): diff --git a/NerdyPy/utils/checks.py b/NerdyPy/utils/checks.py index 5b914ca..004122d 100644 --- a/NerdyPy/utils/checks.py +++ b/NerdyPy/utils/checks.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- + from utils.helpers import send_hidden_message diff --git a/NerdyPy/utils/download.py b/NerdyPy/utils/download.py index 1ed6fe6..7212ef4 100644 --- a/NerdyPy/utils/download.py +++ b/NerdyPy/utils/download.py @@ -9,9 +9,11 @@ import ffmpeg import requests -import youtube_dl from cachetools import TTLCache from discord import FFmpegOpusAudio +from yt_dlp import YoutubeDL +from yt_dlp.utils import DownloadError + from utils.errors import NerpyException LOG = logging.getLogger("nerpybot") @@ -38,7 +40,7 @@ "default_search": "auto", "source_address": "0.0.0.0", # bind to ipv4 since ipv6 addresses cause issues sometimes } -YTDL = youtube_dl.YoutubeDL(YTDL_ARGS) +YTDL = YoutubeDL(YTDL_ARGS) def convert(source, tag=False, is_stream=True): @@ -65,7 +67,7 @@ def lookup_file(file_name): def fetch_yt_infos(url: str): - """Fetches information about a youtube video""" + """Fetches information about a YouTube video""" if url in CACHE: LOG.info("Using cached information for URL: %s", url) return CACHE[url] @@ -74,7 +76,7 @@ def fetch_yt_infos(url: str): data = None try: data = YTDL.extract_info(url, download=False) - except youtube_dl.utils.DownloadError as e: + except DownloadError as e: if "Sign in to confirm you’re not a bot" in str(e): data = YTDL.extract_info(url, download=False) @@ -95,14 +97,14 @@ def download(url: str, tag: bool = False, video_id: str = None): audio_bytes = BytesIO(response.content) if audio_bytes is None: - raise NerpyException(f"could not find a valid source in: {url}") + raise NerpyException(f"Could not find a valid source in: {url}") return convert(audio_bytes, tag) else: - dlfile = lookup_file(video_id) + dl_file = lookup_file(video_id) - if dlfile is None: + if dl_file is None: _ = YTDL.download([url]) - dlfile = lookup_file(video_id) + dl_file = lookup_file(video_id) - return convert(dlfile, is_stream=False) + return convert(dl_file, is_stream=False) diff --git a/NerdyPy/utils/format.py b/NerdyPy/utils/format.py index a1ba2ae..0d90b1f 100644 --- a/NerdyPy/utils/format.py +++ b/NerdyPy/utils/format.py @@ -7,22 +7,23 @@ class MLStripper(HTMLParser): """Markup Language Stripper""" - def __init__(self): + def __init__(self) -> None: super().__init__() self.reset() self.strict = False self.convert_charrefs = True - self.fed = [] + self.fed: list[str] = [] - def handle_data(self, data): + def handle_data(self, data: str) -> None: """handle data""" self.fed.append(data) - def get_data(self): + def get_data(self) -> str: """return data""" return "".join(self.fed) - def error(self, message): + @staticmethod + def error(message): """had to do this cuz abstract""" return message diff --git a/NerdyPy/utils/helpers.py b/NerdyPy/utils/helpers.py index 7fbedc4..64f4930 100644 --- a/NerdyPy/utils/helpers.py +++ b/NerdyPy/utils/helpers.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- + from discord.ext.commands import Context from googleapiclient.discovery import build from utils.errors import NerpyException @@ -14,7 +15,8 @@ def empty_subcommand(ctx: Context): if len(args) > 2: raise NerpyException("Command not found!") elif len(args) <= 1: - return ctx.send_help(ctx.command) + ctx.send_help(ctx.command) + return def youtube(yt_key, return_type, query): diff --git a/pyproject.toml b/pyproject.toml index 0cc8902..9448c16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,10 +23,13 @@ bot = [ "aiohttp>=3.10.11", "idna>=3.7", "discord-py[voice]==2.5.2", - "youtube-dl", "pynacl>=1.5.0", "pyyaml>=6.0.2", "blizzapi>=1.0.2", + "openweather-wrapper>=0.1.1", + "requests-cache>=1.2.1", + "matplotlib>=3.10.3", + "yt-dlp>=2025.7.21", ] test = [ "pytest>=8.4.1", @@ -47,6 +50,3 @@ line-ending = "lf" [tool.uv] default-groups = ["bot"] - -[tool.uv.sources] -youtube-dl = { git = "https://github.com/ytdl-org/youtube-dl.git", branch = "master" } diff --git a/uv.lock b/uv.lock index cc90b38..35cb672 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = "==3.12.*" [[package]] @@ -127,6 +127,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" }, ] +[[package]] +name = "cattrs" +version = "25.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/2b/561d78f488dcc303da4639e02021311728fb7fda8006dd2835550cddd9ed/cattrs-25.1.1.tar.gz", hash = "sha256:c914b734e0f2d59e5b720d145ee010f1fd9a13ee93900922a2f3f9d593b8382c", size = 435016, upload-time = "2025-06-04T20:27:15.44Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/b0/215274ef0d835bbc1056392a367646648b6084e39d489099959aefcca2af/cattrs-25.1.1-py3-none-any.whl", hash = "sha256:1b40b2d3402af7be79a7e7e097a9b4cd16d4c06e6d526644b0b26a063a1cc064", size = 69386, upload-time = "2025-06-04T20:27:13.969Z" }, +] + [[package]] name = "certifi" version = "2025.6.15" @@ -201,6 +214,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, +] + [[package]] name = "coverage" version = "7.9.2" @@ -221,6 +256,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/38/bbe2e63902847cf79036ecc75550d0698af31c91c7575352eb25190d0fb3/coverage-7.9.2-py3-none-any.whl", hash = "sha256:e425cd5b00f6fc0ed7cdbd766c70be8baab4b7839e4d4fe5fac48581dd968ea4", size = 204005, upload-time = "2025-07-03T10:54:13.491Z" }, ] +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + [[package]] name = "discord-py" version = "2.5.2" @@ -264,6 +308,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9f/56/13ab06b4f93ca7cac71078fbe37fcea175d3216f31f85c3168a6bbd0bb9a/flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e", size = 57922, upload-time = "2025-06-20T19:31:34.425Z" }, ] +[[package]] +name = "fonttools" +version = "4.59.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/27/ec3c723bfdf86f34c5c82bf6305df3e0f0d8ea798d2d3a7cb0c0a866d286/fonttools-4.59.0.tar.gz", hash = "sha256:be392ec3529e2f57faa28709d60723a763904f71a2b63aabe14fee6648fe3b14", size = 3532521, upload-time = "2025-07-16T12:04:54.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/77/b1c8af22f4265e951cd2e5535dbef8859efcef4fb8dee742d368c967cddb/fonttools-4.59.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f9b3a78f69dcbd803cf2fb3f972779875b244c1115481dfbdd567b2c22b31f6b", size = 2767562, upload-time = "2025-07-16T12:04:06.895Z" }, + { url = "https://files.pythonhosted.org/packages/ff/5a/aeb975699588176bb357e8b398dfd27e5d3a2230d92b81ab8cbb6187358d/fonttools-4.59.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:57bb7e26928573ee7c6504f54c05860d867fd35e675769f3ce01b52af38d48e2", size = 2335168, upload-time = "2025-07-16T12:04:08.695Z" }, + { url = "https://files.pythonhosted.org/packages/54/97/c6101a7e60ae138c4ef75b22434373a0da50a707dad523dd19a4889315bf/fonttools-4.59.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4536f2695fe5c1ffb528d84a35a7d3967e5558d2af58b4775e7ab1449d65767b", size = 4909850, upload-time = "2025-07-16T12:04:10.761Z" }, + { url = "https://files.pythonhosted.org/packages/bd/6c/fa4d18d641054f7bff878cbea14aa9433f292b9057cb1700d8e91a4d5f4f/fonttools-4.59.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:885bde7d26e5b40e15c47bd5def48b38cbd50830a65f98122a8fb90962af7cd1", size = 4955131, upload-time = "2025-07-16T12:04:12.846Z" }, + { url = "https://files.pythonhosted.org/packages/20/5c/331947fc1377deb928a69bde49f9003364f5115e5cbe351eea99e39412a2/fonttools-4.59.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6801aeddb6acb2c42eafa45bc1cb98ba236871ae6f33f31e984670b749a8e58e", size = 4899667, upload-time = "2025-07-16T12:04:14.558Z" }, + { url = "https://files.pythonhosted.org/packages/8a/46/b66469dfa26b8ff0baa7654b2cc7851206c6d57fe3abdabbaab22079a119/fonttools-4.59.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:31003b6a10f70742a63126b80863ab48175fb8272a18ca0846c0482968f0588e", size = 5051349, upload-time = "2025-07-16T12:04:16.388Z" }, + { url = "https://files.pythonhosted.org/packages/2e/05/ebfb6b1f3a4328ab69787d106a7d92ccde77ce66e98659df0f9e3f28d93d/fonttools-4.59.0-cp312-cp312-win32.whl", hash = "sha256:fbce6dae41b692a5973d0f2158f782b9ad05babc2c2019a970a1094a23909b1b", size = 2201315, upload-time = "2025-07-16T12:04:18.557Z" }, + { url = "https://files.pythonhosted.org/packages/09/45/d2bdc9ea20bbadec1016fd0db45696d573d7a26d95ab5174ffcb6d74340b/fonttools-4.59.0-cp312-cp312-win_amd64.whl", hash = "sha256:332bfe685d1ac58ca8d62b8d6c71c2e52a6c64bc218dc8f7825c9ea51385aa01", size = 2249408, upload-time = "2025-07-16T12:04:20.489Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9c/df0ef2c51845a13043e5088f7bb988ca6cd5bb82d5d4203d6a158aa58cf2/fonttools-4.59.0-py3-none-any.whl", hash = "sha256:241313683afd3baacb32a6bd124d0bce7404bc5280e12e291bae1b9bba28711d", size = 1128050, upload-time = "2025-07-16T12:04:52.687Z" }, +] + [[package]] name = "frozenlist" version = "1.7.0" @@ -439,6 +500,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] +[[package]] +name = "kiwisolver" +version = "1.4.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/59/7c91426a8ac292e1cdd53a63b6d9439abd573c875c3f92c146767dd33faf/kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", size = 97538, upload-time = "2024-12-24T18:30:51.519Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/aa/cea685c4ab647f349c3bc92d2daf7ae34c8e8cf405a6dcd3a497f58a2ac3/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502", size = 124152, upload-time = "2024-12-24T18:29:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/c5/0b/8db6d2e2452d60d5ebc4ce4b204feeb16176a851fd42462f66ade6808084/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31", size = 66555, upload-time = "2024-12-24T18:29:19.146Z" }, + { url = "https://files.pythonhosted.org/packages/60/26/d6a0db6785dd35d3ba5bf2b2df0aedc5af089962c6eb2cbf67a15b81369e/kiwisolver-1.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb", size = 65067, upload-time = "2024-12-24T18:29:20.096Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ed/1d97f7e3561e09757a196231edccc1bcf59d55ddccefa2afc9c615abd8e0/kiwisolver-1.4.8-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f", size = 1378443, upload-time = "2024-12-24T18:29:22.843Z" }, + { url = "https://files.pythonhosted.org/packages/29/61/39d30b99954e6b46f760e6289c12fede2ab96a254c443639052d1b573fbc/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc", size = 1472728, upload-time = "2024-12-24T18:29:24.463Z" }, + { url = "https://files.pythonhosted.org/packages/0c/3e/804163b932f7603ef256e4a715e5843a9600802bb23a68b4e08c8c0ff61d/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a", size = 1478388, upload-time = "2024-12-24T18:29:25.776Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9e/60eaa75169a154700be74f875a4d9961b11ba048bef315fbe89cb6999056/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a", size = 1413849, upload-time = "2024-12-24T18:29:27.202Z" }, + { url = "https://files.pythonhosted.org/packages/bc/b3/9458adb9472e61a998c8c4d95cfdfec91c73c53a375b30b1428310f923e4/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a", size = 1475533, upload-time = "2024-12-24T18:29:28.638Z" }, + { url = "https://files.pythonhosted.org/packages/e4/7a/0a42d9571e35798de80aef4bb43a9b672aa7f8e58643d7bd1950398ffb0a/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3", size = 2268898, upload-time = "2024-12-24T18:29:30.368Z" }, + { url = "https://files.pythonhosted.org/packages/d9/07/1255dc8d80271400126ed8db35a1795b1a2c098ac3a72645075d06fe5c5d/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b", size = 2425605, upload-time = "2024-12-24T18:29:33.151Z" }, + { url = "https://files.pythonhosted.org/packages/84/df/5a3b4cf13780ef6f6942df67b138b03b7e79e9f1f08f57c49957d5867f6e/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4", size = 2375801, upload-time = "2024-12-24T18:29:34.584Z" }, + { url = "https://files.pythonhosted.org/packages/8f/10/2348d068e8b0f635c8c86892788dac7a6b5c0cb12356620ab575775aad89/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d", size = 2520077, upload-time = "2024-12-24T18:29:36.138Z" }, + { url = "https://files.pythonhosted.org/packages/32/d8/014b89fee5d4dce157d814303b0fce4d31385a2af4c41fed194b173b81ac/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8", size = 2338410, upload-time = "2024-12-24T18:29:39.991Z" }, + { url = "https://files.pythonhosted.org/packages/bd/72/dfff0cc97f2a0776e1c9eb5bef1ddfd45f46246c6533b0191887a427bca5/kiwisolver-1.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50", size = 71853, upload-time = "2024-12-24T18:29:42.006Z" }, + { url = "https://files.pythonhosted.org/packages/dc/85/220d13d914485c0948a00f0b9eb419efaf6da81b7d72e88ce2391f7aed8d/kiwisolver-1.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476", size = 65424, upload-time = "2024-12-24T18:29:44.38Z" }, +] + [[package]] name = "mako" version = "1.3.10" @@ -469,6 +553,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, ] +[[package]] +name = "matplotlib" +version = "3.10.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/26/91/d49359a21893183ed2a5b6c76bec40e0b1dcbf8ca148f864d134897cfc75/matplotlib-3.10.3.tar.gz", hash = "sha256:2f82d2c5bb7ae93aaaa4cd42aca65d76ce6376f83304fa3a630b569aca274df0", size = 34799811, upload-time = "2025-05-08T19:10:54.39Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/43/6b80eb47d1071f234ef0c96ca370c2ca621f91c12045f1401b5c9b28a639/matplotlib-3.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0ab1affc11d1f495ab9e6362b8174a25afc19c081ba5b0775ef00533a4236eea", size = 8179689, upload-time = "2025-05-08T19:10:07.602Z" }, + { url = "https://files.pythonhosted.org/packages/0f/70/d61a591958325c357204870b5e7b164f93f2a8cca1dc6ce940f563909a13/matplotlib-3.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2a818d8bdcafa7ed2eed74487fdb071c09c1ae24152d403952adad11fa3c65b4", size = 8050466, upload-time = "2025-05-08T19:10:09.383Z" }, + { url = "https://files.pythonhosted.org/packages/e7/75/70c9d2306203148cc7902a961240c5927dd8728afedf35e6a77e105a2985/matplotlib-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748ebc3470c253e770b17d8b0557f0aa85cf8c63fd52f1a61af5b27ec0b7ffee", size = 8456252, upload-time = "2025-05-08T19:10:11.958Z" }, + { url = "https://files.pythonhosted.org/packages/c4/91/ba0ae1ff4b3f30972ad01cd4a8029e70a0ec3b8ea5be04764b128b66f763/matplotlib-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed70453fd99733293ace1aec568255bc51c6361cb0da94fa5ebf0649fdb2150a", size = 8601321, upload-time = "2025-05-08T19:10:14.47Z" }, + { url = "https://files.pythonhosted.org/packages/d2/88/d636041eb54a84b889e11872d91f7cbf036b3b0e194a70fa064eb8b04f7a/matplotlib-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dbed9917b44070e55640bd13419de83b4c918e52d97561544814ba463811cbc7", size = 9406972, upload-time = "2025-05-08T19:10:16.569Z" }, + { url = "https://files.pythonhosted.org/packages/b1/79/0d1c165eac44405a86478082e225fce87874f7198300bbebc55faaf6d28d/matplotlib-3.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:cf37d8c6ef1a48829443e8ba5227b44236d7fcaf7647caa3178a4ff9f7a5be05", size = 8067954, upload-time = "2025-05-08T19:10:18.663Z" }, +] + [[package]] name = "mccabe" version = "0.7.0" @@ -528,13 +637,16 @@ bot = [ { name = "humanize" }, { name = "idna" }, { name = "igdb-api-v4" }, + { name = "matplotlib" }, + { name = "openweather-wrapper" }, { name = "pymysql" }, { name = "pynacl" }, { name = "pytimeparse2" }, { name = "pyyaml" }, + { name = "requests-cache" }, { name = "sqlalchemy" }, { name = "twitchapi" }, - { name = "youtube-dl" }, + { name = "yt-dlp" }, ] migrations = [ { name = "alembic" }, @@ -559,13 +671,16 @@ bot = [ { name = "humanize", specifier = ">=4,<5" }, { name = "idna", specifier = ">=3.7" }, { name = "igdb-api-v4", specifier = ">=0.3,<0.4" }, + { name = "matplotlib", specifier = ">=3.10.3" }, + { name = "openweather-wrapper", specifier = ">=0.1.1" }, { name = "pymysql", specifier = ">=1.1,<1.2" }, { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytimeparse2", specifier = ">=1.7,<1.8" }, { name = "pyyaml", specifier = ">=6.0.2" }, + { name = "requests-cache", specifier = ">=1.2.1" }, { name = "sqlalchemy", specifier = ">=2.0,<2.1" }, { name = "twitchapi", specifier = ">=4.2.0,<4.3.0" }, - { name = "youtube-dl", git = "https://github.com/ytdl-org/youtube-dl.git?branch=master" }, + { name = "yt-dlp", specifier = ">=2025.7.21" }, ] migrations = [ { name = "alembic", specifier = ">=1.16.2" }, @@ -578,6 +693,25 @@ test = [ { name = "pytest-cov", specifier = ">=6.2.1" }, ] +[[package]] +name = "numpy" +version = "2.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/37/7d/3fec4199c5ffb892bed55cff901e4f39a58c81df9c44c280499e92cad264/numpy-2.3.2.tar.gz", hash = "sha256:e0486a11ec30cdecb53f184d496d1c6a20786c81e55e41640270130056f8ee48", size = 20489306, upload-time = "2025-07-24T21:32:07.553Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/6d/745dd1c1c5c284d17725e5c802ca4d45cfc6803519d777f087b71c9f4069/numpy-2.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bc3186bea41fae9d8e90c2b4fb5f0a1f5a690682da79b92574d63f56b529080b", size = 20956420, upload-time = "2025-07-24T20:28:18.002Z" }, + { url = "https://files.pythonhosted.org/packages/bc/96/e7b533ea5740641dd62b07a790af5d9d8fec36000b8e2d0472bd7574105f/numpy-2.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f4f0215edb189048a3c03bd5b19345bdfa7b45a7a6f72ae5945d2a28272727f", size = 14184660, upload-time = "2025-07-24T20:28:39.522Z" }, + { url = "https://files.pythonhosted.org/packages/2b/53/102c6122db45a62aa20d1b18c9986f67e6b97e0d6fbc1ae13e3e4c84430c/numpy-2.3.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b1224a734cd509f70816455c3cffe13a4f599b1bf7130f913ba0e2c0b2006c0", size = 5113382, upload-time = "2025-07-24T20:28:48.544Z" }, + { url = "https://files.pythonhosted.org/packages/2b/21/376257efcbf63e624250717e82b4fae93d60178f09eb03ed766dbb48ec9c/numpy-2.3.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3dcf02866b977a38ba3ec10215220609ab9667378a9e2150615673f3ffd6c73b", size = 6647258, upload-time = "2025-07-24T20:28:59.104Z" }, + { url = "https://files.pythonhosted.org/packages/91/ba/f4ebf257f08affa464fe6036e13f2bf9d4642a40228781dc1235da81be9f/numpy-2.3.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:572d5512df5470f50ada8d1972c5f1082d9a0b7aa5944db8084077570cf98370", size = 14281409, upload-time = "2025-07-24T20:40:30.298Z" }, + { url = "https://files.pythonhosted.org/packages/59/ef/f96536f1df42c668cbacb727a8c6da7afc9c05ece6d558927fb1722693e1/numpy-2.3.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8145dd6d10df13c559d1e4314df29695613575183fa2e2d11fac4c208c8a1f73", size = 16641317, upload-time = "2025-07-24T20:40:56.625Z" }, + { url = "https://files.pythonhosted.org/packages/f6/a7/af813a7b4f9a42f498dde8a4c6fcbff8100eed00182cc91dbaf095645f38/numpy-2.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:103ea7063fa624af04a791c39f97070bf93b96d7af7eb23530cd087dc8dbe9dc", size = 16056262, upload-time = "2025-07-24T20:41:20.797Z" }, + { url = "https://files.pythonhosted.org/packages/8b/5d/41c4ef8404caaa7f05ed1cfb06afe16a25895260eacbd29b4d84dff2920b/numpy-2.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc927d7f289d14f5e037be917539620603294454130b6de200091e23d27dc9be", size = 18579342, upload-time = "2025-07-24T20:41:50.753Z" }, + { url = "https://files.pythonhosted.org/packages/a1/4f/9950e44c5a11636f4a3af6e825ec23003475cc9a466edb7a759ed3ea63bd/numpy-2.3.2-cp312-cp312-win32.whl", hash = "sha256:d95f59afe7f808c103be692175008bab926b59309ade3e6d25009e9a171f7036", size = 6320610, upload-time = "2025-07-24T20:42:01.551Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2f/244643a5ce54a94f0a9a2ab578189c061e4a87c002e037b0829dd77293b6/numpy-2.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:9e196ade2400c0c737d93465327d1ae7c06c7cb8a1756121ebf54b06ca183c7f", size = 12786292, upload-time = "2025-07-24T20:42:20.738Z" }, + { url = "https://files.pythonhosted.org/packages/54/cd/7b5f49d5d78db7badab22d8323c1b6ae458fbf86c4fdfa194ab3cd4eb39b/numpy-2.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:ee807923782faaf60d0d7331f5e86da7d5e3079e28b291973c545476c2b00d07", size = 10194071, upload-time = "2025-07-24T20:42:36.657Z" }, +] + [[package]] name = "oauthlib" version = "3.3.1" @@ -587,6 +721,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, ] +[[package]] +name = "openweather-wrapper" +version = "0.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/27/d2/bdcb597e1d155baebf54172a8dbb28e23755fea00c7b52408e700c33026c/openweather_wrapper-0.1.1.tar.gz", hash = "sha256:fa34371d8527846ed6cffec08fa8191fa70793af4442770333fb90d322693234", size = 11715, upload-time = "2024-12-17T18:23:39.294Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/41/2eb23ae2d58f66dbd07d79588a5ba56060a0d533eaa9722ad84ed1c9a5b1/openweather_wrapper-0.1.1-py3-none-any.whl", hash = "sha256:e5240911a6d2340f396605091bf0b6a26f5a15da9cc6f82087eb859c5478b5d2", size = 10843, upload-time = "2024-12-17T18:23:31.637Z" }, +] + [[package]] name = "packaging" version = "25.0" @@ -605,6 +751,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, ] +[[package]] +name = "pillow" +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, + { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, + { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, + { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, + { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, + { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, +] + [[package]] name = "platformdirs" version = "4.3.8" @@ -852,6 +1017,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, ] +[[package]] +name = "requests-cache" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "cattrs" }, + { name = "platformdirs" }, + { name = "requests" }, + { name = "url-normalize" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1a/be/7b2a95a9e7a7c3e774e43d067c51244e61dea8b120ae2deff7089a93fb2b/requests_cache-1.2.1.tar.gz", hash = "sha256:68abc986fdc5b8d0911318fbb5f7c80eebcd4d01bfacc6685ecf8876052511d1", size = 3018209, upload-time = "2024-06-18T17:18:03.774Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/2e/8f4051119f460cfc786aa91f212165bb6e643283b533db572d7b33952bd2/requests_cache-1.2.1-py3-none-any.whl", hash = "sha256:1285151cddf5331067baa82598afe2d47c7495a1334bfe7a7d329b43e9fd3603", size = 61425, upload-time = "2024-06-18T17:17:45Z" }, +] + [[package]] name = "requests-oauthlib" version = "2.0.0" @@ -939,6 +1121,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686", size = 11488, upload-time = "2025-06-02T15:12:03.405Z" }, ] +[[package]] +name = "url-normalize" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/31/febb777441e5fcdaacb4522316bf2a527c44551430a4873b052d545e3279/url_normalize-2.2.1.tar.gz", hash = "sha256:74a540a3b6eba1d95bdc610c24f2c0141639f3ba903501e61a52a8730247ff37", size = 18846, upload-time = "2025-04-26T20:37:58.553Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/d9/5ec15501b675f7bc07c5d16aa70d8d778b12375686b6efd47656efdc67cd/url_normalize-2.2.1-py3-none-any.whl", hash = "sha256:3deb687587dc91f7b25c9ae5162ffc0f057ae85d22b1e15cf5698311247f567b", size = 14728, upload-time = "2025-04-26T20:37:57.217Z" }, +] + [[package]] name = "urllib3" version = "2.5.0" @@ -980,6 +1174,10 @@ wheels = [ ] [[package]] -name = "youtube-dl" -version = "2025.4.7" -source = { git = "https://github.com/ytdl-org/youtube-dl.git?branch=master#a084c80f7bac9ae343075a97cc0fb2c1c96ade89" } +name = "yt-dlp" +version = "2025.7.21" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/3a/343f7a0024ddd4c30f150e8d8f57fd7b924846f97d99fc0dcd75ea8d2773/yt_dlp-2025.7.21.tar.gz", hash = "sha256:46fbb53eab1afbe184c45b4c17e9a6eba614be680e4c09de58b782629d0d7f43", size = 3050219, upload-time = "2025-07-21T23:59:03.826Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/2f/abe59a3204c749fed494849ea29176bcefa186ec8898def9e43f649ddbcf/yt_dlp-2025.7.21-py3-none-any.whl", hash = "sha256:d7aa2b53f9b2f35453346360f41811a0dad1e956e70b35a4ae95039d4d815d15", size = 3288681, upload-time = "2025-07-21T23:59:01.788Z" }, +]