Completed the events system upgrade and expanded the notifications events with support for apprise.
This commit is contained in:
parent
0f7f22bdbf
commit
a7e8d242c9
19 changed files with 1639 additions and 1110 deletions
10
README.md
10
README.md
|
|
@ -14,7 +14,7 @@ live streams, and includes features like scheduling downloads, sending notificat
|
|||
* Random beautiful background. `can be disabled or source changed`.
|
||||
* Can handle live streams.
|
||||
* Scheduler to queue channels or playlists to be downloaded automatically at a specified time.
|
||||
* Send notification to targets based on selected events.
|
||||
* Send notification to targets based on selected events. includes [Apprise](https://github.com/caronc/apprise?tab=readme-ov-file#readme) support for non http/https URLs.
|
||||
* Support per link `cli options` & `cookies`.
|
||||
* Queue multiple URLs separated by comma.
|
||||
* Presets system to re-use frequently used yt-dlp options.
|
||||
|
|
@ -31,13 +31,7 @@ live streams, and includes features like scheduling downloads, sending notificat
|
|||
* Automatic upcoming live stream re-queue.
|
||||
* Apply `yt-dlp` options per custom defined conditions.
|
||||
* Custom browser extensions, bookmarklets and iOS shortcuts to send links to YTPTube instance.
|
||||
|
||||
### Side project
|
||||
|
||||
We have a side project related to YTPTube, which takes YTPTube source code and build an executable for Windows, macOS and Linux.
|
||||
The project is in early stages, and might not even work yet. However keep an eye at [This build action](https://github.com/arabcoders/ytptube/actions/workflows/native-build.yml) for builds, simply select last successful build and download the executable for your platform. Help us test out the platforms
|
||||
and report any issues you might find. We only have windows/linux machines to test on, so we need your help to test it out on macOS.
|
||||
|
||||
* A executable for Windows, macOS and Linux, which can be found in the release page.
|
||||
|
||||
# Installation
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,15 @@ import logging
|
|||
import threading
|
||||
from queue import Empty, Queue
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from .Singleton import Singleton
|
||||
|
||||
LOG: logging.Logger = logging.getLogger(__name__)
|
||||
LOG: logging.Logger = logging.getLogger("BackgroundWorker")
|
||||
|
||||
|
||||
class CloseThread:
|
||||
pass
|
||||
|
||||
|
||||
class BackgroundWorker(metaclass=Singleton):
|
||||
|
|
@ -19,12 +25,30 @@ class BackgroundWorker(metaclass=Singleton):
|
|||
_instance = None
|
||||
"""The instance of the Notification class."""
|
||||
|
||||
thread: threading.Thread
|
||||
"""The thread that runs the background worker."""
|
||||
|
||||
def __init__(self):
|
||||
self.queue = Queue()
|
||||
self.running = True
|
||||
|
||||
def attach(self, app: web.Application):
|
||||
app.on_shutdown.append(self.on_shutdown)
|
||||
|
||||
LOG.debug("Starting background worker...")
|
||||
self.thread = threading.Thread(target=self._run, daemon=True)
|
||||
self.thread.start()
|
||||
|
||||
async def on_shutdown(self, _: web.Application):
|
||||
self.running = False
|
||||
try:
|
||||
LOG.debug("Shutting down background worker...")
|
||||
self.queue.put((CloseThread, (), {}))
|
||||
self.thread.join(timeout=5)
|
||||
LOG.debug("Background worker has been shut down.")
|
||||
except Exception as e:
|
||||
LOG.error(f"Failed to shut down background worker: {e}")
|
||||
|
||||
@staticmethod
|
||||
def get_instance() -> "BackgroundWorker":
|
||||
if BackgroundWorker._instance is None:
|
||||
|
|
@ -40,15 +64,20 @@ class BackgroundWorker(metaclass=Singleton):
|
|||
def _loop_runner():
|
||||
try:
|
||||
loop.run_forever()
|
||||
except Exception as e:
|
||||
LOG.exception("Loop error: %s", e)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
threading.Thread(target=_loop_runner, daemon=True, name="Background Runner").start()
|
||||
loop_thread = threading.Thread(target=_loop_runner, daemon=True, name="Background Runner")
|
||||
loop_thread.start()
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
fn, args, kwargs = self.queue.get(timeout=1)
|
||||
try:
|
||||
if isinstance(fn, CloseThread):
|
||||
LOG.info("Received shutdown signal for background worker.")
|
||||
break
|
||||
|
||||
result = fn(*args, **kwargs)
|
||||
if inspect.iscoroutine(result):
|
||||
loop.call_soon_threadsafe(loop.create_task, result)
|
||||
|
|
@ -58,9 +87,13 @@ class BackgroundWorker(metaclass=Singleton):
|
|||
except Empty:
|
||||
continue
|
||||
|
||||
try:
|
||||
loop.call_soon_threadsafe(loop.stop)
|
||||
loop_thread.join(timeout=5)
|
||||
loop.close()
|
||||
LOG.debug("Event loop has been stopped and closed.")
|
||||
except Exception as e:
|
||||
LOG.error(f"Failed to stop the event loop: {e!s}")
|
||||
|
||||
def submit(self, fn, *args, **kwargs):
|
||||
self.queue.put((fn, args, kwargs))
|
||||
|
||||
def shutdown(self):
|
||||
self.running = False
|
||||
self.thread.join()
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ LOG = logging.getLogger("datastore")
|
|||
class StoreType(str, Enum):
|
||||
DONE = "done"
|
||||
QUEUE = "queue"
|
||||
PENDING = "pending"
|
||||
|
||||
@classmethod
|
||||
def all(cls) -> list[str]:
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ class Download:
|
|||
self.proc.start()
|
||||
self.info.status = "preparing"
|
||||
|
||||
await self._notify.emit(Events.UPDATED, data=self.info)
|
||||
await self._notify.emit(Events.ITEM_UPDATED, data=self.info)
|
||||
asyncio.create_task(self.progress_update(), name=f"update-{self.id}")
|
||||
|
||||
return await asyncio.get_running_loop().run_in_executor(None, self.proc.join)
|
||||
|
|
@ -465,7 +465,7 @@ class Download:
|
|||
self.logger.debug(f"Status Update: {self.info._id=} {status=}")
|
||||
|
||||
if isinstance(status, str):
|
||||
await self._notify.emit(Events.UPDATED, data=self.info)
|
||||
await self._notify.emit(Events.ITEM_UPDATED, data=self.info)
|
||||
continue
|
||||
|
||||
self.tmpfilename = status.get("tmpfilename")
|
||||
|
|
@ -529,7 +529,7 @@ class Download:
|
|||
self.logger.exception(e)
|
||||
self.logger.error(f"Failed to run ffprobe. {status.get}. {e}")
|
||||
|
||||
await self._notify.emit(Events.UPDATED, data=self.info)
|
||||
await self._notify.emit(Events.ITEM_UPDATED, data=self.info)
|
||||
|
||||
def is_stale(self) -> bool:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -65,9 +65,6 @@ class DownloadQueue(metaclass=Singleton):
|
|||
done: DataStore
|
||||
"""DataStore for the completed downloads."""
|
||||
|
||||
pending: DataStore
|
||||
"""DataStore for the pending downloads."""
|
||||
|
||||
workers: asyncio.Semaphore
|
||||
"""Semaphore to limit the number of concurrent downloads."""
|
||||
|
||||
|
|
@ -179,7 +176,15 @@ class DownloadQueue(metaclass=Singleton):
|
|||
|
||||
item.info.auto_start = True
|
||||
updated = self.queue.put(item)
|
||||
tasks.append(self._notify.emit(Events.UPDATED, data=updated.info))
|
||||
tasks.append(self._notify.emit(Events.ITEM_UPDATED, data=updated.info))
|
||||
tasks.append(
|
||||
self._notify.emit(
|
||||
Events.ITEM_RESUMED,
|
||||
data=item.info,
|
||||
title="Download Resumed",
|
||||
message=f"Download '{item.info.title}' has been resumed.",
|
||||
)
|
||||
)
|
||||
status[item_id] = "started"
|
||||
started = True
|
||||
LOG.debug(f"Item {item.info.name()} marked as started.")
|
||||
|
|
@ -227,7 +232,15 @@ class DownloadQueue(metaclass=Singleton):
|
|||
|
||||
item.info.auto_start = False
|
||||
updated = self.queue.put(item)
|
||||
tasks.append(self._notify.emit(Events.UPDATED, data=updated.info))
|
||||
tasks.append(self._notify.emit(Events.ITEM_UPDATED, data=updated.info))
|
||||
tasks.append(
|
||||
self._notify.emit(
|
||||
Events.ITEM_PAUSED,
|
||||
data=item.info,
|
||||
title="Download Paused",
|
||||
message=f"Download '{item.info.title}' has been paused.",
|
||||
)
|
||||
)
|
||||
status[item_id] = "paused"
|
||||
LOG.debug(f"Item {item.info.name()} marked as paused.")
|
||||
|
||||
|
|
@ -450,60 +463,56 @@ class DownloadQueue(metaclass=Singleton):
|
|||
|
||||
try:
|
||||
dlInfo: Download = Download(info=dl, info_dict=entry if item.auto_start else None, logs=logs)
|
||||
notifyTitle: str | None = None
|
||||
notifyMessage: str | None = None
|
||||
nEvent: str | None = None
|
||||
nTitle: str | None = None
|
||||
nMessage: str | None = None
|
||||
nStore: str = "queue"
|
||||
|
||||
text_logs: str = ""
|
||||
if filtered_logs := extract_ytdlp_logs(logs):
|
||||
text_logs = f" Logs: {', '.join(filtered_logs)}"
|
||||
text_logs = ", ".join(filtered_logs)
|
||||
|
||||
if "is_upcoming" == entry.get("live_status"):
|
||||
notifyEvent = Events.COMPLETED
|
||||
notifyTitle = "Upcoming Premiere" if is_premiere else "Upcoming Live Stream"
|
||||
notifyMessage = f"{'Premiere video' if is_premiere else 'Stream' } '{dlInfo.info.title}' is not available yet. {text_logs}"
|
||||
nEvent = Events.ITEM_MOVED
|
||||
nStore = "history"
|
||||
nTitle = "Upcoming Premiere" if is_premiere else "Upcoming Live Stream"
|
||||
nMessage = f"{'Premiere video' if is_premiere else 'Stream' } '{dlInfo.info.title}' is not available yet. {text_logs}"
|
||||
|
||||
dlInfo.info.status = "not_live"
|
||||
dlInfo.info.msg = notifyMessage.replace(f" '{dlInfo.info.title}'", "")
|
||||
|
||||
await self._notify.emit(
|
||||
Events.LOG_INFO,
|
||||
data={"lowPriority": True},
|
||||
title=notifyTitle,
|
||||
message=notifyMessage,
|
||||
)
|
||||
dlInfo.info.msg = nMessage.replace(f" '{dlInfo.info.title}'", "")
|
||||
await self._notify.emit(Events.LOG_INFO, data={"lowPriority": True}, title=nTitle, message=nMessage)
|
||||
|
||||
itemDownload: Download = self.done.put(dlInfo)
|
||||
elif len(entry.get("formats", [])) < 1:
|
||||
ava: str = entry.get("availability", "public")
|
||||
notifyTitle = "Download Error"
|
||||
notifyMessage: str = f"No formats for '{dl.title}'."
|
||||
if ava and ava not in ("public",):
|
||||
notifyMessage += f" Availability is set for '{ava}'."
|
||||
nTitle = "Download Error"
|
||||
nMessage: str = f"No formats for '{dl.title}'."
|
||||
nEvent = Events.ITEM_MOVED
|
||||
nStore = "history"
|
||||
|
||||
dlInfo.info.error = notifyMessage.replace(f" for '{dl.title}'.", ".") + text_logs
|
||||
if ava and ava not in ("public",):
|
||||
nMessage += f" Availability is set for '{ava}'."
|
||||
|
||||
dlInfo.info.error = nMessage.replace(f" for '{dl.title}'.", ".") + text_logs
|
||||
dlInfo.info.status = "error"
|
||||
itemDownload = self.done.put(dlInfo)
|
||||
notifyEvent = Events.COMPLETED
|
||||
await self._notify.emit(
|
||||
Events.LOG_WARNING,
|
||||
data={"logs": text_logs},
|
||||
title=notifyTitle,
|
||||
message=notifyMessage,
|
||||
)
|
||||
|
||||
await self._notify.emit(Events.LOG_WARNING, data={"logs": text_logs}, title=nTitle, message=nMessage)
|
||||
elif is_premiere and self.config.prevent_live_premiere:
|
||||
notifyTitle = "Premiere Video"
|
||||
nStore = "history"
|
||||
nTitle = "Premiere Video"
|
||||
dlInfo.info.error = "Premiering right now."
|
||||
|
||||
_requeue = True
|
||||
if release_in:
|
||||
try:
|
||||
starts_in = str_to_dt(release_in)
|
||||
starts_in = (
|
||||
starts_in: datetime = str_to_dt(release_in)
|
||||
starts_in: datetime = (
|
||||
starts_in.replace(tzinfo=UTC) if starts_in.tzinfo is None else starts_in.astimezone(UTC)
|
||||
)
|
||||
starts_in = starts_in + timedelta(minutes=5, seconds=dl.extras.get("duration", 0))
|
||||
dlInfo.info.error += f" Download will start at {starts_in.astimezone().isoformat()}."
|
||||
notifyMessage = dlInfo.info.error.strip()
|
||||
nMessage = dlInfo.info.error.strip()
|
||||
_requeue = False
|
||||
except Exception as e:
|
||||
LOG.error(f"Failed to parse live_in date '{release_in}'. {e!s}")
|
||||
|
|
@ -511,24 +520,25 @@ class DownloadQueue(metaclass=Singleton):
|
|||
else:
|
||||
dlInfo.info.error += f" Delaying download by '{300+dl.extras.get('duration',0)}' seconds."
|
||||
|
||||
notifyMessage = dlInfo.info.error.strip()
|
||||
nMessage = dlInfo.info.error.strip()
|
||||
|
||||
if _requeue:
|
||||
notifyEvent = Events.ADDED
|
||||
nEvent = Events.ITEM_ADDED
|
||||
itemDownload = self.queue.put(dlInfo)
|
||||
if item.auto_start:
|
||||
self.event.set()
|
||||
else:
|
||||
dlInfo.info.status = "not_live"
|
||||
itemDownload = self.done.put(dlInfo)
|
||||
notifyEvent = Events.COMPLETED
|
||||
notifyTitle = "Item Not Live"
|
||||
notifyMessage = f"Item '{dlInfo.info.title}' is not live."
|
||||
await self._notify.emit(Events.LOG_INFO, title=notifyTitle, message=notifyMessage)
|
||||
nStore = "history"
|
||||
nEvent = Events.ITEM_MOVED
|
||||
nTitle = "Item Not Live"
|
||||
nMessage = f"Item '{dlInfo.info.title}' is not live."
|
||||
await self._notify.emit(Events.LOG_INFO, title=nTitle, message=nMessage)
|
||||
else:
|
||||
notifyEvent = Events.ADDED
|
||||
notifyTitle = "Item Added"
|
||||
notifyMessage = f"Item '{dlInfo.info.title}' has been added to the download queue."
|
||||
nEvent = Events.ITEM_ADDED
|
||||
nTitle = "Item Added"
|
||||
nMessage = f"Item '{dlInfo.info.title}' has been added to the download queue."
|
||||
itemDownload = self.queue.put(dlInfo)
|
||||
if item.auto_start:
|
||||
self.event.set()
|
||||
|
|
@ -536,10 +546,10 @@ class DownloadQueue(metaclass=Singleton):
|
|||
LOG.debug(f"Item {itemDownload.info.name()} is not set to auto-start.")
|
||||
|
||||
await self._notify.emit(
|
||||
notifyEvent,
|
||||
data=itemDownload.info.serialize(),
|
||||
title=notifyTitle,
|
||||
message=notifyMessage,
|
||||
nEvent,
|
||||
data={"to": nStore, "item": itemDownload.info} if Events.ITEM_MOVED == nEvent else itemDownload.info,
|
||||
title=nTitle,
|
||||
message=nMessage,
|
||||
)
|
||||
|
||||
return {"status": "ok"}
|
||||
|
|
@ -746,7 +756,7 @@ class DownloadQueue(metaclass=Singleton):
|
|||
LOG.debug(f"Deleting from queue {item_ref}")
|
||||
self.queue.delete(id)
|
||||
await self._notify.emit(
|
||||
Events.CANCELLED,
|
||||
Events.ITEM_CANCELLED,
|
||||
data=item.info,
|
||||
title="Download Cancelled",
|
||||
message=f"Download '{item.info.title}' has been cancelled.",
|
||||
|
|
@ -754,8 +764,8 @@ class DownloadQueue(metaclass=Singleton):
|
|||
item.info.status = "cancelled"
|
||||
self.done.put(item)
|
||||
await self._notify.emit(
|
||||
Events.COMPLETED,
|
||||
data=item.info,
|
||||
Events.ITEM_MOVED,
|
||||
data={"to": "history", "item": item.info},
|
||||
title="Download Cancelled",
|
||||
message=f"Download '{item.info.title}' has been cancelled.",
|
||||
)
|
||||
|
|
@ -829,7 +839,7 @@ class DownloadQueue(metaclass=Singleton):
|
|||
|
||||
_status: str = "Removed" if removed_files > 0 else "Cleared"
|
||||
await self._notify.emit(
|
||||
Events.CLEARED,
|
||||
Events.ITEM_DELETED,
|
||||
data=item.info,
|
||||
title=f"Download {_status}",
|
||||
message=f"{_status} '{item.info.title}' from history.",
|
||||
|
|
@ -946,7 +956,7 @@ class DownloadQueue(metaclass=Singleton):
|
|||
None
|
||||
|
||||
"""
|
||||
filePath = calc_download_path(base_path=self.config.download_path, folder=entry.info.folder)
|
||||
filePath: str = calc_download_path(base_path=self.config.download_path, folder=entry.info.folder)
|
||||
LOG.info(f"Downloading 'id: {id}', 'Title: {entry.info.title}', 'URL: {entry.info.url}' To '{filePath}'.")
|
||||
|
||||
try:
|
||||
|
|
@ -962,28 +972,35 @@ class DownloadQueue(metaclass=Singleton):
|
|||
await entry.close()
|
||||
|
||||
if self.queue.exists(key=id):
|
||||
_tasks = []
|
||||
LOG.debug(f"Download Task '{id}' is completed. Removing from queue.")
|
||||
self.queue.delete(key=id)
|
||||
|
||||
notifyTitle: str | None = None
|
||||
notifyMessage: str | None = None
|
||||
nTitle: str | None = None
|
||||
nMessage: str | None = None
|
||||
|
||||
if entry.is_cancelled() is True:
|
||||
await self._notify.emit(
|
||||
Events.CANCELLED,
|
||||
data=entry.info,
|
||||
title="Download Cancelled",
|
||||
message=f"Download '{entry.info.title}' has been cancelled.",
|
||||
)
|
||||
nTitle = "Download Cancelled"
|
||||
nMessage = f"Download '{entry.info.title}' has been cancelled."
|
||||
await self._notify.emit(Events.ITEM_CANCELLED, data=entry.info, title=nTitle, message=nMessage)
|
||||
entry.info.status = "cancelled"
|
||||
notifyTitle = "Download Cancelled"
|
||||
notifyMessage = f"Download '{entry.info.title}' has been cancelled."
|
||||
elif entry.info.status == "finished":
|
||||
notifyTitle = "Download Completed"
|
||||
notifyMessage = f"Download '{entry.info.title}' has been completed."
|
||||
|
||||
if entry.info.status == "finished" and entry.info.filename:
|
||||
nTitle = "Download Completed"
|
||||
nMessage = f"Download '{entry.info.title}' has been finished."
|
||||
_tasks.append(self._notify.emit(Events.ITEM_COMPLETED, data=entry.info, title=nTitle, message=nMessage))
|
||||
|
||||
self.done.put(value=entry)
|
||||
await self._notify.emit(Events.COMPLETED, data=entry.info, title=notifyTitle, message=notifyMessage)
|
||||
_tasks.append(
|
||||
self._notify.emit(
|
||||
Events.ITEM_MOVED,
|
||||
data={"to": "history", "item": entry.info},
|
||||
title=nTitle,
|
||||
message=nMessage,
|
||||
)
|
||||
)
|
||||
|
||||
await asyncio.gather(*_tasks)
|
||||
else:
|
||||
LOG.warning(f"Download '{id}' not found in queue.")
|
||||
|
||||
|
|
|
|||
|
|
@ -17,53 +17,54 @@ class Events:
|
|||
The events that can be emitted.
|
||||
"""
|
||||
|
||||
STARTUP = "startup"
|
||||
LOADED = "loaded"
|
||||
STARTED = "started"
|
||||
SHUTDOWN = "shutdown"
|
||||
STARTUP: str = "startup"
|
||||
LOADED: str = "loaded"
|
||||
STARTED: str = "started"
|
||||
SHUTDOWN: str = "shutdown"
|
||||
|
||||
ADDED = "added"
|
||||
UPDATE = "update"
|
||||
UPDATED = "updated"
|
||||
COMPLETED = "completed"
|
||||
CANCELLED = "cancelled"
|
||||
CLEARED = "cleared"
|
||||
CONNECTED = "connected"
|
||||
STATUS = "status"
|
||||
CONNECTED: str = "connected"
|
||||
|
||||
LOG_INFO = "log_info"
|
||||
LOG_WARNING = "log_warning"
|
||||
LOG_ERROR = "log_error"
|
||||
LOG_SUCCESS = "log_success"
|
||||
LOG_INFO: str = "log_info"
|
||||
LOG_WARNING: str = "log_warning"
|
||||
LOG_ERROR: str = "log_error"
|
||||
LOG_SUCCESS: str = "log_success"
|
||||
|
||||
ITEM_DELETE = "item_delete"
|
||||
ITEM_CANCEL = "item_cancel"
|
||||
ITEM_ERROR = "item_error"
|
||||
ITEM_ADDED: str = "item_added"
|
||||
ITEM_UPDATED: str = "item_updated"
|
||||
ITEM_COMPLETED: str = "item_completed"
|
||||
ITEM_CANCELLED: str = "item_cancelled"
|
||||
ITEM_DELETED: str = "item_deleted"
|
||||
ITEM_PAUSED: str = "item_paused"
|
||||
ITEM_RESUMED: str = "item_resumed"
|
||||
ITEM_MOVED: str = "item_moved"
|
||||
ITEM_STATUS: str = "item_status"
|
||||
ITEM_ERROR: str = "item_error"
|
||||
|
||||
TEST = "test"
|
||||
ADD_URL = "add_url"
|
||||
TEST: str = "test"
|
||||
ADD_URL: str = "add_url"
|
||||
|
||||
PAUSED = "paused"
|
||||
PAUSED: str = "paused"
|
||||
RESUMED: str = "resumed"
|
||||
|
||||
CLI_POST = "cli_post"
|
||||
CLI_CLOSE = "cli_close"
|
||||
CLI_OUTPUT = "cli_output"
|
||||
CLI_POST: str = "cli_post"
|
||||
CLI_CLOSE: str = "cli_close"
|
||||
CLI_OUTPUT: str = "cli_output"
|
||||
|
||||
TASKS_ADD = "task_add"
|
||||
TASK_DISPATCHED = "task_dispatched"
|
||||
TASK_FINISHED = "task_finished"
|
||||
TASK_ERROR = "task_error"
|
||||
TASKS_ADD: str = "task_add"
|
||||
TASK_DISPATCHED: str = "task_dispatched"
|
||||
TASK_FINISHED: str = "task_finished"
|
||||
TASK_ERROR: str = "task_error"
|
||||
|
||||
PRESETS_ADD = "presets_add"
|
||||
PRESETS_UPDATE = "presets_update"
|
||||
PRESETS_ADD: str = "presets_add"
|
||||
PRESETS_UPDATE: str = "presets_update"
|
||||
|
||||
SCHEDULE_ADD = "schedule_add"
|
||||
SCHEDULE_ADD: str = "schedule_add"
|
||||
|
||||
CONDITIONS_ADD = "conditions_add"
|
||||
CONDITIONS_UPDATE = "conditions_update"
|
||||
CONDITIONS_ADD: str = "conditions_add"
|
||||
CONDITIONS_UPDATE: str = "conditions_update"
|
||||
|
||||
SUBSCRIBED = "subscribed"
|
||||
UNSUBSCRIBED = "unsubscribed"
|
||||
SUBSCRIBED: str = "subscribed"
|
||||
UNSUBSCRIBED: str = "unsubscribed"
|
||||
|
||||
def get_all() -> list:
|
||||
"""
|
||||
|
|
@ -87,21 +88,22 @@ class Events:
|
|||
"""
|
||||
return [
|
||||
Events.CONNECTED,
|
||||
Events.ADDED,
|
||||
Events.LOG_INFO,
|
||||
Events.LOG_WARNING,
|
||||
Events.LOG_ERROR,
|
||||
Events.LOG_SUCCESS,
|
||||
Events.COMPLETED,
|
||||
Events.CANCELLED,
|
||||
Events.CLEARED,
|
||||
Events.UPDATED,
|
||||
Events.UPDATE,
|
||||
Events.ITEM_ADDED,
|
||||
Events.ITEM_UPDATED,
|
||||
Events.ITEM_COMPLETED,
|
||||
Events.ITEM_CANCELLED,
|
||||
Events.ITEM_DELETED,
|
||||
Events.ITEM_MOVED,
|
||||
Events.ITEM_STATUS,
|
||||
Events.PAUSED,
|
||||
Events.PRESETS_UPDATE,
|
||||
Events.STATUS,
|
||||
Events.RESUMED,
|
||||
Events.CLI_CLOSE,
|
||||
Events.CLI_OUTPUT,
|
||||
Events.PRESETS_UPDATE,
|
||||
]
|
||||
|
||||
def only_debug() -> list:
|
||||
|
|
@ -112,7 +114,7 @@ class Events:
|
|||
list: The list of debug events.
|
||||
|
||||
"""
|
||||
return [Events.UPDATED, Events.CLI_OUTPUT]
|
||||
return [Events.ITEM_UPDATED, Events.CLI_OUTPUT]
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
|
|
|
|||
|
|
@ -90,15 +90,25 @@ class Target:
|
|||
|
||||
|
||||
class NotificationEvents:
|
||||
ADDED = Events.ADDED
|
||||
COMPLETED = Events.COMPLETED
|
||||
CANCELLED = Events.CANCELLED
|
||||
CLEARED = Events.CLEARED
|
||||
LOG_INFO = Events.LOG_INFO
|
||||
LOG_SUCCESS = Events.LOG_SUCCESS
|
||||
LOG_WARNING = Events.LOG_WARNING
|
||||
LOG_ERROR = Events.LOG_ERROR
|
||||
TEST = Events.TEST
|
||||
TEST: str = Events.TEST
|
||||
|
||||
ITEM_ADDED: str = Events.ITEM_ADDED
|
||||
ITEM_COMPLETED: str = Events.ITEM_COMPLETED
|
||||
ITEM_CANCELLED: str = Events.ITEM_CANCELLED
|
||||
ITEM_DELETED: str = Events.ITEM_DELETED
|
||||
ITEM_PAUSED: str = Events.ITEM_PAUSED
|
||||
ITEM_RESUMED: str = Events.ITEM_RESUMED
|
||||
ITEM_MOVED: str = Events.ITEM_MOVED
|
||||
|
||||
PAUSED: str = Events.PAUSED
|
||||
RESUMED: str = Events.RESUMED
|
||||
|
||||
LOG_INFO: str = Events.LOG_INFO
|
||||
LOG_SUCCESS: str = Events.LOG_SUCCESS
|
||||
LOG_WARNING: str = Events.LOG_WARNING
|
||||
LOG_ERROR: str = Events.LOG_ERROR
|
||||
|
||||
TASK_DISPATCHED: str = Events.TASK_DISPATCHED
|
||||
|
||||
@staticmethod
|
||||
def get_events() -> dict[str, str]:
|
||||
|
|
|
|||
|
|
@ -11,12 +11,13 @@ from typing import Any
|
|||
|
||||
from aiohttp import web
|
||||
|
||||
from app.library.Services import Services
|
||||
|
||||
from .config import Config
|
||||
from .DownloadQueue import DownloadQueue
|
||||
from .encoder import Encoder
|
||||
from .Events import EventBus, Events
|
||||
from .ItemDTO import Item
|
||||
from .Scheduler import Scheduler
|
||||
from .Services import Services
|
||||
from .Singleton import Singleton
|
||||
from .Utils import init_class, validate_url
|
||||
|
||||
|
|
@ -76,6 +77,7 @@ class Tasks(metaclass=Singleton):
|
|||
self._scheduler: Scheduler = scheduler or Scheduler.get_instance()
|
||||
self._notify: EventBus = EventBus.get_instance()
|
||||
self._task_handler = HandleTask(self._scheduler, self, config)
|
||||
self._downloadQueue = DownloadQueue.get_instance()
|
||||
|
||||
if self._file.exists() and "600" != self._file.stat().st_mode:
|
||||
try:
|
||||
|
|
@ -316,31 +318,38 @@ class Tasks(metaclass=Singleton):
|
|||
template: str = task.template if task.template else ""
|
||||
cli: str = task.cli if task.cli else ""
|
||||
|
||||
await self._notify.emit(
|
||||
Events.ADD_URL,
|
||||
data={
|
||||
"url": task.url,
|
||||
"preset": preset,
|
||||
"folder": folder,
|
||||
"template": template,
|
||||
"cli": cli,
|
||||
},
|
||||
title="Tasks",
|
||||
message=f"Task '{task.name}' started at '{timeNow}'",
|
||||
id=task.id,
|
||||
status = await self._downloadQueue.add(
|
||||
item=Item.format(
|
||||
{
|
||||
"url": task.url,
|
||||
"preset": preset,
|
||||
"folder": folder,
|
||||
"template": template,
|
||||
"cli": cli,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
timeNow = datetime.now(UTC).isoformat()
|
||||
|
||||
ended: float = time.time()
|
||||
LOG.info(f"Task '{task.name}' completed at '{timeNow}' took '{ended - started:.2f}' seconds.")
|
||||
|
||||
await self._notify.emit(
|
||||
Events.LOG_SUCCESS,
|
||||
data={"lowPriority": True},
|
||||
title="Task completed",
|
||||
message=f"Task '{task.name}' completed in '{ended - started:.2f}'.",
|
||||
)
|
||||
_tasks = [
|
||||
self._notify.emit(
|
||||
Events.TASK_DISPATCHED,
|
||||
data=status,
|
||||
title=f"Task '{task.name}' dispatched",
|
||||
message=f"Task '{task.name}' dispatched at '{timeNow}'.",
|
||||
),
|
||||
self._notify.emit(
|
||||
Events.LOG_SUCCESS,
|
||||
data={"lowPriority": True},
|
||||
title="Task completed",
|
||||
message=f"Task '{task.name}' completed in '{ended - started:.2f}'.",
|
||||
),
|
||||
]
|
||||
|
||||
await asyncio.gather(*_tasks)
|
||||
except Exception as e:
|
||||
LOG.error(f"Failed to execute '{task.name}' at '{timeNow}'. '{e!s}'.")
|
||||
await self._notify.emit(
|
||||
|
|
|
|||
|
|
@ -1188,6 +1188,8 @@ def extract_ytdlp_logs(logs: list[str], filters: list[str | re.Pattern] = None)
|
|||
"This video is available to this channel",
|
||||
"Private video. Sign in if you've been granted access to this video",
|
||||
"[youtube] Premieres in",
|
||||
"Falling back on generic information extractor",
|
||||
"URL could be a direct video link, returning it as such",
|
||||
] + (filters or [])
|
||||
|
||||
compiled: list[re.Pattern] = [
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
|
|||
from app.library.config import Config
|
||||
from app.library.DownloadQueue import DownloadQueue
|
||||
from app.library.Events import EventBus, Events
|
||||
from app.library.ItemDTO import ItemDTO
|
||||
from app.library.ItemDTO import Item, ItemDTO
|
||||
from app.library.Tasks import Task
|
||||
from app.library.Utils import is_downloaded
|
||||
from app.library.YTDLPOpts import YTDLPOpts
|
||||
|
|
@ -147,18 +147,18 @@ class YoutubeHandler:
|
|||
template: str = task.template if task.template else ""
|
||||
cli: str = task.cli if task.cli else ""
|
||||
|
||||
queued = asyncio.gather(
|
||||
*[
|
||||
notify.emit(
|
||||
Events.ADD_URL,
|
||||
data={"url": item["url"], "preset": preset, "folder": folder, "template": template, "cli": cli},
|
||||
)
|
||||
for item in filtered
|
||||
]
|
||||
)
|
||||
|
||||
try:
|
||||
await queued
|
||||
await asyncio.gather(
|
||||
*[
|
||||
notify.emit(
|
||||
Events.ADD_URL,
|
||||
data=Item.format(
|
||||
{"url": item["url"], "preset": preset, "folder": folder, "template": template, "cli": cli}
|
||||
).serialize(),
|
||||
)
|
||||
for item in filtered
|
||||
]
|
||||
)
|
||||
except Exception as e:
|
||||
LOG.error(f"Error while adding items from '{task.id}: {task.name}'. {e!s}")
|
||||
return
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ class Main:
|
|||
Presets.get_instance().attach(self._app)
|
||||
Notification.get_instance().attach(self._app)
|
||||
Conditions.get_instance().attach(self._app)
|
||||
self._background_worker.attach(self._app)
|
||||
|
||||
EventBus.get_instance().sync_emit(
|
||||
Events.LOADED,
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ async def item_update(request: Request, queue: DownloadQueue, encoder: Encoder,
|
|||
|
||||
if updated:
|
||||
queue.done.put(item)
|
||||
await notify.emit(Events.UPDATE, data=item.info)
|
||||
await notify.emit(Events.ITEM_UPDATED, data=item.info)
|
||||
|
||||
return web.json_response(
|
||||
data=item.info,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ async def pause(notify: EventBus, queue: DownloadQueue):
|
|||
Events.PAUSED,
|
||||
data={"paused": True, "at": time.time()},
|
||||
title="Downloads Paused",
|
||||
message="Download pool has been paused.",
|
||||
message="Non-active downloads have been paused.",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -31,10 +31,10 @@ async def pause(notify: EventBus, queue: DownloadQueue):
|
|||
async def resume(notify: EventBus, queue: DownloadQueue):
|
||||
queue.resume()
|
||||
await notify.emit(
|
||||
Events.PAUSED,
|
||||
Events.RESUMED,
|
||||
data={"paused": False, "at": time.time()},
|
||||
title="Downloads Resumed",
|
||||
message="Download pool has been resumed.",
|
||||
message="Resumed all downloads.",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ async def add_url(queue: DownloadQueue, notify: EventBus, sid: str, data: dict):
|
|||
try:
|
||||
status = await queue.add(item=Item.format(data))
|
||||
await notify.emit(
|
||||
event=Events.STATUS,
|
||||
event=Events.ITEM_STATUS,
|
||||
title="Adding URL",
|
||||
message=f"Adding URL '{url}' to the download queue.",
|
||||
data=status,
|
||||
|
|
@ -76,12 +76,26 @@ async def item_cancel(queue: DownloadQueue, notify: EventBus, sid: str, data: st
|
|||
)
|
||||
return
|
||||
|
||||
try:
|
||||
item = queue.get_item(id=data)
|
||||
except KeyError:
|
||||
await notify.emit(
|
||||
Events.LOG_ERROR,
|
||||
title="Item Not Found",
|
||||
message=f"Item with ID '{data}' not found.",
|
||||
to=sid,
|
||||
)
|
||||
return
|
||||
|
||||
status: dict[str, str] = {}
|
||||
status = await queue.cancel([data])
|
||||
status.update({"identifier": data})
|
||||
|
||||
await notify.emit(
|
||||
Events.ITEM_CANCEL, data=status, title="Item Cancelled", message=f"Item '{data}': has been cancelled."
|
||||
Events.ITEM_CANCELLED,
|
||||
data=item.info,
|
||||
title="Item Cancelled",
|
||||
message=f"Cancelled '{item.info.title}'.",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -106,23 +120,7 @@ async def item_delete(queue: DownloadQueue, notify: EventBus, sid: str, data: di
|
|||
)
|
||||
return
|
||||
|
||||
item = queue.get_item(id=id)
|
||||
if not item:
|
||||
await notify.emit(
|
||||
Events.LOG_ERROR,
|
||||
title="Item Not Found",
|
||||
message=f"Item with ID '{id}' not found.",
|
||||
to=sid,
|
||||
)
|
||||
return
|
||||
|
||||
status: dict[str, str] = {}
|
||||
status = await queue.clear([id], remove_file=bool(data.get("remove_file", False)))
|
||||
status.update({"identifier": id})
|
||||
|
||||
await notify.emit(
|
||||
Events.ITEM_DELETE, data=status, title="Item Deleted", message=f"Item '{item.info.title}': has been deleted."
|
||||
)
|
||||
await queue.clear([id], remove_file=bool(data.get("remove_file", False)))
|
||||
|
||||
|
||||
@route(RouteType.SOCKET, "archive_item", "archive_item")
|
||||
|
|
|
|||
|
|
@ -4,25 +4,25 @@
|
|||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"dev": "nuxt dev --host",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"web-types": "./web-types.json",
|
||||
"dependencies": {
|
||||
"@pinia/nuxt": "^0.11.1",
|
||||
"@sentry/nuxt": "^9.35.0",
|
||||
"@pinia/nuxt": "^0.11.2",
|
||||
"@sentry/nuxt": "^9.40.0",
|
||||
"@vueuse/core": "^13.5.0",
|
||||
"@vueuse/nuxt": "^13.5.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"cron-parser": "^5.3.0",
|
||||
"cronstrue": "^3.0.0",
|
||||
"cronstrue": "^3.1.0",
|
||||
"floating-vue": "^5.2.2",
|
||||
"hls.js": "^1.6.7",
|
||||
"moment": "^2.30.1",
|
||||
"nuxt": "^3.17.6",
|
||||
"nuxt": "^4.0.0",
|
||||
"pinia": "^3.0.3",
|
||||
"socket.io-client": "^4.8.1",
|
||||
"vue": "^3.5.17",
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ watch(() => config.app.basic_mode, async () => {
|
|||
return
|
||||
}
|
||||
await navigateTo('/')
|
||||
}, { immediate: true })
|
||||
})
|
||||
|
||||
watch(() => config.app.console_enabled, async () => {
|
||||
if (config.app.console_enabled) {
|
||||
|
|
@ -97,7 +97,7 @@ watch(() => config.app.console_enabled, async () => {
|
|||
}
|
||||
toast.error('Console is disabled in the configuration. Please enable it to use this feature.')
|
||||
await navigateTo('/')
|
||||
}, { immediate: true })
|
||||
})
|
||||
|
||||
const handle_event = () => {
|
||||
if (!terminal.value) {
|
||||
|
|
@ -111,6 +111,12 @@ const runCommand = async () => {
|
|||
return
|
||||
}
|
||||
|
||||
if (config.app.basic_mode || !config.app.console_enabled) {
|
||||
await navigateTo('/')
|
||||
toast.error('Console is disabled in the configuration. Please enable it to use this feature.')
|
||||
return
|
||||
}
|
||||
|
||||
if (command.value.startsWith('yt-dlp')) {
|
||||
command.value = command.value.replace(/^yt-dlp/, '').trim()
|
||||
await nextTick()
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ watch(() => config.app.basic_mode, async () => {
|
|||
|
||||
watch(() => socket.isConnected, async () => {
|
||||
if (socket.isConnected && initialLoad.value) {
|
||||
socket.on('status', statusHandler)
|
||||
socket.on('item_status', statusHandler)
|
||||
await reloadContent(true)
|
||||
initialLoad.value = false
|
||||
}
|
||||
|
|
@ -586,7 +586,7 @@ onMounted(async () => {
|
|||
if (!socket.isConnected) {
|
||||
return;
|
||||
}
|
||||
socket.on('status', statusHandler)
|
||||
socket.on('item_status', statusHandler)
|
||||
await reloadContent(true)
|
||||
});
|
||||
|
||||
|
|
@ -683,7 +683,7 @@ const runNow = async (item: task_item, mass: boolean = false) => {
|
|||
}, 500)
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => socket.off('status', statusHandler))
|
||||
onBeforeUnmount(() => socket.off('item_status', statusHandler))
|
||||
|
||||
const statusHandler = async (stream: string) => {
|
||||
const json = JSON.parse(stream)
|
||||
|
|
|
|||
2037
ui/pnpm-lock.yaml
2037
ui/pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -12,6 +12,21 @@ export const useSocketStore = defineStore('socket', () => {
|
|||
const socket = ref<IOSocket | null>(null)
|
||||
const isConnected = ref<boolean>(false)
|
||||
|
||||
const emit = (event: string, data?: any): any => socket.value?.emit(event, data)
|
||||
const on = (event: string | string[], callback: (...args: any[]) => void, withEvent: boolean = false) => {
|
||||
if (!Array.isArray(event)) {
|
||||
event = [event]
|
||||
}
|
||||
event.forEach(e => socket.value?.on(e, (...args) => true === withEvent ? callback(e, ...args) : callback(...args)))
|
||||
}
|
||||
|
||||
const off = (event: string | string[], callback: (...args: any[]) => void): any => {
|
||||
if (!Array.isArray(event)) {
|
||||
event = [event]
|
||||
}
|
||||
event.forEach(e => socket.value?.off(e, callback));
|
||||
}
|
||||
|
||||
const connect = () => {
|
||||
let opts = {
|
||||
transports: ['websocket', 'polling'],
|
||||
|
|
@ -23,6 +38,8 @@ export const useSocketStore = defineStore('socket', () => {
|
|||
if ('development' !== runtimeConfig.public?.APP_ENV) {
|
||||
url = window.origin;
|
||||
opts.path = `${runtimeConfig.app.baseURL.replace(/\/$/, '')}/socket.io`;
|
||||
} else {
|
||||
window.ws = socket.value;
|
||||
}
|
||||
|
||||
socket.value = io(url, opts)
|
||||
|
|
@ -45,13 +62,13 @@ export const useSocketStore = defineStore('socket', () => {
|
|||
stateStore.addAll('history', json.data.done || {})
|
||||
})
|
||||
|
||||
socket.value.on('added', stream => {
|
||||
on('item_added', stream => {
|
||||
const json = JSON.parse(stream);
|
||||
stateStore.add('queue', json.data._id, json.data);
|
||||
toast.success(`Item queued: ${ag(stateStore.get('queue', json.data._id, {}), 'title')}`);
|
||||
});
|
||||
|
||||
['log_info', 'log_success', 'log_warning', 'log_error'].forEach(event => socket.value?.on(event, stream => {
|
||||
on(['log_info', 'log_success', 'log_warning', 'log_error'], (event: string, stream: string) => {
|
||||
const json = JSON.parse(stream);
|
||||
const message = json?.message || json?.data?.message;
|
||||
const data = json.data?.data || json.data || {};
|
||||
|
|
@ -69,19 +86,24 @@ export const useSocketStore = defineStore('socket', () => {
|
|||
toast.error(message, data);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
}, true);
|
||||
|
||||
socket.value.on('completed', stream => {
|
||||
on('item_completed', (stream: string) => {
|
||||
const json = JSON.parse(stream);
|
||||
|
||||
if (true === stateStore.has('queue', json.data._id)) {
|
||||
stateStore.remove('queue', json.data._id);
|
||||
}
|
||||
|
||||
if (true === stateStore.has('history', json.data._id)) {
|
||||
stateStore.update('history', json.data._id, json.data);
|
||||
return;
|
||||
}
|
||||
|
||||
stateStore.add('history', json.data._id, json.data);
|
||||
});
|
||||
|
||||
socket.value.on('cancelled', stream => {
|
||||
on('item_cancelled', (stream: string) => {
|
||||
const item = JSON.parse(stream);
|
||||
const id = item.data._id
|
||||
|
||||
|
|
@ -96,7 +118,7 @@ export const useSocketStore = defineStore('socket', () => {
|
|||
}
|
||||
});
|
||||
|
||||
socket.value.on('cleared', stream => {
|
||||
on('item_deleted', (stream: string) => {
|
||||
const item = JSON.parse(stream);
|
||||
const id = item.data._id
|
||||
|
||||
|
|
@ -107,7 +129,7 @@ export const useSocketStore = defineStore('socket', () => {
|
|||
stateStore.remove('history', id);
|
||||
});
|
||||
|
||||
socket.value.on("updated", stream => {
|
||||
on('item_updated', (stream: string) => {
|
||||
const json = JSON.parse(stream);
|
||||
const id = json.data._id;
|
||||
|
||||
|
|
@ -116,42 +138,51 @@ export const useSocketStore = defineStore('socket', () => {
|
|||
return;
|
||||
}
|
||||
|
||||
stateStore.update('queue', id, json.data);
|
||||
});
|
||||
|
||||
socket.value.on("update", stream => {
|
||||
const json = JSON.parse(stream);
|
||||
if (true === stateStore.has('history', json.data._id)) {
|
||||
stateStore.update('history', json.data._id, json.data);
|
||||
return;
|
||||
if (true === stateStore.has('queue', id)) {
|
||||
stateStore.update('queue', id, json.data);
|
||||
}
|
||||
});
|
||||
|
||||
socket.value.on('paused', data => {
|
||||
on('item_moved', (stream: string) => {
|
||||
const json = JSON.parse(stream);
|
||||
const to = json.data.to;
|
||||
const id = json.data.item._id;
|
||||
|
||||
if ('queue' === to) {
|
||||
if (true === stateStore.has('history', id)) {
|
||||
stateStore.remove('history', id);
|
||||
}
|
||||
stateStore.add('queue', id, json.data.item);
|
||||
}
|
||||
|
||||
if ('history' === to) {
|
||||
if (true === stateStore.has('queue', id)) {
|
||||
stateStore.remove('queue', id);
|
||||
}
|
||||
stateStore.add('history', id, json.data.item);
|
||||
}
|
||||
});
|
||||
|
||||
on(['paused', 'resumed'], (event: string, data: string) => {
|
||||
const json = JSON.parse(data);
|
||||
const pausedState = Boolean(json.data.paused);
|
||||
config.update('paused', pausedState);
|
||||
|
||||
if (false === pausedState) {
|
||||
if ('resumed' === event) {
|
||||
toast.success('Download queue resumed.');
|
||||
return;
|
||||
}
|
||||
|
||||
toast.warning('Download queue paused.', { timeout: 10000 });
|
||||
});
|
||||
}, true);
|
||||
|
||||
socket.value.on('presets_update', (data: string) => config.update('presets', JSON.parse(data).data || []));
|
||||
on('presets_update', (data: string) => config.update('presets', JSON.parse(data).data || []));
|
||||
}
|
||||
|
||||
const emit = (event: string, data?: any): any => socket.value?.emit(event, data)
|
||||
const on = (event: string, callback: (...args: any[]) => void): any => socket.value?.on(event, callback)
|
||||
const off = (event: string, callback: (...args: any[]) => void): any => socket.value?.off(event, callback)
|
||||
|
||||
if (false === isConnected.value) {
|
||||
connect();
|
||||
}
|
||||
|
||||
window.ws = socket.value;
|
||||
|
||||
return { connect, on, off, emit, socket, isConnected };
|
||||
});
|
||||
|
|
|
|||
148
uv.lock
148
uv.lock
|
|
@ -27,7 +27,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
version = "3.12.13"
|
||||
version = "3.12.14"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aiohappyeyeballs" },
|
||||
|
|
@ -38,59 +38,59 @@ dependencies = [
|
|||
{ name = "propcache" },
|
||||
{ name = "yarl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/42/6e/ab88e7cb2a4058bed2f7870276454f85a7c56cd6da79349eb314fc7bbcaa/aiohttp-3.12.13.tar.gz", hash = "sha256:47e2da578528264a12e4e3dd8dd72a7289e5f812758fe086473fab037a10fcce", size = 7819160 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e6/0b/e39ad954107ebf213a2325038a3e7a506be3d98e1435e1f82086eec4cde2/aiohttp-3.12.14.tar.gz", hash = "sha256:6e06e120e34d93100de448fd941522e11dafa78ef1a893c179901b7d66aa29f2", size = 7822921 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/65/5566b49553bf20ffed6041c665a5504fb047cefdef1b701407b8ce1a47c4/aiohttp-3.12.13-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7c229b1437aa2576b99384e4be668af1db84b31a45305d02f61f5497cfa6f60c", size = 709401 },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/b5/48e4cc61b54850bdfafa8fe0b641ab35ad53d8e5a65ab22b310e0902fa42/aiohttp-3.12.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04076d8c63471e51e3689c93940775dc3d12d855c0c80d18ac5a1c68f0904358", size = 481669 },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/4f/e3f95c8b2a20a0437d51d41d5ccc4a02970d8ad59352efb43ea2841bd08e/aiohttp-3.12.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55683615813ce3601640cfaa1041174dc956d28ba0511c8cbd75273eb0587014", size = 469933 },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/c9/c5269f3b6453b1cfbd2cfbb6a777d718c5f086a3727f576c51a468b03ae2/aiohttp-3.12.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:921bc91e602d7506d37643e77819cb0b840d4ebb5f8d6408423af3d3bf79a7b7", size = 1740128 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/49/a3f76caa62773d33d0cfaa842bdf5789a78749dbfe697df38ab1badff369/aiohttp-3.12.13-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e72d17fe0974ddeae8ed86db297e23dba39c7ac36d84acdbb53df2e18505a013", size = 1688796 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/e4/556fccc4576dc22bf18554b64cc873b1a3e5429a5bdb7bbef7f5d0bc7664/aiohttp-3.12.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0653d15587909a52e024a261943cf1c5bdc69acb71f411b0dd5966d065a51a47", size = 1787589 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/3d/d81b13ed48e1a46734f848e26d55a7391708421a80336e341d2aef3b6db2/aiohttp-3.12.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a77b48997c66722c65e157c06c74332cdf9c7ad00494b85ec43f324e5c5a9b9a", size = 1826635 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/a5/472e25f347da88459188cdaadd1f108f6292f8a25e62d226e63f860486d1/aiohttp-3.12.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6946bae55fd36cfb8e4092c921075cde029c71c7cb571d72f1079d1e4e013bc", size = 1729095 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/fe/322a78b9ac1725bfc59dfc301a5342e73d817592828e4445bd8f4ff83489/aiohttp-3.12.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f95db8c8b219bcf294a53742c7bda49b80ceb9d577c8e7aa075612b7f39ffb7", size = 1666170 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/77/ec80912270e231d5e3839dbd6c065472b9920a159ec8a1895cf868c2708e/aiohttp-3.12.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:03d5eb3cfb4949ab4c74822fb3326cd9655c2b9fe22e4257e2100d44215b2e2b", size = 1714444 },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/b2/fb5aedbcb2b58d4180e58500e7c23ff8593258c27c089abfbcc7db65bd40/aiohttp-3.12.13-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6383dd0ffa15515283c26cbf41ac8e6705aab54b4cbb77bdb8935a713a89bee9", size = 1709604 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/15/a94c05f7c4dc8904f80b6001ad6e07e035c58a8ebfcc15e6b5d58500c858/aiohttp-3.12.13-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6548a411bc8219b45ba2577716493aa63b12803d1e5dc70508c539d0db8dbf5a", size = 1689786 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/fd/0d2e618388f7a7a4441eed578b626bda9ec6b5361cd2954cfc5ab39aa170/aiohttp-3.12.13-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:81b0fcbfe59a4ca41dc8f635c2a4a71e63f75168cc91026c61be665945739e2d", size = 1783389 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/6b/6986d0c75996ef7e64ff7619b9b7449b1d1cbbe05c6755e65d92f1784fe9/aiohttp-3.12.13-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a83797a0174e7995e5edce9dcecc517c642eb43bc3cba296d4512edf346eee2", size = 1803853 },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/65/cd37b38f6655d95dd07d496b6d2f3924f579c43fd64b0e32b547b9c24df5/aiohttp-3.12.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5734d8469a5633a4e9ffdf9983ff7cdb512524645c7a3d4bc8a3de45b935ac3", size = 1716909 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/20/2de7012427dc116714c38ca564467f6143aec3d5eca3768848d62aa43e62/aiohttp-3.12.13-cp311-cp311-win32.whl", hash = "sha256:fef8d50dfa482925bb6b4c208b40d8e9fa54cecba923dc65b825a72eed9a5dbd", size = 427036 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/b6/98518bcc615ef998a64bef371178b9afc98ee25895b4f476c428fade2220/aiohttp-3.12.13-cp311-cp311-win_amd64.whl", hash = "sha256:9a27da9c3b5ed9d04c36ad2df65b38a96a37e9cfba6f1381b842d05d98e6afe9", size = 451427 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/6a/ce40e329788013cd190b1d62bbabb2b6a9673ecb6d836298635b939562ef/aiohttp-3.12.13-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0aa580cf80558557285b49452151b9c69f2fa3ad94c5c9e76e684719a8791b73", size = 700491 },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/d9/7150d5cf9163e05081f1c5c64a0cdf3c32d2f56e2ac95db2a28fe90eca69/aiohttp-3.12.13-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b103a7e414b57e6939cc4dece8e282cfb22043efd0c7298044f6594cf83ab347", size = 475104 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/91/d42ba4aed039ce6e449b3e2db694328756c152a79804e64e3da5bc19dffc/aiohttp-3.12.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78f64e748e9e741d2eccff9597d09fb3cd962210e5b5716047cbb646dc8fe06f", size = 467948 },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/3b/06f0a632775946981d7c4e5a865cddb6e8dfdbaed2f56f9ade7bb4a1039b/aiohttp-3.12.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c955989bf4c696d2ededc6b0ccb85a73623ae6e112439398935362bacfaaf6", size = 1714742 },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/a6/2552eebad9ec5e3581a89256276009e6a974dc0793632796af144df8b740/aiohttp-3.12.13-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d640191016763fab76072c87d8854a19e8e65d7a6fcfcbf017926bdbbb30a7e5", size = 1697393 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/9f/bd08fdde114b3fec7a021381b537b21920cdd2aa29ad48c5dffd8ee314f1/aiohttp-3.12.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4dc507481266b410dede95dd9f26c8d6f5a14315372cc48a6e43eac652237d9b", size = 1752486 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/e1/affdea8723aec5bd0959171b5490dccd9a91fcc505c8c26c9f1dca73474d/aiohttp-3.12.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8a94daa873465d518db073bd95d75f14302e0208a08e8c942b2f3f1c07288a75", size = 1798643 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/9d/666d856cc3af3a62ae86393baa3074cc1d591a47d89dc3bf16f6eb2c8d32/aiohttp-3.12.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f52420cde4ce0bb9425a375d95577fe082cb5721ecb61da3049b55189e4e6", size = 1718082 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/ce/3c185293843d17be063dada45efd2712bb6bf6370b37104b4eda908ffdbd/aiohttp-3.12.13-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f7df1f620ec40f1a7fbcb99ea17d7326ea6996715e78f71a1c9a021e31b96b8", size = 1633884 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/5b/f3413f4b238113be35dfd6794e65029250d4b93caa0974ca572217745bdb/aiohttp-3.12.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3062d4ad53b36e17796dce1c0d6da0ad27a015c321e663657ba1cc7659cfc710", size = 1694943 },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/c8/0e56e8bf12081faca85d14a6929ad5c1263c146149cd66caa7bc12255b6d/aiohttp-3.12.13-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:8605e22d2a86b8e51ffb5253d9045ea73683d92d47c0b1438e11a359bdb94462", size = 1716398 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/f3/33192b4761f7f9b2f7f4281365d925d663629cfaea093a64b658b94fc8e1/aiohttp-3.12.13-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:54fbbe6beafc2820de71ece2198458a711e224e116efefa01b7969f3e2b3ddae", size = 1657051 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/0b/26ddd91ca8f84c48452431cb4c5dd9523b13bc0c9766bda468e072ac9e29/aiohttp-3.12.13-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:050bd277dfc3768b606fd4eae79dd58ceda67d8b0b3c565656a89ae34525d15e", size = 1736611 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/8d/e04569aae853302648e2c138a680a6a2f02e374c5b6711732b29f1e129cc/aiohttp-3.12.13-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2637a60910b58f50f22379b6797466c3aa6ae28a6ab6404e09175ce4955b4e6a", size = 1764586 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/98/c193c1d1198571d988454e4ed75adc21c55af247a9fda08236602921c8c8/aiohttp-3.12.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e986067357550d1aaa21cfe9897fa19e680110551518a5a7cf44e6c5638cb8b5", size = 1724197 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/9e/07bb8aa11eec762c6b1ff61575eeeb2657df11ab3d3abfa528d95f3e9337/aiohttp-3.12.13-cp312-cp312-win32.whl", hash = "sha256:ac941a80aeea2aaae2875c9500861a3ba356f9ff17b9cb2dbfb5cbf91baaf5bf", size = 421771 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/66/3ce877e56ec0813069cdc9607cd979575859c597b6fb9b4182c6d5f31886/aiohttp-3.12.13-cp312-cp312-win_amd64.whl", hash = "sha256:671f41e6146a749b6c81cb7fd07f5a8356d46febdaaaf07b0e774ff04830461e", size = 447869 },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/0f/db19abdf2d86aa1deec3c1e0e5ea46a587b97c07a16516b6438428b3a3f8/aiohttp-3.12.13-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d4a18e61f271127465bdb0e8ff36e8f02ac4a32a80d8927aa52371e93cd87938", size = 694910 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/81/0ab551e1b5d7f1339e2d6eb482456ccbe9025605b28eed2b1c0203aaaade/aiohttp-3.12.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:532542cb48691179455fab429cdb0d558b5e5290b033b87478f2aa6af5d20ace", size = 472566 },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/3f/6b7d336663337672d29b1f82d1f252ec1a040fe2d548f709d3f90fa2218a/aiohttp-3.12.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d7eea18b52f23c050ae9db5d01f3d264ab08f09e7356d6f68e3f3ac2de9dfabb", size = 464856 },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/7f/32ca0f170496aa2ab9b812630fac0c2372c531b797e1deb3deb4cea904bd/aiohttp-3.12.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad7c8e5c25f2a26842a7c239de3f7b6bfb92304593ef997c04ac49fb703ff4d7", size = 1703683 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/53/d5513624b33a811c0abea8461e30a732294112318276ce3dbf047dbd9d8b/aiohttp-3.12.13-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6af355b483e3fe9d7336d84539fef460120c2f6e50e06c658fe2907c69262d6b", size = 1684946 },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/72/4c237dd127827b0247dc138d3ebd49c2ded6114c6991bbe969058575f25f/aiohttp-3.12.13-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a95cf9f097498f35c88e3609f55bb47b28a5ef67f6888f4390b3d73e2bac6177", size = 1737017 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/67/8a7eb3afa01e9d0acc26e1ef847c1a9111f8b42b82955fcd9faeb84edeb4/aiohttp-3.12.13-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8ed8c38a1c584fe99a475a8f60eefc0b682ea413a84c6ce769bb19a7ff1c5ef", size = 1786390 },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/19/0377df97dd0176ad23cd8cad4fd4232cfeadcec6c1b7f036315305c98e3f/aiohttp-3.12.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0b9170d5d800126b5bc89d3053a2363406d6e327afb6afaeda2d19ee8bb103", size = 1708719 },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/97/ade1982a5c642b45f3622255173e40c3eed289c169f89d00eeac29a89906/aiohttp-3.12.13-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:372feeace612ef8eb41f05ae014a92121a512bd5067db8f25101dd88a8db11da", size = 1622424 },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/ab/00ad3eea004e1d07ccc406e44cfe2b8da5acb72f8c66aeeb11a096798868/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a946d3702f7965d81f7af7ea8fb03bb33fe53d311df48a46eeca17e9e0beed2d", size = 1675447 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/fe/74e5ce8b2ccaba445fe0087abc201bfd7259431d92ae608f684fcac5d143/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a0c4725fae86555bbb1d4082129e21de7264f4ab14baf735278c974785cd2041", size = 1707110 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/c4/39af17807f694f7a267bd8ab1fbacf16ad66740862192a6c8abac2bff813/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b28ea2f708234f0a5c44eb6c7d9eb63a148ce3252ba0140d050b091b6e842d1", size = 1649706 },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/e8/f5a0a5f44f19f171d8477059aa5f28a158d7d57fe1a46c553e231f698435/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d4f5becd2a5791829f79608c6f3dc745388162376f310eb9c142c985f9441cc1", size = 1725839 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/ac/81acc594c7f529ef4419d3866913f628cd4fa9cab17f7bf410a5c3c04c53/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:60f2ce6b944e97649051d5f5cc0f439360690b73909230e107fd45a359d3e911", size = 1759311 },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/0d/aabe636bd25c6ab7b18825e5a97d40024da75152bec39aa6ac8b7a677630/aiohttp-3.12.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:69fc1909857401b67bf599c793f2183fbc4804717388b0b888f27f9929aa41f3", size = 1708202 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/ab/561ef2d8a223261683fb95a6283ad0d36cb66c87503f3a7dde7afe208bb2/aiohttp-3.12.13-cp313-cp313-win32.whl", hash = "sha256:7d7e68787a2046b0e44ba5587aa723ce05d711e3a3665b6b7545328ac8e3c0dd", size = 420794 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/47/b11d0089875a23bff0abd3edb5516bcd454db3fefab8604f5e4b07bd6210/aiohttp-3.12.13-cp313-cp313-win_amd64.whl", hash = "sha256:5a178390ca90419bfd41419a809688c368e63c86bd725e1186dd97f6b89c2706", size = 446735 },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/e1/8029b29316971c5fa89cec170274582619a01b3d82dd1036872acc9bc7e8/aiohttp-3.12.14-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f4552ff7b18bcec18b60a90c6982049cdb9dac1dba48cf00b97934a06ce2e597", size = 709960 },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/bd/4f204cf1e282041f7b7e8155f846583b19149e0872752711d0da5e9cc023/aiohttp-3.12.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8283f42181ff6ccbcf25acaae4e8ab2ff7e92b3ca4a4ced73b2c12d8cd971393", size = 482235 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/0f/2a580fcdd113fe2197a3b9df30230c7e85bb10bf56f7915457c60e9addd9/aiohttp-3.12.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:040afa180ea514495aaff7ad34ec3d27826eaa5d19812730fe9e529b04bb2179", size = 470501 },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/78/2c1089f6adca90c3dd74915bafed6d6d8a87df5e3da74200f6b3a8b8906f/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b413c12f14c1149f0ffd890f4141a7471ba4b41234fe4fd4a0ff82b1dc299dbb", size = 1740696 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/c8/ce6c7a34d9c589f007cfe064da2d943b3dee5aabc64eaecd21faf927ab11/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1d6f607ce2e1a93315414e3d448b831238f1874b9968e1195b06efaa5c87e245", size = 1689365 },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/10/431cd3d089de700756a56aa896faf3ea82bee39d22f89db7ddc957580308/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:565e70d03e924333004ed101599902bba09ebb14843c8ea39d657f037115201b", size = 1788157 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/b2/26f4524184e0f7ba46671c512d4b03022633bcf7d32fa0c6f1ef49d55800/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4699979560728b168d5ab63c668a093c9570af2c7a78ea24ca5212c6cdc2b641", size = 1827203 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/30/aadcdf71b510a718e3d98a7bfeaea2396ac847f218b7e8edb241b09bd99a/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad5fdf6af93ec6c99bf800eba3af9a43d8bfd66dce920ac905c817ef4a712afe", size = 1729664 },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/7f/7ccf11756ae498fdedc3d689a0c36ace8fc82f9d52d3517da24adf6e9a74/aiohttp-3.12.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ac76627c0b7ee0e80e871bde0d376a057916cb008a8f3ffc889570a838f5cc7", size = 1666741 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/4d/35ebc170b1856dd020c92376dbfe4297217625ef4004d56587024dc2289c/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:798204af1180885651b77bf03adc903743a86a39c7392c472891649610844635", size = 1715013 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/24/46dc0380146f33e2e4aa088b92374b598f5bdcde1718c77e8d1a0094f1a4/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4f1205f97de92c37dd71cf2d5bcfb65fdaed3c255d246172cce729a8d849b4da", size = 1710172 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/0a/46599d7d19b64f4d0fe1b57bdf96a9a40b5c125f0ae0d8899bc22e91fdce/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:76ae6f1dd041f85065d9df77c6bc9c9703da9b5c018479d20262acc3df97d419", size = 1690355 },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/86/b21b682e33d5ca317ef96bd21294984f72379454e689d7da584df1512a19/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a194ace7bc43ce765338ca2dfb5661489317db216ea7ea700b0332878b392cab", size = 1783958 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/45/f639482530b1396c365f23c5e3b1ae51c9bc02ba2b2248ca0c855a730059/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:16260e8e03744a6fe3fcb05259eeab8e08342c4c33decf96a9dad9f1187275d0", size = 1804423 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/e5/39635a9e06eed1d73671bd4079a3caf9cf09a49df08490686f45a710b80e/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c779e5ebbf0e2e15334ea404fcce54009dc069210164a244d2eac8352a44b28", size = 1717479 },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/e1/7f1c77515d369b7419c5b501196526dad3e72800946c0099594c1f0c20b4/aiohttp-3.12.14-cp311-cp311-win32.whl", hash = "sha256:a289f50bf1bd5be227376c067927f78079a7bdeccf8daa6a9e65c38bae14324b", size = 427907 },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/24/a6bf915c85b7a5b07beba3d42b3282936b51e4578b64a51e8e875643c276/aiohttp-3.12.14-cp311-cp311-win_amd64.whl", hash = "sha256:0b8a69acaf06b17e9c54151a6c956339cf46db4ff72b3ac28516d0f7068f4ced", size = 452334 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/0d/29026524e9336e33d9767a1e593ae2b24c2b8b09af7c2bd8193762f76b3e/aiohttp-3.12.14-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a0ecbb32fc3e69bc25efcda7d28d38e987d007096cbbeed04f14a6662d0eee22", size = 701055 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/b8/a5e8e583e6c8c1056f4b012b50a03c77a669c2e9bf012b7cf33d6bc4b141/aiohttp-3.12.14-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0400f0ca9bb3e0b02f6466421f253797f6384e9845820c8b05e976398ac1d81a", size = 475670 },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/e8/5202890c9e81a4ec2c2808dd90ffe024952e72c061729e1d49917677952f/aiohttp-3.12.14-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a56809fed4c8a830b5cae18454b7464e1529dbf66f71c4772e3cfa9cbec0a1ff", size = 468513 },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/e5/d11db8c23d8923d3484a27468a40737d50f05b05eebbb6288bafcb467356/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f2e373276e4755691a963e5d11756d093e346119f0627c2d6518208483fb6d", size = 1715309 },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/44/af6879ca0eff7a16b1b650b7ea4a827301737a350a464239e58aa7c387ef/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ca39e433630e9a16281125ef57ece6817afd1d54c9f1bf32e901f38f16035869", size = 1697961 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/94/18457f043399e1ec0e59ad8674c0372f925363059c276a45a1459e17f423/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c748b3f8b14c77720132b2510a7d9907a03c20ba80f469e58d5dfd90c079a1c", size = 1753055 },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/d9/1d3744dc588fafb50ff8a6226d58f484a2242b5dd93d8038882f55474d41/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a568abe1b15ce69d4cc37e23020720423f0728e3cb1f9bcd3f53420ec3bfe7", size = 1799211 },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/12/2530fb2b08773f717ab2d249ca7a982ac66e32187c62d49e2c86c9bba9b4/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9888e60c2c54eaf56704b17feb558c7ed6b7439bca1e07d4818ab878f2083660", size = 1718649 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/34/8d6015a729f6571341a311061b578e8b8072ea3656b3d72329fa0faa2c7c/aiohttp-3.12.14-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3006a1dc579b9156de01e7916d38c63dc1ea0679b14627a37edf6151bc530088", size = 1634452 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/4b/08b83ea02595a582447aeb0c1986792d0de35fe7a22fb2125d65091cbaf3/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aa8ec5c15ab80e5501a26719eb48a55f3c567da45c6ea5bb78c52c036b2655c7", size = 1695511 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/66/9c7c31037a063eec13ecf1976185c65d1394ded4a5120dd5965e3473cb21/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:39b94e50959aa07844c7fe2206b9f75d63cc3ad1c648aaa755aa257f6f2498a9", size = 1716967 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/02/84406e0ad1acb0fb61fd617651ab6de760b2d6a31700904bc0b33bd0894d/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:04c11907492f416dad9885d503fbfc5dcb6768d90cad8639a771922d584609d3", size = 1657620 },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/53/da018f4013a7a179017b9a274b46b9a12cbeb387570f116964f498a6f211/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:88167bd9ab69bb46cee91bd9761db6dfd45b6e76a0438c7e884c3f8160ff21eb", size = 1737179 },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/e8/ca01c5ccfeaafb026d85fa4f43ceb23eb80ea9c1385688db0ef322c751e9/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:791504763f25e8f9f251e4688195e8b455f8820274320204f7eafc467e609425", size = 1765156 },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/32/5501ab525a47ba23c20613e568174d6c63aa09e2caa22cded5c6ea8e3ada/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2785b112346e435dd3a1a67f67713a3fe692d288542f1347ad255683f066d8e0", size = 1724766 },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/af/28e24574801fcf1657945347ee10df3892311c2829b41232be6089e461e7/aiohttp-3.12.14-cp312-cp312-win32.whl", hash = "sha256:15f5f4792c9c999a31d8decf444e79fcfd98497bf98e94284bf390a7bb8c1729", size = 422641 },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/d5/7ac2464aebd2eecac38dbe96148c9eb487679c512449ba5215d233755582/aiohttp-3.12.14-cp312-cp312-win_amd64.whl", hash = "sha256:3b66e1a182879f579b105a80d5c4bd448b91a57e8933564bf41665064796a338", size = 449316 },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/48/e0d2fa8ac778008071e7b79b93ab31ef14ab88804d7ba71b5c964a7c844e/aiohttp-3.12.14-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3143a7893d94dc82bc409f7308bc10d60285a3cd831a68faf1aa0836c5c3c767", size = 695471 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/e7/f73206afa33100804f790b71092888f47df65fd9a4cd0e6800d7c6826441/aiohttp-3.12.14-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3d62ac3d506cef54b355bd34c2a7c230eb693880001dfcda0bf88b38f5d7af7e", size = 473128 },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/e2/4dd00180be551a6e7ee979c20fc7c32727f4889ee3fd5b0586e0d47f30e1/aiohttp-3.12.14-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:48e43e075c6a438937c4de48ec30fa8ad8e6dfef122a038847456bfe7b947b63", size = 465426 },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/dd/525ed198a0bb674a323e93e4d928443a680860802c44fa7922d39436b48b/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:077b4488411a9724cecc436cbc8c133e0d61e694995b8de51aaf351c7578949d", size = 1704252 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/b1/01e542aed560a968f692ab4fc4323286e8bc4daae83348cd63588e4f33e3/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d8c35632575653f297dcbc9546305b2c1133391089ab925a6a3706dfa775ccab", size = 1685514 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/06/93669694dc5fdabdc01338791e70452d60ce21ea0946a878715688d5a191/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b8ce87963f0035c6834b28f061df90cf525ff7c9b6283a8ac23acee6502afd4", size = 1737586 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/3a/18991048ffc1407ca51efb49ba8bcc1645961f97f563a6c480cdf0286310/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a2cf66e32a2563bb0766eb24eae7e9a269ac0dc48db0aae90b575dc9583026", size = 1786958 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/a8/81e237f89a32029f9b4a805af6dffc378f8459c7b9942712c809ff9e76e5/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdea089caf6d5cde975084a884c72d901e36ef9c2fd972c9f51efbbc64e96fbd", size = 1709287 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/e3/bd67a11b0fe7fc12c6030473afd9e44223d456f500f7cf526dbaa259ae46/aiohttp-3.12.14-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7865f27db67d49e81d463da64a59365ebd6b826e0e4847aa111056dcb9dc88", size = 1622990 },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/ba/e0cc8e0f0d9ce0904e3cf2d6fa41904e379e718a013c721b781d53dcbcca/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0ab5b38a6a39781d77713ad930cb5e7feea6f253de656a5f9f281a8f5931b086", size = 1676015 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/b3/1e6c960520bda094c48b56de29a3d978254637ace7168dd97ddc273d0d6c/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b3b15acee5c17e8848d90a4ebc27853f37077ba6aec4d8cb4dbbea56d156933", size = 1707678 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/19/929a3eb8c35b7f9f076a462eaa9830b32c7f27d3395397665caa5e975614/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e4c972b0bdaac167c1e53e16a16101b17c6d0ed7eac178e653a07b9f7fad7151", size = 1650274 },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/e5/81682a6f20dd1b18ce3d747de8eba11cbef9b270f567426ff7880b096b48/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7442488b0039257a3bdbc55f7209587911f143fca11df9869578db6c26feeeb8", size = 1726408 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/17/884938dffaa4048302985483f77dfce5ac18339aad9b04ad4aaa5e32b028/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f68d3067eecb64c5e9bab4a26aa11bd676f4c70eea9ef6536b0a4e490639add3", size = 1759879 },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/78/53b081980f50b5cf874359bde707a6eacd6c4be3f5f5c93937e48c9d0025/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f88d3704c8b3d598a08ad17d06006cb1ca52a1182291f04979e305c8be6c9758", size = 1708770 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/91/228eeddb008ecbe3ffa6c77b440597fdf640307162f0c6488e72c5a2d112/aiohttp-3.12.14-cp313-cp313-win32.whl", hash = "sha256:a3c99ab19c7bf375c4ae3debd91ca5d394b98b6089a03231d4c580ef3c2ae4c5", size = 421688 },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/5f/8427618903343402fdafe2850738f735fd1d9409d2a8f9bcaae5e630d3ba/aiohttp-3.12.14-cp313-cp313-win_amd64.whl", hash = "sha256:3f8aad695e12edc9d571f878c62bedc91adf30c760c8632f09663e5f564f4baa", size = 448098 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -264,11 +264,11 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2025.6.15"
|
||||
version = "2025.7.14"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/73/f7/f14b46d4bcd21092d7d3ccef689615220d8a08fb25e564b65d20738e672e/certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b", size = 158753 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b3/76/52c535bcebe74590f296d6c77c86dabf761c41980e1347a2422e4aa2ae41/certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995", size = 163981 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/84/ae/320161bd181fc06471eed047ecce67b693fd7515b16d495d8932db763426/certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057", size = 157650 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/52/34c6cf5bb9285074dc3531c437b3919e825d976fde097a7a73f79e726d03/certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2", size = 162722 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -456,23 +456,23 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "debugpy"
|
||||
version = "1.8.14"
|
||||
version = "1.8.15"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bd/75/087fe07d40f490a78782ff3b0a30e3968936854105487decdb33446d4b0e/debugpy-1.8.14.tar.gz", hash = "sha256:7cd287184318416850aa8b60ac90105837bb1e59531898c07569d197d2ed5322", size = 1641444 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/3a9a28ddb750a76eaec445c7f4d3147ea2c579a97dbd9e25d39001b92b21/debugpy-1.8.15.tar.gz", hash = "sha256:58d7a20b7773ab5ee6bdfb2e6cf622fdf1e40c9d5aef2857d85391526719ac00", size = 1643279 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/67/e8/57fe0c86915671fd6a3d2d8746e40485fd55e8d9e682388fbb3a3d42b86f/debugpy-1.8.14-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:1b2ac8c13b2645e0b1eaf30e816404990fbdb168e193322be8f545e8c01644a9", size = 2175064 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/97/2b2fd1b1c9569c6764ccdb650a6f752e4ac31be465049563c9eb127a8487/debugpy-1.8.14-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf431c343a99384ac7eab2f763980724834f933a271e90496944195318c619e2", size = 3132359 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/ee/b825c87ed06256ee2a7ed8bab8fb3bb5851293bf9465409fdffc6261c426/debugpy-1.8.14-cp311-cp311-win32.whl", hash = "sha256:c99295c76161ad8d507b413cd33422d7c542889fbb73035889420ac1fad354f2", size = 5133269 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/a6/6c70cd15afa43d37839d60f324213843174c1d1e6bb616bd89f7c1341bac/debugpy-1.8.14-cp311-cp311-win_amd64.whl", hash = "sha256:7816acea4a46d7e4e50ad8d09d963a680ecc814ae31cdef3622eb05ccacf7b01", size = 5158156 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/2a/ac2df0eda4898f29c46eb6713a5148e6f8b2b389c8ec9e425a4a1d67bf07/debugpy-1.8.14-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:8899c17920d089cfa23e6005ad9f22582fd86f144b23acb9feeda59e84405b84", size = 2501268 },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/53/0a0cb5d79dd9f7039169f8bf94a144ad3efa52cc519940b3b7dde23bcb89/debugpy-1.8.14-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6bb5c0dcf80ad5dbc7b7d6eac484e2af34bdacdf81df09b6a3e62792b722826", size = 4221077 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/d5/84e01821f362327bf4828728aa31e907a2eca7c78cd7c6ec062780d249f8/debugpy-1.8.14-cp312-cp312-win32.whl", hash = "sha256:281d44d248a0e1791ad0eafdbbd2912ff0de9eec48022a5bfbc332957487ed3f", size = 5255127 },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/16/1ed929d812c758295cac7f9cf3dab5c73439c83d9091f2d91871e648093e/debugpy-1.8.14-cp312-cp312-win_amd64.whl", hash = "sha256:5aa56ef8538893e4502a7d79047fe39b1dae08d9ae257074c6464a7b290b806f", size = 5297249 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/e4/395c792b243f2367d84202dc33689aa3d910fb9826a7491ba20fc9e261f5/debugpy-1.8.14-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:329a15d0660ee09fec6786acdb6e0443d595f64f5d096fc3e3ccf09a4259033f", size = 2485676 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/f1/6f2ee3f991327ad9e4c2f8b82611a467052a0fb0e247390192580e89f7ff/debugpy-1.8.14-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f920c7f9af409d90f5fd26e313e119d908b0dd2952c2393cd3247a462331f15", size = 4217514 },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/28/b9d146f8f2dc535c236ee09ad3e5ac899adb39d7a19b49f03ac95d216beb/debugpy-1.8.14-cp313-cp313-win32.whl", hash = "sha256:3784ec6e8600c66cbdd4ca2726c72d8ca781e94bce2f396cc606d458146f8f4e", size = 5254756 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/62/a7b4a57013eac4ccaef6977966e6bec5c63906dd25a86e35f155952e29a1/debugpy-1.8.14-cp313-cp313-win_amd64.whl", hash = "sha256:684eaf43c95a3ec39a96f1f5195a7ff3d4144e4a18d69bb66beeb1a6de605d6e", size = 5297119 },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/1a/481f33c37ee3ac8040d3d51fc4c4e4e7e61cb08b8bc8971d6032acc2279f/debugpy-1.8.14-py2.py3-none-any.whl", hash = "sha256:5cd9a579d553b6cb9759a7908a41988ee6280b961f24f63336835d9418216a20", size = 5256230 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/b3/1c44a2ed311199ab11c2299c9474a6c7cd80d19278defd333aeb7c287995/debugpy-1.8.15-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:babc4fb1962dd6a37e94d611280e3d0d11a1f5e6c72ac9b3d87a08212c4b6dd3", size = 2183442 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/69/e2dcb721491e1c294d348681227c9b44fb95218f379aa88e12a19d85528d/debugpy-1.8.15-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f778e68f2986a58479d0ac4f643e0b8c82fdd97c2e200d4d61e7c2d13838eb53", size = 3134215 },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/76/4ce63b95d8294dcf2fd1820860b300a420d077df4e93afcaa25a984c2ca7/debugpy-1.8.15-cp311-cp311-win32.whl", hash = "sha256:f9d1b5abd75cd965e2deabb1a06b0e93a1546f31f9f621d2705e78104377c702", size = 5154037 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/a7/e5a7c784465eb9c976d84408873d597dc7ce74a0fc69ed009548a1a94813/debugpy-1.8.15-cp311-cp311-win_amd64.whl", hash = "sha256:62954fb904bec463e2b5a415777f6d1926c97febb08ef1694da0e5d1463c5c3b", size = 5178133 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/4a/4508d256e52897f5cdfee6a6d7580974811e911c6d01321df3264508a5ac/debugpy-1.8.15-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:3dcc7225cb317469721ab5136cda9ff9c8b6e6fb43e87c9e15d5b108b99d01ba", size = 2511197 },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/8d/7f6ef1097e7fecf26b4ef72338d08e41644a41b7ee958a19f494ffcffc29/debugpy-1.8.15-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:047a493ca93c85ccede1dbbaf4e66816794bdc214213dde41a9a61e42d27f8fc", size = 4229517 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/e8/e8c6a9aa33a9c9c6dacbf31747384f6ed2adde4de2e9693c766bdf323aa3/debugpy-1.8.15-cp312-cp312-win32.whl", hash = "sha256:b08e9b0bc260cf324c890626961dad4ffd973f7568fbf57feb3c3a65ab6b6327", size = 5276132 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/ad/231050c6177b3476b85fcea01e565dac83607b5233d003ff067e2ee44d8f/debugpy-1.8.15-cp312-cp312-win_amd64.whl", hash = "sha256:e2a4fe357c92334272eb2845fcfcdbec3ef9f22c16cf613c388ac0887aed15fa", size = 5317645 },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/70/2928aad2310726d5920b18ed9f54b9f06df5aa4c10cf9b45fa18ff0ab7e8/debugpy-1.8.15-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:f5e01291ad7d6649aed5773256c5bba7a1a556196300232de1474c3c372592bf", size = 2495538 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/c6/9b8ffb4ca91fac8b2877eef63c9cc0e87dd2570b1120054c272815ec4cd0/debugpy-1.8.15-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94dc0f0d00e528d915e0ce1c78e771475b2335b376c49afcc7382ee0b146bab6", size = 4221874 },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/8a/9b8d59674b4bf489318c7c46a1aab58e606e583651438084b7e029bf3c43/debugpy-1.8.15-cp313-cp313-win32.whl", hash = "sha256:fcf0748d4f6e25f89dc5e013d1129ca6f26ad4da405e0723a4f704583896a709", size = 5275949 },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/83/9e58e6fdfa8710a5e6ec06c2401241b9ad48b71c0a7eb99570a1f1edb1d3/debugpy-1.8.15-cp313-cp313-win_amd64.whl", hash = "sha256:73c943776cb83e36baf95e8f7f8da765896fd94b05991e7bc162456d25500683", size = 5317720 },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/d5/98748d9860e767a1248b5e31ffa7ce8cb7006e97bf8abbf3d891d0a8ba4e/debugpy-1.8.15-py2.py3-none-any.whl", hash = "sha256:bce2e6c5ff4f2e00b98d45e7e01a49c7b489ff6df5f12d881c67d2f1ac635f3d", size = 5282697 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -906,15 +906,15 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "pyinstaller-hooks-contrib"
|
||||
version = "2025.5"
|
||||
version = "2025.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "packaging" },
|
||||
{ name = "setuptools" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5f/ff/e3376595935d5f8135964d2177cd3e3e0c1b5a6237497d9775237c247a5d/pyinstaller_hooks_contrib-2025.5.tar.gz", hash = "sha256:707386770b8fe066c04aad18a71bc483c7b25e18b4750a756999f7da2ab31982", size = 163124 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ea/f7/d375cf8112d839afaf05b90c70dd128624473fd915fce211f5646b0afbc7/pyinstaller_hooks_contrib-2025.6.tar.gz", hash = "sha256:223ae773733fb7a0ee9cb5e817480998a90a6c7a9c3d2b7b580d2dfa2b325751", size = 163799 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/2c/b4d317534e17dd1df95c394d4b37febb15ead006a1c07c2bb006481fb5e7/pyinstaller_hooks_contrib-2025.5-py3-none-any.whl", hash = "sha256:ebfae1ba341cb0002fb2770fad0edf2b3e913c2728d92df7ad562260988ca373", size = 437246 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/e6/ab065bd226099a4e39aa08a54810f846beb7a9c534fa221ee750a3befa25/pyinstaller_hooks_contrib-2025.6-py3-none-any.whl", hash = "sha256:06779d024f7d60dd75b05520923bba16b17df5f64073434b23e570ffb71094dc", size = 440590 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
Loading…
Reference in a new issue