Merge pull request #557 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix: use yt-dlp[default] for upgrading logic
This commit is contained in:
commit
0473c86fd6
32 changed files with 1693 additions and 1577 deletions
2
.github/workflows/update-yt-dlp.yml
vendored
2
.github/workflows/update-yt-dlp.yml
vendored
|
|
@ -42,7 +42,7 @@ jobs:
|
|||
VER=$(uv pip list --outdated | awk '$1 == "yt-dlp" {print $3}')
|
||||
if [ -n "$VER" ]; then
|
||||
echo "YTLDLP_VER=${VER}" >> "$GITHUB_OUTPUT"
|
||||
uv pip install --upgrade yt-dlp
|
||||
uv pip install --upgrade yt-dlp[default]
|
||||
uv sync --upgrade
|
||||
UPDATED=true
|
||||
else
|
||||
|
|
|
|||
18
FAQ.md
18
FAQ.md
|
|
@ -317,22 +317,13 @@ Then simply create a new preset, and in the `Command options for yt-dlp` field s
|
|||
|
||||
```bash
|
||||
--extractor-args "youtubepot-bgutilhttp:base_url=http://bgutil_provider:4416"
|
||||
--extractor-args "youtube:player-client=default,tv,mweb;formats=incomplete"
|
||||
```
|
||||
|
||||
you and also enable the fallback by using the follow extractor args
|
||||
|
||||
```bash
|
||||
--extractor-args "youtubepot-bgutilhttp:base_url=http://bgutil_provider:4416;disable_innertube=1"
|
||||
--extractor-args "youtube:player-client=default,tv,mweb;formats=incomplete"
|
||||
```
|
||||
|
||||
Use this alternative extractor args in case the extractor fails to get the pot tokens from the bgutil provider server.
|
||||
For more information please visit [bgutil-ytdlp-pot-provider](https://github.com/Brainicism/bgutil-ytdlp-pot-provider) project.
|
||||
|
||||
# Troubleshooting and submitting issues
|
||||
|
||||
Before asking a question or submitting an issue for YTPTube, please remember that YTPTube is only a thin wrapper for
|
||||
Before asking a question or submitting an issue for YTPTube, please remember that YTPTube is only a wrapper for
|
||||
[yt-dlp](https://github.com/yt-dlp/yt-dlp). Any issues you might be experiencing with authentication to video websites,
|
||||
postprocessing, permissions, other `yt-dlp options` configurations which seem not to work, or anything else that
|
||||
concerns the workings of the underlying yt-dlp library, need not be opened on the YTPTube project.
|
||||
|
|
@ -343,7 +334,8 @@ and once that is working, importing the options that worked for you into a new `
|
|||
## Via HTTP
|
||||
|
||||
If you have enabled the web terminal via `YTP_CONSOLE_ENABLED` environment variable, simply go to `Other > Terminal` use
|
||||
the yt-dlp command, the interface is jailed to the `yt-dlp` binary you can't access anything else.
|
||||
the yt-dlp command, the interface is jailed to the `yt-dlp` binary you can't access anything else. Or from download form
|
||||
by clicking `advanced options` button than the yellow terminal icon `Run directly in console`.
|
||||
|
||||
## Via CLI
|
||||
|
||||
|
|
@ -503,7 +495,7 @@ as we only test for GPU encoding once on first video stream.
|
|||
|
||||
# Allowing internal URLs requests
|
||||
|
||||
By default, YTPTube prevents requests to internal resources, for security reasons. However, if you want to allow requests to internal URLs, you can set the `YTP_ALLOW_INTERNAL_URLS` environment variable to `true`. This will allow requests to internal URLs.
|
||||
By default, YTPTube prevents requests to internal resources. However, if you want to allow requests to internal URLs, you can set the `YTP_ALLOW_INTERNAL_URLS` environment variable to `true`. This will allow requests to internal URLs.
|
||||
|
||||
We do not recommend enabling this option unless you know what you are doing, as it can expose your internal network to
|
||||
potential security risks. This should only be used if it's truly needed.
|
||||
|
|
@ -557,7 +549,6 @@ services:
|
|||
After making the changes, restart your container. This should resolve the "No space left on device"
|
||||
error during download.
|
||||
|
||||
|
||||
# How to prevent loading screen during YouTube premieres?
|
||||
|
||||
Depending on how you look at it, YTPTube live download implementation is rather great and fast. However, during YouTube
|
||||
|
|
@ -566,7 +557,6 @@ playing. By default we wait for 5min + the duration of the video before starting
|
|||
the loading screen. However, you can override the behavior by setting the following environment variable:
|
||||
|
||||
```env
|
||||
YTP_PREVENT_LIVE_PREMIERE=true
|
||||
YTP_LIVE_PREMIERE_BUFFER=10
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class Segments:
|
|||
}
|
||||
|
||||
caps: dict[str, dict[str, bool]] = detect_qsv_capabilities()
|
||||
base_codec: str = s_codec.split("_")[0]
|
||||
base_codec: str = s_codec.split("_", maxsplit=1)[0]
|
||||
codec_caps: dict[str, bool] = caps.get(base_codec, {"full": False, "lp": False})
|
||||
ctx["qsv"] = codec_caps
|
||||
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ async def segments_stream(request: Request, config: Config, app: web.Application
|
|||
await Segments(
|
||||
download_path=config.download_path,
|
||||
index=int(segment),
|
||||
duration=float(f"{float(sd if sd else M3u8.duration):.6f}"),
|
||||
duration=float(f"{float(sd or M3u8.duration):.6f}"),
|
||||
vconvert=vc == 1,
|
||||
aconvert=ac == 1,
|
||||
).stream(realFile, resp)
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ class TaskHandle:
|
|||
|
||||
return TaskFailure(
|
||||
message=extraction.message,
|
||||
error=extraction.error if extraction.error else extraction.message,
|
||||
error=extraction.error or extraction.message,
|
||||
metadata=combined_failure_metadata,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ def extract_info_sync(
|
|||
archive_id: str | None = f".{id_dict['id']}" if id_dict.get("id") else None
|
||||
|
||||
log_wrapper.add_target(
|
||||
target=logging.getLogger(f"yt-dlp{archive_id if archive_id else '.extract_info'}"),
|
||||
target=logging.getLogger(f"yt-dlp{archive_id or '.extract_info'}"),
|
||||
level=logging.DEBUG if debug else logging.WARNING,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ async def get_info(request: Request, cache: Cache, config: Config) -> Response:
|
|||
data["is_archived"] = False
|
||||
|
||||
archive_file: str | None = ytdlp_opts.get("download_archive")
|
||||
data["archive_file"] = archive_file if archive_file else None
|
||||
data["archive_file"] = archive_file or None
|
||||
|
||||
if archive_file and (archive_id := get_archive_id(url=url).get("archive_id")):
|
||||
data["archive_id"] = archive_id
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ class YTDLPCli:
|
|||
raise ValueError(msg)
|
||||
|
||||
self.item = item
|
||||
preset_name = item.preset if item.preset else self._config.default_preset
|
||||
preset_name = item.preset or self._config.default_preset
|
||||
self.preset: Preset | None = YTDLPCli._get_presets().get(preset_name)
|
||||
self._config: Config = config or Config.get_instance()
|
||||
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ class Item:
|
|||
"""
|
||||
from app.features.presets.service import Presets
|
||||
|
||||
return Presets.get_instance().get(self.preset if self.preset else self._default_preset())
|
||||
return Presets.get_instance().get(self.preset or self._default_preset())
|
||||
|
||||
def get_archive_id(self) -> str | None:
|
||||
"""
|
||||
|
|
@ -553,7 +553,7 @@ class ItemDTO:
|
|||
"""
|
||||
from app.features.presets.service import Presets
|
||||
|
||||
return Presets.get_instance().get(self.preset if self.preset else "default")
|
||||
return Presets.get_instance().get(self.preset or "default")
|
||||
|
||||
def archive_status(self, force: bool = False) -> None:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -113,15 +113,16 @@ class PackageInstaller:
|
|||
if "yt_dlp" == pkg:
|
||||
pkg = "yt-dlp"
|
||||
|
||||
pkg_name: str = "yt-dlp[default]" if pkg == "yt-dlp" else pkg
|
||||
if version:
|
||||
if "nightly" == version and pkg == "yt-dlp":
|
||||
cmd.extend(["--pre", "yt-dlp[default]"])
|
||||
elif "master" == version and pkg == "yt-dlp":
|
||||
if "nightly" == version and "yt-dlp" == pkg:
|
||||
cmd.extend(["--pre", pkg_name])
|
||||
elif "master" == version and "yt-dlp" == pkg:
|
||||
cmd.append("git+https://github.com/yt-dlp/yt-dlp.git@master")
|
||||
else:
|
||||
cmd.append(version if str(version).startswith("git+") else f"{pkg}=={version}")
|
||||
cmd.append(version if str(version).startswith("git+") else f"{pkg_name}=={version}")
|
||||
else:
|
||||
cmd.extend(["--disable-pip-version-check", pkg])
|
||||
cmd.extend(["--disable-pip-version-check", pkg_name])
|
||||
|
||||
try:
|
||||
proc: subprocess.CompletedProcess[bytes] = subprocess.run(
|
||||
|
|
|
|||
|
|
@ -131,8 +131,8 @@ class UpdateChecker(metaclass=Singleton):
|
|||
if app_cached and ytdlp_cached:
|
||||
return (app_cached, ytdlp_cached)
|
||||
|
||||
app_result = app_cached if app_cached else await self._check_app_version()
|
||||
ytdlp_result = ytdlp_cached if ytdlp_cached else await self._check_ytdlp_version()
|
||||
app_result = app_cached or await self._check_app_version()
|
||||
ytdlp_result = ytdlp_cached or await self._check_ytdlp_version()
|
||||
|
||||
return (app_result, ytdlp_result)
|
||||
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ class Config(metaclass=Singleton):
|
|||
is_native: bool = False
|
||||
"Is the application running in natively."
|
||||
|
||||
prevent_live_premiere: bool = False
|
||||
prevent_live_premiere: bool = True
|
||||
"""Prevent downloading of the initial premiere live broadcast."""
|
||||
|
||||
live_premiere_buffer: int = 5
|
||||
|
|
|
|||
|
|
@ -62,10 +62,10 @@ class Download:
|
|||
self.max_workers = int(config.max_workers)
|
||||
self.is_live: bool = bool(info.is_live) or info.live_in is not None
|
||||
self.info_dict: dict | None = info_dict
|
||||
self.logger: logging.Logger = logging.getLogger(f"Download.{info.id if info.id else info._id}")
|
||||
self.logger: logging.Logger = logging.getLogger(f"Download.{info.id or info._id}")
|
||||
self.started_time = 0
|
||||
self.queue_time: datetime = datetime.now(tz=UTC)
|
||||
self.logs: list[str] = logs if logs else []
|
||||
self.logs: list[str] = logs or []
|
||||
|
||||
self._process_manager = ProcessManager(
|
||||
download_id=self.id,
|
||||
|
|
@ -131,10 +131,7 @@ class Download:
|
|||
|
||||
if self.info.cookies:
|
||||
try:
|
||||
cookie_file = (
|
||||
Path(self._temp_manager.temp_path if self._temp_manager.temp_path else self.temp_dir)
|
||||
/ f"cookie_{self.info._id}.txt"
|
||||
)
|
||||
cookie_file = Path(self._temp_manager.temp_path or self.temp_dir) / f"cookie_{self.info._id}.txt"
|
||||
self.logger.debug(
|
||||
f"Creating cookie file for '{self.info.id}: {self.info.title}' - '{cookie_file}'."
|
||||
)
|
||||
|
|
@ -372,7 +369,7 @@ class Download:
|
|||
self.logger.debug(f"Download task '{self.info.title}: {self.info.id}' started for '{elapsed}' seconds.")
|
||||
return False
|
||||
|
||||
status: str = self.info.status if self.info.status else "unknown"
|
||||
status: str = self.info.status or "unknown"
|
||||
is_stale = is_download_stale(self.started_time, status, self.running(), self.info.auto_start, min_elapsed=300)
|
||||
|
||||
if is_stale:
|
||||
|
|
|
|||
|
|
@ -185,8 +185,7 @@ class StatusTracker:
|
|||
if next_status is None or isinstance(next_status, Terminator):
|
||||
continue
|
||||
await self.process_status_update(next_status)
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Error processing status update during drain: {e}")
|
||||
except Exception: # noqa: S112
|
||||
continue
|
||||
|
||||
def cancel_update_task(self) -> None:
|
||||
|
|
|
|||
|
|
@ -112,12 +112,12 @@ async def add_video(queue: "DownloadQueue", entry: dict, item: "Item", logs: lis
|
|||
download_dir=download_dir,
|
||||
temp_dir=queue.config.temp_path,
|
||||
cookies=item.cookies,
|
||||
template=item.template if item.template else queue.config.output_template,
|
||||
template=item.template or queue.config.output_template,
|
||||
template_chapter=queue.config.output_template_chapter,
|
||||
datetime=formatdate(time.time()),
|
||||
error=error,
|
||||
is_live=is_live,
|
||||
live_in=live_in if live_in else item.extras.get("live_in", None),
|
||||
live_in=live_in or item.extras.get("live_in", None),
|
||||
options=options,
|
||||
cli=item.cli,
|
||||
auto_start=item.auto_start,
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ class Database:
|
|||
else:
|
||||
self.conn: AsyncConnection = db_url
|
||||
|
||||
async def __aenter__(self) -> "Database":
|
||||
async def __aenter__(self):
|
||||
if self._owns_connection and self.conn is None:
|
||||
# Create connection from string URL
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
|
|
@ -284,7 +284,7 @@ def create_migration(name: str, directory: str | None = None) -> str:
|
|||
Create a migration with the given name. If no directory is specified,
|
||||
the current working directory will be used.
|
||||
"""
|
||||
directory = directory if directory else "."
|
||||
directory = directory or "."
|
||||
if not os.path.exists(directory) or not os.path.isdir(directory):
|
||||
msg: str = f"{directory} is not a directory."
|
||||
raise Error(msg)
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ def route(
|
|||
return await func(*args, **kwargs)
|
||||
|
||||
for m in methods:
|
||||
route_name = name if name else make_route_name(m, path)
|
||||
route_name = name or make_route_name(m, path)
|
||||
route_type: str = RouteType.SOCKET if RouteType.SOCKET == m else RouteType.HTTP
|
||||
|
||||
if route_type not in ROUTES:
|
||||
|
|
@ -124,7 +124,7 @@ def add_route(
|
|||
methods = [method] if isinstance(method, (str, RouteType)) else method
|
||||
|
||||
for m in methods:
|
||||
route_name = name if name else make_route_name(m, path)
|
||||
route_name = name or make_route_name(m, path)
|
||||
route_type: str = RouteType.SOCKET if RouteType.SOCKET == m else RouteType.HTTP
|
||||
|
||||
if route_type not in ROUTES:
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ class SqliteStore(metaclass=ThreadSafe):
|
|||
self._flush_interval: float = flush_interval
|
||||
self._max_pending: int = max_pending
|
||||
|
||||
async def __aenter__(self) -> "SqliteStore":
|
||||
async def __aenter__(self):
|
||||
await self.get_connection()
|
||||
return self
|
||||
|
||||
|
|
|
|||
|
|
@ -425,14 +425,12 @@ async def items_add(request: Request, queue: DownloadQueue, encoder: Encoder) ->
|
|||
if not item.extras:
|
||||
item.extras = {}
|
||||
|
||||
item.extras["batch_id"] = batch_id
|
||||
item.extras["batch_index"] = idx
|
||||
item.extras["batch_total"] = len(items)
|
||||
if len(items) > 1:
|
||||
item.extras["batch_id"] = batch_id
|
||||
item.extras["batch_index"] = idx
|
||||
item.extras["batch_total"] = len(items)
|
||||
|
||||
task = asyncio.create_task(
|
||||
queue.add(item=item),
|
||||
name=f"bulk_add_{batch_id}_{idx}",
|
||||
)
|
||||
task = asyncio.create_task(queue.add(item=item), name=f"bulk_add_{batch_id}_{idx}")
|
||||
task.add_done_callback(lambda t: handle_task_exception(t, LOG))
|
||||
|
||||
return web.json_response(
|
||||
|
|
|
|||
|
|
@ -199,12 +199,12 @@ async def check_updates(config: Config, encoder: Encoder, update_checker: Update
|
|||
"app": {
|
||||
"status": "update_available" if config.new_version else "up_to_date",
|
||||
"current_version": config.app_version,
|
||||
"new_version": config.new_version if config.new_version else None,
|
||||
"new_version": config.new_version or None,
|
||||
},
|
||||
"ytdlp": {
|
||||
"status": "update_available" if config.yt_new_version else "up_to_date",
|
||||
"current_version": config._ytdlp_version(),
|
||||
"new_version": config.yt_new_version if config.yt_new_version else None,
|
||||
"new_version": config.yt_new_version or None,
|
||||
},
|
||||
},
|
||||
status=web.HTTPOk.status_code,
|
||||
|
|
|
|||
|
|
@ -170,171 +170,7 @@ class TestUpdateChecker:
|
|||
|
||||
mock_ytdlp_response = MagicMock()
|
||||
mock_ytdlp_response.status_code = 200
|
||||
mock_ytdlp_response.json.return_value = {"tag_name": "9999.12.31"}
|
||||
|
||||
mock_get = AsyncMock(side_effect=[mock_app_response, mock_ytdlp_response])
|
||||
mock_http = MagicMock()
|
||||
mock_http.get = mock_get
|
||||
mock_client.return_value = mock_http
|
||||
|
||||
with patch("app.library.UpdateChecker.APP_VERSION", "v1.0.0"):
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
(app_status, app_version), (ytdlp_status, ytdlp_version) = await checker.check_for_updates()
|
||||
|
||||
assert "update_available" == app_status, "Should return update_available status for app"
|
||||
assert "v99.0.0" == app_version, "Should return new app version tag"
|
||||
assert "v99.0.0" == config.new_version, "Should store new app version tag"
|
||||
assert "update_available" == ytdlp_status, "Should return update_available status for yt-dlp"
|
||||
assert "9999.12.31" == ytdlp_version, "Should return new yt-dlp version tag"
|
||||
assert "9999.12.31" == config.yt_new_version, "Should store new yt-dlp version tag"
|
||||
assert checker._job_id is None, "Should stop scheduled task after finding app update"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("app.library.UpdateChecker.get_async_client")
|
||||
async def test_check_for_updates_no_update_available(self, mock_client):
|
||||
"""Test that check_for_updates correctly handles when no update is available."""
|
||||
from app.library.config import Config
|
||||
from app.library.UpdateChecker import UpdateChecker
|
||||
|
||||
config = Config.get_instance()
|
||||
config.check_for_updates = True
|
||||
config.new_version = ""
|
||||
config.yt_new_version = ""
|
||||
|
||||
mock_app_response = MagicMock()
|
||||
mock_app_response.status_code = 200
|
||||
mock_app_response.json.return_value = {"tag_name": "v1.0.0"}
|
||||
|
||||
mock_ytdlp_response = MagicMock()
|
||||
mock_ytdlp_response.status_code = 200
|
||||
mock_ytdlp_response.json.return_value = {"tag_name": "2020.01.01"}
|
||||
|
||||
mock_get = AsyncMock(side_effect=[mock_app_response, mock_ytdlp_response])
|
||||
mock_http = MagicMock()
|
||||
mock_http.get = mock_get
|
||||
mock_client.return_value = mock_http
|
||||
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
checker._job_id = "test-job"
|
||||
|
||||
(app_status, app_version), (ytdlp_status, ytdlp_version) = await checker.check_for_updates()
|
||||
|
||||
assert "up_to_date" == app_status, "Should return up_to_date status for app"
|
||||
assert app_version is None, "Should return None for app new_version"
|
||||
assert "" == config.new_version, "Should clear new_version when no app update available"
|
||||
assert "up_to_date" == ytdlp_status, "Should return up_to_date status for yt-dlp"
|
||||
assert ytdlp_version is None, "Should return None for yt-dlp new_version"
|
||||
assert "" == config.yt_new_version, "Should clear yt_new_version when no yt-dlp update available"
|
||||
assert "test-job" == checker._job_id, "Should keep scheduled task running"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("app.library.UpdateChecker.get_async_client")
|
||||
async def test_check_for_updates_handles_http_error(self, mock_client):
|
||||
"""Test that check_for_updates handles HTTP errors gracefully."""
|
||||
from app.library.config import Config
|
||||
from app.library.UpdateChecker import UpdateChecker
|
||||
|
||||
config = Config.get_instance()
|
||||
config.check_for_updates = True
|
||||
config.new_version = ""
|
||||
config.yt_new_version = ""
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 404
|
||||
|
||||
mock_http = MagicMock()
|
||||
mock_http.get = AsyncMock(return_value=mock_response)
|
||||
mock_client.return_value = mock_http
|
||||
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
|
||||
(app_status, app_version), (ytdlp_status, ytdlp_version) = await checker.check_for_updates()
|
||||
|
||||
assert "error" == app_status, "Should return error status for app"
|
||||
assert app_version is None, "Should return None for app new_version on error"
|
||||
assert "" == config.new_version, "Should not set new_version on HTTP error"
|
||||
assert "error" == ytdlp_status, "Should return error status for yt-dlp"
|
||||
assert ytdlp_version is None, "Should return None for yt-dlp new_version on error"
|
||||
assert "" == config.yt_new_version, "Should not set yt_new_version on HTTP error"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("app.library.UpdateChecker.get_async_client")
|
||||
async def test_check_for_updates_handles_exception(self, mock_client):
|
||||
"""Test that check_for_updates handles exceptions gracefully."""
|
||||
from app.library.config import Config
|
||||
from app.library.UpdateChecker import UpdateChecker
|
||||
|
||||
config = Config.get_instance()
|
||||
config.check_for_updates = True
|
||||
config.new_version = ""
|
||||
config.yt_new_version = ""
|
||||
|
||||
mock_http = MagicMock()
|
||||
mock_http.get = AsyncMock(side_effect=Exception("Network error"))
|
||||
mock_client.return_value = mock_http
|
||||
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
|
||||
(app_status, app_version), (ytdlp_status, ytdlp_version) = await checker.check_for_updates()
|
||||
|
||||
assert "error" == app_status, "Should return error status on exception for app"
|
||||
assert app_version is None, "Should return None for app new_version on exception"
|
||||
assert "" == config.new_version, "Should not set new_version on exception"
|
||||
assert "error" == ytdlp_status, "Should return error status on exception for yt-dlp"
|
||||
assert ytdlp_version is None, "Should return None for yt-dlp new_version on exception"
|
||||
assert "" == config.yt_new_version, "Should not set yt_new_version on exception"
|
||||
|
||||
def test_compare_versions_newer_available(self):
|
||||
"""Test version comparison detects newer version."""
|
||||
from app.library.UpdateChecker import UpdateChecker
|
||||
|
||||
checker = UpdateChecker.get_instance()
|
||||
|
||||
assert checker._compare_versions("1.0.0", "2.0.0") is True, "Should detect 2.0.0 > 1.0.0"
|
||||
assert checker._compare_versions("1.0.0", "1.1.0") is True, "Should detect 1.1.0 > 1.0.0"
|
||||
assert checker._compare_versions("1.0.0", "1.0.1") is True, "Should detect 1.0.1 > 1.0.0"
|
||||
|
||||
def test_compare_versions_same_version(self):
|
||||
"""Test version comparison with same version."""
|
||||
from app.library.UpdateChecker import UpdateChecker
|
||||
|
||||
checker = UpdateChecker.get_instance()
|
||||
|
||||
assert checker._compare_versions("1.0.0", "1.0.0") is False, "Should detect versions are equal"
|
||||
|
||||
def test_compare_versions_older_version(self):
|
||||
"""Test version comparison with older version."""
|
||||
from app.library.UpdateChecker import UpdateChecker
|
||||
|
||||
checker = UpdateChecker.get_instance()
|
||||
|
||||
assert checker._compare_versions("2.0.0", "1.0.0") is False, "Should detect 1.0.0 is not newer than 2.0.0"
|
||||
|
||||
def test_github_api_url_constant(self):
|
||||
"""Test that GitHub API URL is correctly defined."""
|
||||
from app.library.UpdateChecker import UpdateChecker
|
||||
|
||||
expected_url = "https://api.github.com/repos/arabcoders/ytptube/releases/latest"
|
||||
assert UpdateChecker.GITHUB_API_URL == expected_url, "GitHub API URL should be correct"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_check_for_updates_stores_tag_name(self):
|
||||
"""Test that check_for_updates stores the tag_name when update found."""
|
||||
from app.library.config import Config
|
||||
from app.library.UpdateChecker import UpdateChecker
|
||||
|
||||
config = Config.get_instance()
|
||||
config.check_for_updates = True
|
||||
config.new_version = ""
|
||||
config.yt_new_version = ""
|
||||
|
||||
mock_app_response = MagicMock()
|
||||
mock_app_response.status_code = 200
|
||||
mock_app_response.json.return_value = {"tag_name": "v2.0.0"}
|
||||
|
||||
mock_ytdlp_response = MagicMock()
|
||||
mock_ytdlp_response.status_code = 200
|
||||
mock_ytdlp_response.json.return_value = {"tag_name": "2026.01.01"}
|
||||
mock_ytdlp_response.json.return_value = {"tag_name": "2026.12.31"}
|
||||
|
||||
mock_get = AsyncMock(side_effect=[mock_app_response, mock_ytdlp_response])
|
||||
mock_http = MagicMock()
|
||||
|
|
@ -342,11 +178,12 @@ class TestUpdateChecker:
|
|||
|
||||
with patch("app.library.UpdateChecker.get_async_client", return_value=mock_http):
|
||||
with patch("app.library.UpdateChecker.APP_VERSION", "v1.0.0"):
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
await checker.check_for_updates()
|
||||
with patch("app.library.config.Config._ytdlp_version", return_value="2026.01.01"):
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
await checker.check_for_updates()
|
||||
|
||||
assert "v2.0.0" == config.new_version, "Should store full tag_name including 'v' prefix"
|
||||
assert "2026.01.01" == config.yt_new_version, "Should store yt-dlp tag_name"
|
||||
assert "v99.0.0" == config.new_version, "Should store full tag_name including 'v' prefix"
|
||||
assert "2026.12.31" == config.yt_new_version, "Should store yt-dlp tag_name"
|
||||
|
||||
def test_subscribe_to_started_event(self):
|
||||
"""Test that attach subscribes to Events.STARTED."""
|
||||
|
|
@ -401,8 +238,9 @@ class TestUpdateChecker:
|
|||
mock_http.get = AsyncMock(return_value=mock_response)
|
||||
mock_client.return_value = mock_http
|
||||
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
status, new_version = await checker._check_ytdlp_version()
|
||||
with patch("app.library.config.Config._ytdlp_version", return_value="2024.01.01"):
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
status, new_version = await checker._check_ytdlp_version()
|
||||
|
||||
assert "update_available" == status, "Should return update_available status for yt-dlp"
|
||||
assert "9999.12.31" == new_version, "Should return new yt-dlp version tag"
|
||||
|
|
@ -427,8 +265,9 @@ class TestUpdateChecker:
|
|||
mock_http.get = AsyncMock(return_value=mock_response)
|
||||
mock_client.return_value = mock_http
|
||||
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
status, new_version = await checker._check_ytdlp_version()
|
||||
with patch("app.library.config.Config._ytdlp_version", return_value="2025.01.01"):
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
status, new_version = await checker._check_ytdlp_version()
|
||||
|
||||
assert "up_to_date" == status, "Should return up_to_date status for yt-dlp"
|
||||
assert new_version is None, "Should return None for yt-dlp new_version"
|
||||
|
|
@ -477,7 +316,7 @@ class TestUpdateChecker:
|
|||
|
||||
mock_ytdlp_response = MagicMock()
|
||||
mock_ytdlp_response.status_code = 200
|
||||
mock_ytdlp_response.json.return_value = {"tag_name": "2026.01.01"}
|
||||
mock_ytdlp_response.json.return_value = {"tag_name": "2026.12.31"}
|
||||
|
||||
mock_get = AsyncMock(side_effect=[mock_app_response, mock_ytdlp_response])
|
||||
mock_http = MagicMock()
|
||||
|
|
@ -485,8 +324,9 @@ class TestUpdateChecker:
|
|||
mock_client.return_value = mock_http
|
||||
|
||||
with patch("app.library.UpdateChecker.APP_VERSION", "v1.0.0"):
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
(app_status1, app_version1), (ytdlp_status1, ytdlp_version1) = await checker.check_for_updates()
|
||||
with patch("app.library.config.Config._ytdlp_version", return_value="2026.01.01"):
|
||||
checker = UpdateChecker.get_instance(config=config)
|
||||
(app_status1, app_version1), (ytdlp_status1, ytdlp_version1) = await checker.check_for_updates()
|
||||
|
||||
assert "update_available" == app_status1, "Should find app update on first call"
|
||||
assert "update_available" == ytdlp_status1, "Should find yt-dlp update on first call"
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ class NFOMakerPP(PostProcessor):
|
|||
try:
|
||||
first_date: str = next((str(nfo_data[k]) for k in self._DATE_FIELDS if nfo_data.get(k)), "")
|
||||
if first_date:
|
||||
nfo_data["year"] = first_date.split("-")[0]
|
||||
nfo_data["year"] = first_date.split("-", maxsplit=1)[0]
|
||||
except Exception as e:
|
||||
self.report_warning(f"Error extracting year from date: {e}")
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,13 @@ ignore = [
|
|||
"PT011",
|
||||
"RUF001",
|
||||
"S311",
|
||||
"TC001"
|
||||
"TC001",
|
||||
"ASYNC240",
|
||||
# will be fixed in the future
|
||||
"UP042",
|
||||
"FURB171",
|
||||
"FURB110",
|
||||
"PLW0108",
|
||||
]
|
||||
|
||||
fixable = ["ALL"]
|
||||
|
|
@ -186,7 +192,7 @@ pythonpath = ["."]
|
|||
testpaths = ["app/tests", "app/features"]
|
||||
addopts = "-v --tb=short"
|
||||
filterwarnings = [
|
||||
"ignore:Parsing dates involving a day of month without a year:DeprecationWarning"
|
||||
"ignore:Parsing dates involving a day of month without a year:DeprecationWarning",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
|
|
@ -195,4 +201,5 @@ dev = [
|
|||
"pytest>=8.4.2",
|
||||
"pytest-asyncio>=1.1.0",
|
||||
"ruff>=0.13.0",
|
||||
"pip>=26.0.0",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@
|
|||
<div class="modal-background" @click="closeVideo"></div>
|
||||
<div class="modal-content is-unbounded-model">
|
||||
<VideoPlayer type="default" :isMuted="false" autoplay="true" :isControls="true" :item="video_item"
|
||||
class="is-fullwidth" @closeModel="closeVideo" />
|
||||
class="is-fullwidth" @closeModel="closeVideo" @error="async (error: string) => await box.alert(error)" />
|
||||
</div>
|
||||
<button class="modal-close is-large" aria-label="close" @click="closeVideo"></button>
|
||||
</div>
|
||||
|
|
@ -499,10 +499,11 @@ import { useStorage, useIntersectionObserver } from '@vueuse/core'
|
|||
import type { StoreItem } from '~/types/store'
|
||||
import { useConfirm } from '~/composables/useConfirm'
|
||||
import { deepIncludes, getPath, getImage } from '~/utils'
|
||||
import type { item_request } from '~/types/item'
|
||||
|
||||
const emitter = defineEmits<{
|
||||
(e: 'getInfo', url: string, preset: string, cli: string): void
|
||||
(e: 'add_new', item: Partial<StoreItem>): void
|
||||
(e: 'add_new', item: item_request): void
|
||||
(e: 'getItemInfo', id: string): void
|
||||
(e: 'clear_search'): void
|
||||
}>()
|
||||
|
|
@ -850,7 +851,7 @@ const removeItem = async (item: StoreItem) => {
|
|||
}
|
||||
|
||||
const retryItem = async (item: StoreItem, re_add: boolean = false, remove_file: boolean = false) => {
|
||||
const item_req: Partial<StoreItem> = {
|
||||
const item_req: item_request = {
|
||||
url: item.url,
|
||||
preset: item.preset,
|
||||
folder: item.folder,
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@
|
|||
<span>Pause</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="column is-half-mobile">
|
||||
<div class="column">
|
||||
<Dropdown icons="fa-solid fa-cogs" label="Actions">
|
||||
<template v-if="isEmbedable(item.url)">
|
||||
<NuxtLink class="dropdown-item has-text-danger" @click="embed_url = getEmbedable(item.url) as string">
|
||||
|
|
|
|||
|
|
@ -260,11 +260,12 @@ import type { StoreItem } from '~/types/store'
|
|||
import type { file_info, video_source_element, video_track_element } from '~/types/video'
|
||||
|
||||
const config = useConfigStore()
|
||||
const toast = useNotification()
|
||||
|
||||
const props = defineProps({ item: { type: Object as () => StoreItem, default: () => ({}) } })
|
||||
|
||||
const emitter = defineEmits(['closeModel'])
|
||||
const props = defineProps<{ item: StoreItem }>()
|
||||
const emitter = defineEmits<{
|
||||
(e: 'closeModel'): void,
|
||||
(e: 'error', message: string): void,
|
||||
}>()
|
||||
|
||||
const video = useTemplateRef<HTMLVideoElement>('video')
|
||||
const tracks = ref<Array<video_track_element>>([])
|
||||
|
|
@ -486,7 +487,7 @@ onMounted(async () => {
|
|||
const response: file_info = await req.json()
|
||||
|
||||
if (!req.ok) {
|
||||
toast.error(`Failed to fetch video info. ${response?.error}`)
|
||||
emitter('error', response?.error || 'Failed to fetch video info. Unknown error')
|
||||
emitter('closeModel')
|
||||
return
|
||||
}
|
||||
|
|
@ -746,7 +747,7 @@ const forceSwitchToHls = () => {
|
|||
}
|
||||
|
||||
if (!hasVideoStream.value) {
|
||||
toast.error('Cannot switch to HLS: stream has no video track.')
|
||||
useNotification().error('Cannot switch to HLS: stream has no video track.')
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@
|
|||
|
||||
<div v-show="'history' === activeTab">
|
||||
<History @getInfo="(url: string, preset: string = '', cli: string = '') => view_info(url, false, preset, cli)"
|
||||
@add_new="(item: Partial<StoreItem>) => toNewDownload(item)" :query="query" :thumbnails="show_thumbnail"
|
||||
@add_new="(item: item_request) => toNewDownload(item)" :query="query" :thumbnails="show_thumbnail"
|
||||
@getItemInfo="(id: string) => view_info(`/api/history/${id}`, true)" @clear_search="query = ''" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -90,13 +90,13 @@
|
|||
|
||||
<div class="column is-2-tablet is-5-mobile">
|
||||
<Dropdown label="Actions" icons="fa-solid fa-list">
|
||||
<a class="dropdown-item has-text-purple" @click="(selectedElms.length > 0 && !massRun) ? runConfirm() : null"
|
||||
<a class="dropdown-item has-text-purple" @click="(selectedElms.length > 0 && !massRun) ? runSelected() : null"
|
||||
:style="{ opacity: (selectedElms.length < 1 || massRun) ? 0.5 : 1, cursor: (selectedElms.length < 1 || massRun) ? 'not-allowed' : 'pointer' }">
|
||||
<span class="icon"><i class="fa-solid fa-up-right-from-square" /></span>
|
||||
<span>Run Selected</span>
|
||||
</a>
|
||||
<a class="dropdown-item has-text-danger"
|
||||
@click="(selectedElms.length > 0 && !massDelete) ? deleteConfirm() : null"
|
||||
@click="(selectedElms.length > 0 && !massDelete) ? deleteSelected() : null"
|
||||
:style="{ opacity: (selectedElms.length < 1 || massDelete) ? 0.5 : 1, cursor: (selectedElms.length < 1 || massDelete) ? 'not-allowed' : 'pointer' }">
|
||||
<span class="icon"><i class="fa-solid fa-trash-can" /></span>
|
||||
<span>Remove Selected</span>
|
||||
|
|
@ -448,10 +448,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="dialog_confirm.visible" :visible="dialog_confirm.visible" :title="dialog_confirm.title"
|
||||
:message="dialog_confirm.message" :options="dialog_confirm.options" @confirm="dialog_confirm.confirm"
|
||||
:html_message="dialog_confirm.html_message" @cancel="dialog_confirm = reset_dialog()" />
|
||||
|
||||
<Modal v-if="inspectTask" @close="() => inspectTask = null" :contentClass="`modal-content-max`">
|
||||
<TaskInspect :url="inspectTask.url" :preset="inspectTask.preset" />
|
||||
</Modal>
|
||||
|
|
@ -470,6 +466,7 @@ import type { Task, ExportedTask } from '~/types/tasks'
|
|||
import type { WSEP } from '~/types/sockets'
|
||||
import { sleep } from '~/utils'
|
||||
import { useSessionCache } from '~/utils/cache'
|
||||
import type { item_request } from '~/types/item'
|
||||
|
||||
type TaskWithUI = Task & { in_progress?: boolean }
|
||||
|
||||
|
|
@ -478,16 +475,15 @@ const toast = useNotification()
|
|||
const config = useConfigStore()
|
||||
const socket = useSocketStore()
|
||||
const stateStore = useStateStore()
|
||||
const { confirmDialog: cDialog } = useDialog()
|
||||
const { confirmDialog } = useDialog()
|
||||
const sessionCache = useSessionCache()
|
||||
const display_style = useStorage<string>("tasks_display_style", "cards")
|
||||
const isMobile = useMediaQuery({ maxWidth: 1024 })
|
||||
|
||||
// Use the tasks composable
|
||||
const tasksComposable = useTasks()
|
||||
const { tasks, isLoading, addInProgress } = tasksComposable
|
||||
|
||||
const task = ref<TaskWithUI | Record<string, unknown>>({})
|
||||
const task = ref<Partial<TaskWithUI>>({})
|
||||
const taskRef = ref<number | null>(null)
|
||||
const toggleForm = ref<boolean>(false)
|
||||
const selectedElms = ref<Array<number>>([])
|
||||
|
|
@ -496,20 +492,10 @@ const massRun = ref<boolean>(false)
|
|||
const massDelete = ref<boolean>(false)
|
||||
const table_container = ref(false)
|
||||
const inspectTask = ref<TaskWithUI | null>(null)
|
||||
|
||||
const reset_dialog = () => ({
|
||||
visible: false,
|
||||
title: 'Confirm Action',
|
||||
confirm: (_opts: any) => { },
|
||||
message: '',
|
||||
html_message: '',
|
||||
options: [],
|
||||
});
|
||||
|
||||
const dialog_confirm = ref(reset_dialog())
|
||||
|
||||
const query = ref()
|
||||
const toggleFilter = ref(false)
|
||||
const CACHE_KEY = 'tasks:handler_support'
|
||||
const taskHandlerSupport = ref<Record<string, boolean>>(sessionCache.get(CACHE_KEY) || {})
|
||||
|
||||
watch(toggleFilter, () => {
|
||||
if (!toggleFilter.value) {
|
||||
|
|
@ -522,18 +508,19 @@ watch(query, () => {
|
|||
selectedElms.value = []
|
||||
})
|
||||
|
||||
|
||||
watch(masterSelectAll, value => {
|
||||
if (!value) {
|
||||
selectedElms.value = []
|
||||
return
|
||||
}
|
||||
|
||||
for (const key in filteredTasks.value) {
|
||||
const element = filteredTasks.value[key] as Task
|
||||
if (element.id) {
|
||||
selectedElms.value.push(element.id)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
watch(() => socket.isConnected, async () => {
|
||||
|
|
@ -543,10 +530,7 @@ watch(() => socket.isConnected, async () => {
|
|||
socket.on('item_status', statusHandler)
|
||||
})
|
||||
|
||||
|
||||
const CACHE_KEY = 'tasks:handler_support'
|
||||
const taskHandlerSupport = ref<Record<string, boolean>>(sessionCache.get(CACHE_KEY) || {})
|
||||
watch(taskHandlerSupport, (newValue) => sessionCache.set(CACHE_KEY, newValue), { deep: true })
|
||||
watch(taskHandlerSupport, newValue => sessionCache.set(CACHE_KEY, newValue), { deep: true })
|
||||
|
||||
const getCacheKey = (task: Task): string => `${task.id}:${task.url}`
|
||||
|
||||
|
|
@ -581,7 +565,7 @@ const checkHandlerSupport = async (task: Task): Promise<boolean> => {
|
|||
url: task.url,
|
||||
static_only: true
|
||||
})
|
||||
const supported = result?.matched === true
|
||||
const supported = true === result?.matched
|
||||
taskHandlerSupport.value[cacheKey] = supported
|
||||
return supported
|
||||
} catch {
|
||||
|
|
@ -624,7 +608,6 @@ const reloadContent = async (fromMounted: boolean = false) => {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
const resetForm = (closeForm: boolean = false) => {
|
||||
task.value = {
|
||||
name: '',
|
||||
|
|
@ -644,38 +627,39 @@ const resetForm = (closeForm: boolean = false) => {
|
|||
}
|
||||
}
|
||||
|
||||
const deleteConfirm = () => {
|
||||
if (selectedElms.value.length < 1) {
|
||||
toast.error('No tasks selected.')
|
||||
return
|
||||
}
|
||||
dialog_confirm.value.visible = true
|
||||
dialog_confirm.value.title = 'Delete Selected Tasks'
|
||||
dialog_confirm.value.message = `Delete ${selectedElms.value.length} task/s?`
|
||||
dialog_confirm.value.confirm = async () => await deleteSelected()
|
||||
}
|
||||
|
||||
const deleteSelected = async () => {
|
||||
if (selectedElms.value.length < 1) {
|
||||
toast.error('No tasks selected.')
|
||||
return
|
||||
}
|
||||
|
||||
massDelete.value = true
|
||||
dialog_confirm.value = reset_dialog()
|
||||
const { status } = await confirmDialog({
|
||||
title: 'Delete Selected Tasks',
|
||||
rawHTML: `Delete <strong class="has-text-danger">${selectedElms.value.length}</strong> task/s?<ul>` + selectedElms.value.map(id => {
|
||||
const item = tasks.value.find(t => t.id === id)
|
||||
return item ? `<li>${item.id}: ${item.name}</li>` : ''
|
||||
}).join('') + `</ul>`,
|
||||
confirmText: 'Delete',
|
||||
confirmColor: 'is-danger'
|
||||
})
|
||||
|
||||
if (true !== status) {
|
||||
return
|
||||
}
|
||||
|
||||
const itemsToDelete = tasks.value.filter(t => t.id && selectedElms.value.includes(t.id))
|
||||
if (itemsToDelete.length < 1) {
|
||||
toast.error('No tasks found to delete.')
|
||||
massDelete.value = false
|
||||
return
|
||||
}
|
||||
|
||||
// Delete tasks sequentially
|
||||
massDelete.value = true
|
||||
|
||||
for (const item of itemsToDelete) {
|
||||
if (item.id) {
|
||||
await tasksComposable.deleteTask(item.id)
|
||||
if (!item.id) {
|
||||
continue
|
||||
}
|
||||
await tasksComposable.deleteTask(item.id)
|
||||
}
|
||||
|
||||
selectedElms.value = []
|
||||
|
|
@ -687,15 +671,9 @@ const deleteSelected = async () => {
|
|||
}
|
||||
|
||||
const deleteItem = async (item: Task) => {
|
||||
if (true !== (await box.confirm(`Delete '${item.name}' task?`))) {
|
||||
if (!item.id || true !== (await box.confirm(`Delete '${item.name}' task?`))) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!item.id) {
|
||||
toast.error('Task ID is missing')
|
||||
return
|
||||
}
|
||||
|
||||
await tasksComposable.deleteTask(item.id)
|
||||
}
|
||||
|
||||
|
|
@ -705,15 +683,9 @@ const toggleEnabled = async (item: Task) => {
|
|||
return
|
||||
}
|
||||
|
||||
const newStatus = !item.enabled
|
||||
|
||||
const updated = await tasksComposable.patchTask(item.id, { enabled: newStatus })
|
||||
|
||||
const updated = await tasksComposable.patchTask(item.id, { enabled: !item.enabled })
|
||||
if (updated) {
|
||||
// Update local reference
|
||||
item.enabled = updated.enabled
|
||||
|
||||
// Update handler support cache if needed
|
||||
if (updated.enabled) {
|
||||
await checkHandlerSupport(updated)
|
||||
}
|
||||
|
|
@ -726,15 +698,9 @@ const toggleHandlerEnabled = async (item: Task) => {
|
|||
return
|
||||
}
|
||||
|
||||
const newStatus = !item.handler_enabled
|
||||
|
||||
const updated = await tasksComposable.patchTask(item.id, { handler_enabled: newStatus })
|
||||
|
||||
const updated = await tasksComposable.patchTask(item.id, { handler_enabled: !item.handler_enabled })
|
||||
if (updated) {
|
||||
// Update local reference
|
||||
item.handler_enabled = updated.handler_enabled
|
||||
|
||||
// Update handler support cache if needed
|
||||
if (updated.handler_enabled) {
|
||||
await checkHandlerSupport(updated)
|
||||
}
|
||||
|
|
@ -745,10 +711,8 @@ const updateItem = async ({ reference, task, archive_all }: { reference?: number
|
|||
let createdOrUpdated: Task | null = null
|
||||
|
||||
if (reference) {
|
||||
// Update existing task
|
||||
createdOrUpdated = await tasksComposable.updateTask(reference, task)
|
||||
} else {
|
||||
// Create new task
|
||||
createdOrUpdated = await tasksComposable.createTask(task)
|
||||
}
|
||||
|
||||
|
|
@ -756,7 +720,6 @@ const updateItem = async ({ reference, task, archive_all }: { reference?: number
|
|||
return
|
||||
}
|
||||
|
||||
// Check handler support for the new/updated task
|
||||
await checkHandlerSupport(createdOrUpdated)
|
||||
|
||||
if (!reference && true === archive_all && createdOrUpdated.id) {
|
||||
|
|
@ -799,29 +762,22 @@ const tryParse = (expression: string) => {
|
|||
}
|
||||
}
|
||||
|
||||
const runConfirm = () => {
|
||||
if (selectedElms.value.length < 1) {
|
||||
toast.error('No tasks selected.')
|
||||
return
|
||||
}
|
||||
dialog_confirm.value.visible = true
|
||||
dialog_confirm.value.title = 'Run Selected Tasks'
|
||||
|
||||
dialog_confirm.value.html_message = `Run the following tasks?<ul>` + selectedElms.value.map(id => {
|
||||
const item = tasks.value.find(t => t.id === id)
|
||||
return item ? `<li>${item.name}</li>` : ''
|
||||
}).join('') + `</ul>`
|
||||
|
||||
dialog_confirm.value.confirm = async () => await runSelected()
|
||||
}
|
||||
|
||||
const runSelected = async () => {
|
||||
if (selectedElms.value.length < 1) {
|
||||
toast.error('No tasks selected.')
|
||||
return
|
||||
}
|
||||
|
||||
dialog_confirm.value = reset_dialog()
|
||||
const { status } = await confirmDialog({
|
||||
rawHTML: `Run the following tasks?<ul>` + selectedElms.value.map(id => {
|
||||
const item = tasks.value.find(t => t.id === id)
|
||||
return item ? `<li>${item.name}</li>` : ''
|
||||
}).join('') + `</ul>`
|
||||
})
|
||||
|
||||
if (true !== status) {
|
||||
return
|
||||
}
|
||||
|
||||
massRun.value = true
|
||||
|
||||
|
|
@ -851,9 +807,14 @@ const runNow = async (item: TaskWithUI, mass: boolean = false) => {
|
|||
item.in_progress = true
|
||||
}
|
||||
|
||||
const data: Record<string, unknown> = {
|
||||
const data: item_request = {
|
||||
url: item.url,
|
||||
preset: item.preset,
|
||||
extras: {
|
||||
source_name: item.name,
|
||||
source_id: item.id,
|
||||
source_handler: "Web",
|
||||
}
|
||||
}
|
||||
|
||||
if (item.folder) {
|
||||
|
|
@ -868,7 +829,7 @@ const runNow = async (item: TaskWithUI, mass: boolean = false) => {
|
|||
data.cli = item.cli
|
||||
}
|
||||
|
||||
if (item?.auto_start !== undefined) {
|
||||
if (undefined !== item?.auto_start) {
|
||||
data.auto_start = item.auto_start
|
||||
}
|
||||
|
||||
|
|
@ -939,7 +900,7 @@ const archiveAll = async (item: TaskWithUI, by_pass: boolean = false) => {
|
|||
|
||||
try {
|
||||
if (true !== by_pass) {
|
||||
const { status } = await cDialog({
|
||||
const { status } = await confirmDialog({
|
||||
message: `Mark all '${item.name}' items as downloaded in download archive?`
|
||||
})
|
||||
|
||||
|
|
@ -965,7 +926,7 @@ const unarchiveAll = async (item: TaskWithUI) => {
|
|||
}
|
||||
|
||||
try {
|
||||
const { status } = await cDialog({
|
||||
const { status } = await confirmDialog({
|
||||
message: `Remove all '${item.name}' items from download archive?`
|
||||
})
|
||||
|
||||
|
|
@ -990,7 +951,7 @@ const generateMeta = async (item: TaskWithUI) => {
|
|||
}
|
||||
|
||||
try {
|
||||
const { status } = await cDialog({
|
||||
const { status } = await confirmDialog({
|
||||
rawHTML: `
|
||||
<p>
|
||||
Generate '${item.name}' metadata? you will be notified when it is done.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import type { item_request } from '~/types/item'
|
||||
import type { StoreItem } from '~/types/store'
|
||||
import { request } from '~/utils'
|
||||
|
||||
|
|
@ -211,7 +212,7 @@ export const useStateStore = defineStore('state', () => {
|
|||
* @param data - Download data (url, preset, folder, etc.)
|
||||
* @returns Promise that resolves when download is added
|
||||
*/
|
||||
const addDownload = async (data: Record<string, unknown>): Promise<void> => {
|
||||
const addDownload = async (data: item_request): Promise<void> => {
|
||||
const socket = useSocketStore()
|
||||
const toast = useNotification()
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@
|
|||
"dependencies": {
|
||||
"@microsoft/fetch-event-source": "^2.0.1",
|
||||
"@pinia/nuxt": "^0.11.3",
|
||||
"@vueuse/core": "^14.1.0",
|
||||
"@vueuse/nuxt": "^14.1.0",
|
||||
"@vueuse/core": "^14.2.0",
|
||||
"@vueuse/nuxt": "^14.2.0",
|
||||
"@xterm/addon-fit": "^0.11.0",
|
||||
"@xterm/xterm": "^6.0.0",
|
||||
"cron-parser": "^5.4.0",
|
||||
"cronstrue": "^3.9.0",
|
||||
"cron-parser": "^5.5.0",
|
||||
"cronstrue": "^3.11.0",
|
||||
"floating-vue": "^5.2.2",
|
||||
"hls.js": "^1.6.15",
|
||||
"marked": "^17.0.1",
|
||||
|
|
@ -34,10 +34,10 @@
|
|||
"marked-base-url": "^1.1.8",
|
||||
"marked-gfm-heading-id": "^4.1.3",
|
||||
"moment": "^2.30.1",
|
||||
"nuxt": "^4.2.2",
|
||||
"nuxt": "^4.3.0",
|
||||
"pinia": "^3.0.4",
|
||||
"vue": "^3.5.26",
|
||||
"vue-router": "^4.6.4",
|
||||
"vue": "^3.5.27",
|
||||
"vue-router": "^5.0.1",
|
||||
"vue-toastification": "2.0.0-rc.5"
|
||||
},
|
||||
"pnpm": {
|
||||
|
|
@ -53,13 +53,13 @@
|
|||
"ansi-regex": "6.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint": "^1.12.1",
|
||||
"@nuxt/eslint-config": "^1.12.1",
|
||||
"@typescript-eslint/parser": "^8.53.0",
|
||||
"@nuxt/eslint": "^1.13.0",
|
||||
"@nuxt/eslint-config": "^1.13.0",
|
||||
"@typescript-eslint/parser": "^8.54.0",
|
||||
"eslint": "^9.39.2",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.17",
|
||||
"vitest": "^4.0.18",
|
||||
"vue-eslint-parser": "^10.2.0",
|
||||
"vue-tsc": "^3.2.2"
|
||||
"vue-tsc": "^3.2.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2444
ui/pnpm-lock.yaml
2444
ui/pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
330
uv.lock
330
uv.lock
|
|
@ -146,7 +146,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "apprise"
|
||||
version = "1.9.6"
|
||||
version = "1.9.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
|
|
@ -157,9 +157,18 @@ dependencies = [
|
|||
{ name = "requests-oauthlib" },
|
||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a9/a7/bb182d81f35c3fe405505f0976da4b74f942cfdd53c7193b0fe50412aa27/apprise-1.9.6.tar.gz", hash = "sha256:4206be9cb5694a3d08dd8e0393bbb9b36212ac3a7769c2633620055e75c6caef", size = 1921714 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bc/f5/97dc06b3401bb67abcef6e8bef7155f192b75795c2a2aa4d59eb5aa7fa66/apprise-1.9.7.tar.gz", hash = "sha256:2f73cc1e0264fb119fdb9b7cde82e8fde40a0f531ac885d8c6f0cf0f6e13aec2", size = 1937173 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/39/df/343d125241f8cd3c9af58fd09688cf2bf59cc1edfd609adafef3556ce8ec/apprise-1.9.6-py3-none-any.whl", hash = "sha256:2fd18e8a5251b6a12f6f9d169f1d895d458d1de36a5faee4db149cedcce51674", size = 1452059 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/6b/cfa80a13437896eb8f4504ddac6dfa4ef7f1d2b2261057aa4a30003b8de6/apprise-1.9.7-py3-none-any.whl", hash = "sha256:c7640a81a1097685de66e0508e3da89f49235d566cb44bbead1dd98419bf5ee3", size = 1459879 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-generator"
|
||||
version = "1.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ce/b6/6fa6b3b598a03cba5e80f829e0dadbb49d7645f523d209b2fb7ea0bbb02a/async_generator-1.10.tar.gz", hash = "sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144", size = 29870 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/71/52/39d20e03abd0ac9159c162ec24b93fbcaa111e8400308f2465432495ca2b/async_generator-1.10-py3-none-any.whl", hash = "sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b", size = 18857 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -371,11 +380,11 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "cssselect"
|
||||
version = "1.3.0"
|
||||
version = "1.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/0a/c3ea9573b1dc2e151abfe88c7fe0c26d1892fe6ed02d0cdb30f0d57029d5/cssselect-1.3.0.tar.gz", hash = "sha256:57f8a99424cfab289a1b6a816a43075a4b00948c86b4dcf3ef4ee7e15f7ab0c7", size = 42870 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ec/2e/cdfd8b01c37cbf4f9482eefd455853a3cf9c995029a46acd31dfaa9c1dd6/cssselect-1.4.0.tar.gz", hash = "sha256:fdaf0a1425e17dfe8c5cf66191d211b357cf7872ae8afc4c6762ddd8ac47fc92", size = 40589 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/58/257350f7db99b4ae12b614a36256d9cc870d71d9e451e79c2dc3b23d7c3c/cssselect-1.3.0-py3-none-any.whl", hash = "sha256:56d1bf3e198080cc1667e137bc51de9cadfca259f03c2d4e09037b3e01e30f0d", size = 18786 },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/0c/7bb51e3acfafd16c48875bf3db03607674df16f5b6ef8d056586af7e2b8b/cssselect-1.4.0-py3-none-any.whl", hash = "sha256:c0ec5c0191c8ee39fcc8afc1540331d8b55b0183478c50e9c8a79d44dbceb1d8", size = 18540 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -401,7 +410,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "dateparser"
|
||||
version = "1.2.2"
|
||||
version = "1.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "python-dateutil" },
|
||||
|
|
@ -409,26 +418,26 @@ dependencies = [
|
|||
{ name = "regex" },
|
||||
{ name = "tzlocal" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a9/30/064144f0df1749e7bb5faaa7f52b007d7c2d08ec08fed8411aba87207f68/dateparser-1.2.2.tar.gz", hash = "sha256:986316f17cb8cdc23ea8ce563027c5ef12fc725b6fb1d137c14ca08777c5ecf7", size = 329840 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/2c/668dfb8c073a5dde3efb80fa382de1502e3b14002fd386a8c1b0b49e92a9/dateparser-1.3.0.tar.gz", hash = "sha256:5bccf5d1ec6785e5be71cc7ec80f014575a09b4923e762f850e57443bddbf1a5", size = 337152 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/87/22/f020c047ae1346613db9322638186468238bcfa8849b4668a22b97faad65/dateparser-1.2.2-py3-none-any.whl", hash = "sha256:5a5d7211a09013499867547023a2a0c91d5a27d15dd4dbcea676ea9fe66f2482", size = 315453 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/c7/95349670e193b2891176e1b8e5f43e12b31bff6d9994f70e74ab385047f6/dateparser-1.3.0-py3-none-any.whl", hash = "sha256:8dc678b0a526e103379f02ae44337d424bd366aac727d3c6cf52ce1b01efbb5a", size = 318688 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "debugpy"
|
||||
version = "1.8.19"
|
||||
version = "1.8.20"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/73/75/9e12d4d42349b817cd545b89247696c67917aab907012ae5b64bbfea3199/debugpy-1.8.19.tar.gz", hash = "sha256:eea7e5987445ab0b5ed258093722d5ecb8bb72217c5c9b1e21f64efe23ddebdb", size = 1644590 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/71/3d/388035a31a59c26f1ecc8d86af607d0c42e20ef80074147cd07b180c4349/debugpy-1.8.19-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:91e35db2672a0abaf325f4868fcac9c1674a0d9ad9bb8a8c849c03a5ebba3e6d", size = 2538859 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/19/c93a0772d0962294f083dbdb113af1a7427bb632d36e5314297068f55db7/debugpy-1.8.19-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:85016a73ab84dea1c1f1dcd88ec692993bcbe4532d1b49ecb5f3c688ae50c606", size = 4292575 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/56/09e48ab796b0a77e3d7dc250f95251832b8bf6838c9632f6100c98bdf426/debugpy-1.8.19-cp313-cp313-win32.whl", hash = "sha256:b605f17e89ba0ecee994391194285fada89cee111cfcd29d6f2ee11cbdc40976", size = 5286209 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/4e/931480b9552c7d0feebe40c73725dd7703dcc578ba9efc14fe0e6d31cfd1/debugpy-1.8.19-cp313-cp313-win_amd64.whl", hash = "sha256:c30639998a9f9cd9699b4b621942c0179a6527f083c72351f95c6ab1728d5b73", size = 5328206 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/b9/cbec520c3a00508327476c7fce26fbafef98f412707e511eb9d19a2ef467/debugpy-1.8.19-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:1e8c4d1bd230067bf1bbcdbd6032e5a57068638eb28b9153d008ecde288152af", size = 2537372 },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/5e/cf4e4dc712a141e10d58405c58c8268554aec3c35c09cdcda7535ff13f76/debugpy-1.8.19-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d40c016c1f538dbf1762936e3aeb43a89b965069d9f60f9e39d35d9d25e6b809", size = 4268729 },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/a3/c91a087ab21f1047db328c1d3eb5d1ff0e52de9e74f9f6f6fa14cdd93d58/debugpy-1.8.19-cp314-cp314-win32.whl", hash = "sha256:0601708223fe1cd0e27c6cce67a899d92c7d68e73690211e6788a4b0e1903f5b", size = 5286388 },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/b8/bfdc30b6e94f1eff09f2dc9cc1f9cd1c6cde3d996bcbd36ce2d9a4956e99/debugpy-1.8.19-cp314-cp314-win_amd64.whl", hash = "sha256:8e19a725f5d486f20e53a1dde2ab8bb2c9607c40c00a42ab646def962b41125f", size = 5327741 },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/3e/e27078370414ef35fafad2c06d182110073daaeb5d3bf734b0b1eeefe452/debugpy-1.8.19-py2.py3-none-any.whl", hash = "sha256:360ffd231a780abbc414ba0f005dad409e71c78637efe8f2bd75837132a41d38", size = 5292321 },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/e2/fc500524cc6f104a9d049abc85a0a8b3f0d14c0a39b9c140511c61e5b40b/debugpy-1.8.20-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:5dff4bb27027821fdfcc9e8f87309a28988231165147c31730128b1c983e282a", size = 2539560 },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/83/fb33dcea789ed6018f8da20c5a9bc9d82adc65c0c990faed43f7c955da46/debugpy-1.8.20-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:84562982dd7cf5ebebfdea667ca20a064e096099997b175fe204e86817f64eaf", size = 4293272 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/25/b1e4a01bfb824d79a6af24b99ef291e24189080c93576dfd9b1a2815cd0f/debugpy-1.8.20-cp313-cp313-win32.whl", hash = "sha256:da11dea6447b2cadbf8ce2bec59ecea87cc18d2c574980f643f2d2dfe4862393", size = 5331208 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/f7/a0b368ce54ffff9e9028c098bd2d28cfc5b54f9f6c186929083d4c60ba58/debugpy-1.8.20-cp313-cp313-win_amd64.whl", hash = "sha256:eb506e45943cab2efb7c6eafdd65b842f3ae779f020c82221f55aca9de135ed7", size = 5372930 },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/2e/f6cb9a8a13f5058f0a20fe09711a7b726232cd5a78c6a7c05b2ec726cff9/debugpy-1.8.20-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:9c74df62fc064cd5e5eaca1353a3ef5a5d50da5eb8058fcef63106f7bebe6173", size = 2538066 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/56/6ddca50b53624e1ca3ce1d1e49ff22db46c47ea5fb4c0cc5c9b90a616364/debugpy-1.8.20-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:077a7447589ee9bc1ff0cdf443566d0ecf540ac8aa7333b775ebcb8ce9f4ecad", size = 4269425 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/d9/d64199c14a0d4c476df46c82470a3ce45c8d183a6796cfb5e66533b3663c/debugpy-1.8.20-cp314-cp314-win32.whl", hash = "sha256:352036a99dd35053b37b7803f748efc456076f929c6a895556932eaf2d23b07f", size = 5331407 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/d9/1f07395b54413432624d61524dfd98c1a7c7827d2abfdb8829ac92638205/debugpy-1.8.20-cp314-cp314-win_amd64.whl", hash = "sha256:a98eec61135465b062846112e5ecf2eebb855305acc1dfbae43b72903b8ab5be", size = 5372521 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -515,33 +524,36 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "greenlet"
|
||||
version = "3.3.0"
|
||||
version = "3.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8a/99/1cd3411c56a410994669062bd73dd58270c00cc074cac15f385a1fd91f8a/greenlet-3.3.1.tar.gz", hash = "sha256:41848f3230b58c08bb43dee542e74a2a2e34d3c59dc3076cec9151aeeedcae98", size = 184690 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/02/2f/28592176381b9ab2cafa12829ba7b472d177f3acc35d8fbcf3673d966fff/greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739", size = 275140 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/80/fbe937bf81e9fca98c981fe499e59a3f45df2a04da0baa5c2be0dca0d329/greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808", size = 599219 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/ff/7c985128f0514271b8268476af89aee6866df5eec04ac17dcfbc676213df/greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54", size = 610211 },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/07/c47a82d881319ec18a4510bb30463ed6891f2ad2c1901ed5ec23d3de351f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492", size = 624311 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/8e/424b8c6e78bd9837d14ff7df01a9829fc883ba2ab4ea787d4f848435f23f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527", size = 612833 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/ba/56699ff9b7c76ca12f1cdc27a886d0f81f2189c3455ff9f65246780f713d/greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39", size = 1567256 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/37/f31136132967982d698c71a281a8901daf1a8fbab935dce7c0cf15f942cc/greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8", size = 1636483 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/71/ba21c3fb8c5dce83b8c01f458a42e99ffdb1963aeec08fff5a18588d8fd7/greenlet-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38", size = 301833 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/7c/f0a6d0ede2c7bf092d00bc83ad5bafb7e6ec9b4aab2fbdfa6f134dc73327/greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f", size = 275671 },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/06/dac639ae1a50f5969d82d2e3dd9767d30d6dbdbab0e1a54010c8fe90263c/greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365", size = 646360 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/94/0fb76fe6c5369fba9bf98529ada6f4c3a1adf19e406a47332245ef0eb357/greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3", size = 658160 },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/79/d2c70cae6e823fac36c3bbc9077962105052b7ef81db2f01ec3b9bf17e2b/greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45", size = 671388 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/14/bab308fc2c1b5228c3224ec2bf928ce2e4d21d8046c161e44a2012b5203e/greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955", size = 660166 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/d2/91465d39164eaa0085177f61983d80ffe746c5a1860f009811d498e7259c/greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55", size = 1615193 },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/1b/83d110a37044b92423084d52d5d5a3b3a73cafb51b547e6d7366ff62eff1/greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc", size = 1683653 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/9a/9030e6f9aa8fd7808e9c31ba4c38f87c4f8ec324ee67431d181fe396d705/greenlet-3.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170", size = 305387 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/66/bd6317bc5932accf351fc19f177ffba53712a202f9df10587da8df257c7e/greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931", size = 282638 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/cf/cc81cb030b40e738d6e69502ccbd0dd1bced0588e958f9e757945de24404/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388", size = 651145 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/ea/1020037b5ecfe95ca7df8d8549959baceb8186031da83d5ecceff8b08cd2/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3", size = 654236 },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/cc/1e4bae2e45ca2fa55299f4e85854606a78ecc37fead20d69322f96000504/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221", size = 662506 },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/b9/f8025d71a6085c441a7eaff0fd928bbb275a6633773667023d19179fe815/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b", size = 653783 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/c7/876a8c7a7485d5d6b5c6821201d542ef28be645aa024cfe1145b35c120c1/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd", size = 1614857 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/dc/041be1dff9f23dac5f48a43323cd0789cb798342011c19a248d9c9335536/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9", size = 1676034 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/ab/d26750f2b7242c2b90ea2ad71de70cfcd73a948a49513188a0fc0d6fc15a/greenlet-3.3.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:7ab327905cabb0622adca5971e488064e35115430cec2c35a50fd36e72a315b3", size = 275205 },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/d3/be7d19e8fad7c5a78eeefb2d896a08cd4643e1e90c605c4be3b46264998f/greenlet-3.3.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:65be2f026ca6a176f88fb935ee23c18333ccea97048076aef4db1ef5bc0713ac", size = 599284 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/21/fe703aaa056fdb0f17e5afd4b5c80195bbdab701208918938bd15b00d39b/greenlet-3.3.1-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7a3ae05b3d225b4155bda56b072ceb09d05e974bc74be6c3fc15463cf69f33fd", size = 610274 },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/00/95df0b6a935103c0452dad2203f5be8377e551b8466a29650c4c5a5af6cc/greenlet-3.3.1-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:12184c61e5d64268a160226fb4818af4df02cfead8379d7f8b99a56c3a54ff3e", size = 624375 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/86/5c6ab23bb3c28c21ed6bebad006515cfe08b04613eb105ca0041fecca852/greenlet-3.3.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6423481193bbbe871313de5fd06a082f2649e7ce6e08015d2a76c1e9186ca5b3", size = 612904 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/f3/7949994264e22639e40718c2daf6f6df5169bf48fb038c008a489ec53a50/greenlet-3.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:33a956fe78bbbda82bfc95e128d61129b32d66bcf0a20a1f0c08aa4839ffa951", size = 1567316 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/6e/d73c94d13b6465e9f7cd6231c68abde838bb22408596c05d9059830b7872/greenlet-3.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b065d3284be43728dd280f6f9a13990b56470b81be20375a207cdc814a983f2", size = 1636549 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/b3/c9c23a6478b3bcc91f979ce4ca50879e4d0b2bd7b9a53d8ecded719b92e2/greenlet-3.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:27289986f4e5b0edec7b5a91063c109f0276abb09a7e9bdab08437525977c946", size = 227042 },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/e7/824beda656097edee36ab15809fd063447b200cc03a7f6a24c34d520bc88/greenlet-3.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:2f080e028001c5273e0b42690eaf359aeef9cb1389da0f171ea51a5dc3c7608d", size = 226294 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/fb/011c7c717213182caf78084a9bea51c8590b0afda98001f69d9f853a495b/greenlet-3.3.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:bd59acd8529b372775cd0fcbc5f420ae20681c5b045ce25bd453ed8455ab99b5", size = 275737 },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/2e/a3a417d620363fdbb08a48b1dd582956a46a61bf8fd27ee8164f9dfe87c2/greenlet-3.3.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b31c05dd84ef6871dd47120386aed35323c944d86c3d91a17c4b8d23df62f15b", size = 646422 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/09/c6c4a0db47defafd2d6bab8ddfe47ad19963b4e30f5bed84d75328059f8c/greenlet-3.3.1-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:02925a0bfffc41e542c70aa14c7eda3593e4d7e274bfcccca1827e6c0875902e", size = 658219 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/89/b95f2ddcc5f3c2bc09c8ee8d77be312df7f9e7175703ab780f2014a0e781/greenlet-3.3.1-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3e0f3878ca3a3ff63ab4ea478585942b53df66ddde327b59ecb191b19dbbd62d", size = 671455 },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/38/9d42d60dffb04b45f03dbab9430898352dba277758640751dc5cc316c521/greenlet-3.3.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34a729e2e4e4ffe9ae2408d5ecaf12f944853f40ad724929b7585bca808a9d6f", size = 660237 },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/61/373c30b7197f9e756e4c81ae90a8d55dc3598c17673f91f4d31c3c689c3f/greenlet-3.3.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aec9ab04e82918e623415947921dea15851b152b822661cce3f8e4393c3df683", size = 1615261 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/d3/ca534310343f5945316f9451e953dcd89b36fe7a19de652a1dc5a0eeef3f/greenlet-3.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:71c767cf281a80d02b6c1bdc41c9468e1f5a494fb11bc8688c360524e273d7b1", size = 1683719 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/cb/c21a3fd5d2c9c8b622e7bede6d6d00e00551a5ee474ea6d831b5f567a8b4/greenlet-3.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:96aff77af063b607f2489473484e39a0bbae730f2ea90c9e5606c9b73c44174a", size = 228125 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/8e/8a2db6d11491837af1de64b8aff23707c6e85241be13c60ed399a72e2ef8/greenlet-3.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:b066e8b50e28b503f604fa538adc764a638b38cf8e81e025011d26e8a627fa79", size = 227519 },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/24/cbbec49bacdcc9ec652a81d3efef7b59f326697e7edf6ed775a5e08e54c2/greenlet-3.3.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:3e63252943c921b90abb035ebe9de832c436401d9c45f262d80e2d06cc659242", size = 282706 },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/2e/4f2b9323c144c4fe8842a4e0d92121465485c3c2c5b9e9b30a52e80f523f/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:76e39058e68eb125de10c92524573924e827927df5d3891fbc97bd55764a8774", size = 651209 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/87/50ca60e515f5bb55a2fbc5f0c9b5b156de7d2fc51a0a69abc9d23914a237/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9f9d5e7a9310b7a2f416dd13d2e3fd8b42d803968ea580b7c0f322ccb389b97", size = 654300 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/25/c51a63f3f463171e09cb586eb64db0861eb06667ab01a7968371a24c4f3b/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b9721549a95db96689458a1e0ae32412ca18776ed004463df3a9299c1b257ab", size = 662574 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/94/74310866dfa2b73dd08659a3d18762f83985ad3281901ba0ee9a815194fb/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92497c78adf3ac703b57f1e3813c2d874f27f71a178f9ea5887855da413cd6d2", size = 653842 },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/43/8bf0ffa3d498eeee4c58c212a3905dd6146c01c8dc0b0a046481ca29b18c/greenlet-3.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ed6b402bc74d6557a705e197d47f9063733091ed6357b3de33619d8a8d93ac53", size = 1614917 },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/90/a3be7a5f378fc6e84abe4dcfb2ba32b07786861172e502388b4c90000d1b/greenlet-3.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:59913f1e5ada20fde795ba906916aea25d442abcc0593fba7e26c92b7ad76249", size = 1676092 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/2b/98c7f93e6db9977aaee07eb1e51ca63bd5f779b900d362791d3252e60558/greenlet-3.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:301860987846c24cb8964bdec0e31a96ad4a2a801b41b4ef40963c1b44f33451", size = 233181 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -662,6 +674,18 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "8.7.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "zipp" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.3.0"
|
||||
|
|
@ -673,11 +697,11 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "jmespath"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -783,11 +807,11 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "markdown"
|
||||
version = "3.10"
|
||||
version = "3.10.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/7dd27d9d863b3376fcf23a5a13cb5d024aed1db46f963f1b5735ae43b3be/markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e", size = 364931 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b7/b1/af95bcae8549f1f3fd70faacb29075826a0d689a27f232e8cee315efa053/markdown-3.10.1.tar.gz", hash = "sha256:1c19c10bd5c14ac948c53d0d762a04e2fa35a6d58a6b7b1e6bfcbe6fefc0001a", size = 365402 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/70/81/54e3ce63502cd085a0c556652a4e1b919c45a446bd1e5300e10c44c8c521/markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c", size = 107678 },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/1b/6ef961f543593969d25b2afe57a3564200280528caa9bd1082eecdd7b3bc/markdown-3.10.1-py3-none-any.whl", hash = "sha256:867d788939fe33e4b736426f5b9f651ad0c0ae0ecf89df0ca5d1176c70812fe3", size = 107684 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -840,6 +864,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/b0/7a/620f945b96be1f6ee357d211d5bf74ab1b7fe72a9f1525aafbfe3aee6875/mutagen-1.47.0-py3-none-any.whl", hash = "sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719", size = 194391 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oauthlib"
|
||||
version = "3.3.1"
|
||||
|
|
@ -863,16 +896,16 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "25.0"
|
||||
version = "26.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parsel"
|
||||
version = "1.10.0"
|
||||
version = "1.11.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cssselect" },
|
||||
|
|
@ -881,9 +914,9 @@ dependencies = [
|
|||
{ name = "packaging" },
|
||||
{ name = "w3lib" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f6/df/acd504c154c0b9028b0d8491a77fdd5f86e9c06ee04f986abf85e36d9a5f/parsel-1.10.0.tar.gz", hash = "sha256:14f17db9559f51b43357b9dfe43cec870a8efb5ea4857abb624ec6ff80d8a080", size = 51421 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/91/c8/4ace3a5c61e39ca21734a5715d0e076eea6200dd8daea2a5b99452f5a0d6/parsel-1.11.0.tar.gz", hash = "sha256:5925fe087eb16fc404a7ed91e31e2c1e2a9b230da4b64f34d81358c0d0e27e88", size = 106849 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/12/18/35d1d947553d24909dca37e2ff11720eecb601360d1bac8d7a9a1bc7eb08/parsel-1.10.0-py2.py3-none-any.whl", hash = "sha256:6a0c28bd81f9df34ba665884c88efa0b18b8d2c44c81f64e27f2f0cb37d46169", size = 17266 },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/23/4e0dae5e5bee14aea26dba003a682e621563451a20f751ed985810f818b6/parsel-1.11.0-py3-none-any.whl", hash = "sha256:bda82575df1774dd64e1c1396163f3cadb3e383e0f8080d43d45fa6705355daa", size = 14176 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -895,6 +928,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl", hash = "sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f", size = 74766 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pip"
|
||||
version = "26.0.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/48/83/0d7d4e9efe3344b8e2fe25d93be44f64b65364d3c8d7bc6dc90198d5422e/pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8", size = 1812747 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b", size = 1787723 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.5.1"
|
||||
|
|
@ -984,11 +1026,11 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.23"
|
||||
version = "3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1158,15 +1200,15 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "pyinstaller-hooks-contrib"
|
||||
version = "2025.11"
|
||||
version = "2026.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "packaging" },
|
||||
{ name = "setuptools" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/45/2f/2c68b6722d233dae3e5243751aafc932940b836919cfaca22dd0c60d417c/pyinstaller_hooks_contrib-2025.11.tar.gz", hash = "sha256:dfe18632e06655fa88d218e0d768fd753e1886465c12a6d4bce04f1aaeec917d", size = 169183 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/31/8f/8052ff65067697ee80fde45b9731842e160751c41ac5690ba232c22030e8/pyinstaller_hooks_contrib-2026.0.tar.gz", hash = "sha256:0120893de491a000845470ca9c0b39284731ac6bace26f6849dea9627aaed48e", size = 170311 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/c4/3a096c6e701832443b957b9dac18a163103360d0c7f5842ca41695371148/pyinstaller_hooks_contrib-2025.11-py3-none-any.whl", hash = "sha256:777e163e2942474aa41a8e6d31ac1635292d63422c3646c176d584d04d971c34", size = 449478 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/b1/9da6ec3e88696018ee7bb9dc4a7310c2cfaebf32923a19598cd342767c10/pyinstaller_hooks_contrib-2026.0-py3-none-any.whl", hash = "sha256:0590db8edeba3e6c30c8474937021f5cd39c0602b4d10f74a064c73911efaca5", size = 452318 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1566,54 +1608,56 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.14.13"
|
||||
version = "0.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/50/0a/1914efb7903174b381ee2ffeebb4253e729de57f114e63595114c8ca451f/ruff-0.14.13.tar.gz", hash = "sha256:83cd6c0763190784b99650a20fec7633c59f6ebe41c5cc9d45ee42749563ad47", size = 6059504 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c8/39/5cee96809fbca590abea6b46c6d1c586b49663d1d2830a751cc8fc42c666/ruff-0.15.0.tar.gz", hash = "sha256:6bdea47cdbea30d40f8f8d7d69c0854ba7c15420ec75a26f463290949d7f7e9a", size = 4524893 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/ae/0deefbc65ca74b0ab1fd3917f94dc3b398233346a74b8bbb0a916a1a6bf6/ruff-0.14.13-py3-none-linux_armv6l.whl", hash = "sha256:76f62c62cd37c276cb03a275b198c7c15bd1d60c989f944db08a8c1c2dbec18b", size = 13062418 },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/df/5916604faa530a97a3c154c62a81cb6b735c0cb05d1e26d5ad0f0c8ac48a/ruff-0.14.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:914a8023ece0528d5cc33f5a684f5f38199bbb566a04815c2c211d8f40b5d0ed", size = 13442344 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/f3/e0e694dd69163c3a1671e102aa574a50357536f18a33375050334d5cd517/ruff-0.14.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d24899478c35ebfa730597a4a775d430ad0d5631b8647a3ab368c29b7e7bd063", size = 12354720 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/e8/67f5fcbbaee25e8fc3b56cc33e9892eca7ffe09f773c8e5907757a7e3bdb/ruff-0.14.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aaf3870f14d925bbaf18b8a2347ee0ae7d95a2e490e4d4aea6813ed15ebc80e", size = 12774493 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/ce/d2e9cb510870b52a9565d885c0d7668cc050e30fa2c8ac3fb1fda15c083d/ruff-0.14.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac5b7f63dd3b27cc811850f5ffd8fff845b00ad70e60b043aabf8d6ecc304e09", size = 12815174 },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/00/c38e5da58beebcf4fa32d0ddd993b63dfacefd02ab7922614231330845bf/ruff-0.14.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2b1097750d90ba82ce4ba676e85230a0ed694178ca5e61aa9b459970b3eb9", size = 13680909 },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/61/cd37c9dd5bd0a3099ba79b2a5899ad417d8f3b04038810b0501a80814fd7/ruff-0.14.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d0bf87705acbbcb8d4c24b2d77fbb73d40210a95c3903b443cd9e30824a5032", size = 15144215 },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/8a/85502d7edbf98c2df7b8876f316c0157359165e16cdf98507c65c8d07d3d/ruff-0.14.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3eb5da8e2c9e9f13431032fdcbe7681de9ceda5835efee3269417c13f1fed5c", size = 14706067 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/2f/de0df127feb2ee8c1e54354dc1179b4a23798f0866019528c938ba439aca/ruff-0.14.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:642442b42957093811cd8d2140dfadd19c7417030a7a68cf8d51fcdd5f217427", size = 14133916 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/77/9b99686bb9fe07a757c82f6f95e555c7a47801a9305576a9c67e0a31d280/ruff-0.14.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4acdf009f32b46f6e8864af19cbf6841eaaed8638e65c8dac845aea0d703c841", size = 13859207 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/46/2bdcb34a87a179a4d23022d818c1c236cb40e477faf0d7c9afb6813e5876/ruff-0.14.13-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:591a7f68860ea4e003917d19b5c4f5ac39ff558f162dc753a2c5de897fd5502c", size = 14043686 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/a9/5c6a4f56a0512c691cf143371bcf60505ed0f0860f24a85da8bd123b2bf1/ruff-0.14.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:774c77e841cc6e046fc3e91623ce0903d1cd07e3a36b1a9fe79b81dab3de506b", size = 12663837 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/bb/b920016ece7651fa7fcd335d9d199306665486694d4361547ccb19394c44/ruff-0.14.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:61f4e40077a1248436772bb6512db5fc4457fe4c49e7a94ea7c5088655dd21ae", size = 12805867 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/b3/0bd909851e5696cd21e32a8fc25727e5f58f1934b3596975503e6e85415c/ruff-0.14.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6d02f1428357fae9e98ac7aa94b7e966fd24151088510d32cf6f902d6c09235e", size = 13208528 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/3b/e2d94cb613f6bbd5155a75cbe072813756363eba46a3f2177a1fcd0cd670/ruff-0.14.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e399341472ce15237be0c0ae5fbceca4b04cd9bebab1a2b2c979e015455d8f0c", size = 13929242 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/c5/abd840d4132fd51a12f594934af5eba1d5d27298a6f5b5d6c3be45301caf/ruff-0.14.13-py3-none-win32.whl", hash = "sha256:ef720f529aec113968b45dfdb838ac8934e519711da53a0456038a0efecbd680", size = 12919024 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/55/6384b0b8ce731b6e2ade2b5449bf07c0e4c31e8a2e68ea65b3bafadcecc5/ruff-0.14.13-py3-none-win_amd64.whl", hash = "sha256:6070bd026e409734b9257e03e3ef18c6e1a216f0435c6751d7a8ec69cb59abef", size = 14097887 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/e1/7348090988095e4e39560cfc2f7555b1b2a7357deba19167b600fdf5215d/ruff-0.14.13-py3-none-win_arm64.whl", hash = "sha256:7ab819e14f1ad9fe39f246cfcc435880ef7a9390d81a2b6ac7e01039083dd247", size = 13080224 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/88/3fd1b0aa4b6330d6aaa63a285bc96c9f71970351579152d231ed90914586/ruff-0.15.0-py3-none-linux_armv6l.whl", hash = "sha256:aac4ebaa612a82b23d45964586f24ae9bc23ca101919f5590bdb368d74ad5455", size = 10354332 },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/f6/62e173fbb7eb75cc29fe2576a1e20f0a46f671a2587b5f604bfb0eaf5f6f/ruff-0.15.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dcd4be7cc75cfbbca24a98d04d0b9b36a270d0833241f776b788d59f4142b14d", size = 10767189 },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/e4/968ae17b676d1d2ff101d56dc69cf333e3a4c985e1ec23803df84fc7bf9e/ruff-0.15.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d747e3319b2bce179c7c1eaad3d884dc0a199b5f4d5187620530adf9105268ce", size = 10075384 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/bf/9843c6044ab9e20af879c751487e61333ca79a2c8c3058b15722386b8cae/ruff-0.15.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:650bd9c56ae03102c51a5e4b554d74d825ff3abe4db22b90fd32d816c2e90621", size = 10481363 },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/d9/4ada5ccf4cd1f532db1c8d44b6f664f2208d3d93acbeec18f82315e15193/ruff-0.15.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6664b7eac559e3048223a2da77769c2f92b43a6dfd4720cef42654299a599c9", size = 10187736 },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/e2/f25eaecd446af7bb132af0a1d5b135a62971a41f5366ff41d06d25e77a91/ruff-0.15.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f811f97b0f092b35320d1556f3353bf238763420ade5d9e62ebd2b73f2ff179", size = 10968415 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/dc/f06a8558d06333bf79b497d29a50c3a673d9251214e0d7ec78f90b30aa79/ruff-0.15.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:761ec0a66680fab6454236635a39abaf14198818c8cdf691e036f4bc0f406b2d", size = 11809643 },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/45/0ece8db2c474ad7df13af3a6d50f76e22a09d078af63078f005057ca59eb/ruff-0.15.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:940f11c2604d317e797b289f4f9f3fa5555ffe4fb574b55ed006c3d9b6f0eb78", size = 11234787 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/d9/0e3a81467a120fd265658d127db648e4d3acfe3e4f6f5d4ea79fac47e587/ruff-0.15.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcbca3d40558789126da91d7ef9a7c87772ee107033db7191edefa34e2c7f1b4", size = 11112797 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/cb/8c0b3b0c692683f8ff31351dfb6241047fa873a4481a76df4335a8bff716/ruff-0.15.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9a121a96db1d75fa3eb39c4539e607f628920dd72ff1f7c5ee4f1b768ac62d6e", size = 11033133 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/5e/23b87370cf0f9081a8c89a753e69a4e8778805b8802ccfe175cc410e50b9/ruff-0.15.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5298d518e493061f2eabd4abd067c7e4fb89e2f63291c94332e35631c07c3662", size = 10442646 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/9a/3c94de5ce642830167e6d00b5c75aacd73e6347b4c7fc6828699b150a5ee/ruff-0.15.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:afb6e603d6375ff0d6b0cee563fa21ab570fd15e65c852cb24922cef25050cf1", size = 10195750 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/15/e396325080d600b436acc970848d69df9c13977942fb62bb8722d729bee8/ruff-0.15.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:77e515f6b15f828b94dc17d2b4ace334c9ddb7d9468c54b2f9ed2b9c1593ef16", size = 10676120 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/c9/229a23d52a2983de1ad0fb0ee37d36e0257e6f28bfd6b498ee2c76361874/ruff-0.15.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6f6e80850a01eb13b3e42ee0ebdf6e4497151b48c35051aab51c101266d187a3", size = 11201636 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/b0/69adf22f4e24f3677208adb715c578266842e6e6a3cc77483f48dd999ede/ruff-0.15.0-py3-none-win32.whl", hash = "sha256:238a717ef803e501b6d51e0bdd0d2c6e8513fe9eec14002445134d3907cd46c3", size = 10465945 },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/ad/f813b6e2c97e9b4598be25e94a9147b9af7e60523b0cb5d94d307c15229d/ruff-0.15.0-py3-none-win_amd64.whl", hash = "sha256:dd5e4d3301dc01de614da3cdffc33d4b1b96fb89e45721f1598e5532ccf78b18", size = 11564657 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/b0/2d823f6e77ebe560f4e397d078487e8d52c1516b331e3521bc75db4272ca/ruff-0.15.0-py3-none-win_arm64.whl", hash = "sha256:c480d632cc0ca3f0727acac8b7d053542d9e114a462a145d0b00e7cd658c515a", size = 10865753 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "selenium"
|
||||
version = "4.39.0"
|
||||
version = "4.40.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "trio" },
|
||||
{ name = "trio-typing" },
|
||||
{ name = "trio-websocket" },
|
||||
{ name = "types-certifi" },
|
||||
{ name = "types-urllib3" },
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "urllib3", extra = ["socks"] },
|
||||
{ name = "websocket-client" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/af/19/27c1bf9eb1f7025632d35a956b50746efb4b10aa87f961b263fa7081f4c5/selenium-4.39.0.tar.gz", hash = "sha256:12f3325f02d43b6c24030fc9602b34a3c6865abbb1db9406641d13d108aa1889", size = 928575 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/66/ef/a5727fa7b33d20d296322adf851b76072d8d3513e1b151969d3228437faf/selenium-4.40.0.tar.gz", hash = "sha256:a88f5905d88ad0b84991c2386ea39e2bbde6d6c334be38df5842318ba98eaa8c", size = 930444 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/58/d0/55a6b7c6f35aad4c8a54be0eb7a52c1ff29a59542fc3e655f0ecbb14456d/selenium-4.39.0-py3-none-any.whl", hash = "sha256:c85f65d5610642ca0f47dae9d5cc117cd9e831f74038bc09fe1af126288200f9", size = 9655249 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/74/eb9d6540aca1911106fa0877b8e9ef24171bc18857937a6b0ffe0586c623/selenium-4.40.0-py3-none-any.whl", hash = "sha256:c8823fc02e2c771d9ad9a0cf899cee7de1a57a6697e3d0b91f67566129f2b729", size = 9608184 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "80.9.0"
|
||||
version = "80.10.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/76/95/faf61eb8363f26aa7e1d762267a8d602a1b26d4f3a1e758e92cb3cb8b054/setuptools-80.10.2.tar.gz", hash = "sha256:8b0e9d10c784bf7d262c4e5ec5d4ec94127ce206e8738f29a437945fbc219b70", size = 1200343 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486 },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/b8/f1f62a5e3c0ad2ff1d189590bfa4c46b4f3b6e49cef6f26c6ee4e575394d/setuptools-80.10.2-py3-none-any.whl", hash = "sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173", size = 1064234 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1654,31 +1698,37 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlalchemy"
|
||||
version = "2.0.45"
|
||||
version = "2.0.46"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/be/f9/5e4491e5ccf42f5d9cfc663741d261b3e6e1683ae7812114e7636409fcc6/sqlalchemy-2.0.45.tar.gz", hash = "sha256:1632a4bda8d2d25703fdad6363058d882541bdaaee0e5e3ddfa0cd3229efce88", size = 9869912 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/06/aa/9ce0f3e7a9829ead5c8ce549392f33a12c4555a6c0609bb27d882e9c7ddf/sqlalchemy-2.0.46.tar.gz", hash = "sha256:cf36851ee7219c170bb0793dbc3da3e80c582e04a5437bc601bfe8c85c9216d7", size = 9865393 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/c8/7cc5221b47a54edc72a0140a1efa56e0a2730eefa4058d7ed0b4c4357ff8/sqlalchemy-2.0.45-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe187fc31a54d7fd90352f34e8c008cf3ad5d064d08fedd3de2e8df83eb4a1cf", size = 3277082 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/50/80a8d080ac7d3d321e5e5d420c9a522b0aa770ec7013ea91f9a8b7d36e4a/sqlalchemy-2.0.45-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:672c45cae53ba88e0dad74b9027dddd09ef6f441e927786b05bec75d949fbb2e", size = 3293131 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/4c/13dab31266fc9904f7609a5dc308a2432a066141d65b857760c3bef97e69/sqlalchemy-2.0.45-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:470daea2c1ce73910f08caf10575676a37159a6d16c4da33d0033546bddebc9b", size = 3225389 },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/04/891b5c2e9f83589de202e7abaf24cd4e4fa59e1837d64d528829ad6cc107/sqlalchemy-2.0.45-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9c6378449e0940476577047150fd09e242529b761dc887c9808a9a937fe990c8", size = 3266054 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/24/fc59e7f71b0948cdd4cff7a286210e86b0443ef1d18a23b0d83b87e4b1f7/sqlalchemy-2.0.45-cp313-cp313-win32.whl", hash = "sha256:4b6bec67ca45bc166c8729910bd2a87f1c0407ee955df110d78948f5b5827e8a", size = 2110299 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/c5/d17113020b2d43073412aeca09b60d2009442420372123b8d49cc253f8b8/sqlalchemy-2.0.45-cp313-cp313-win_amd64.whl", hash = "sha256:afbf47dc4de31fa38fd491f3705cac5307d21d4bb828a4f020ee59af412744ee", size = 2136264 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/8d/bb40a5d10e7a5f2195f235c0b2f2c79b0bf6e8f00c0c223130a4fbd2db09/sqlalchemy-2.0.45-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83d7009f40ce619d483d26ac1b757dfe3167b39921379a8bd1b596cf02dab4a6", size = 3521998 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/a5/346128b0464886f036c039ea287b7332a410aa2d3fb0bb5d404cb8861635/sqlalchemy-2.0.45-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d8a2ca754e5415cde2b656c27900b19d50ba076aa05ce66e2207623d3fe41f5a", size = 3473434 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/64/4e1913772646b060b025d3fc52ce91a58967fe58957df32b455de5a12b4f/sqlalchemy-2.0.45-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f46ec744e7f51275582e6a24326e10c49fbdd3fc99103e01376841213028774", size = 3272404 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/27/caf606ee924282fe4747ee4fd454b335a72a6e018f97eab5ff7f28199e16/sqlalchemy-2.0.45-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:883c600c345123c033c2f6caca18def08f1f7f4c3ebeb591a63b6fceffc95cce", size = 3277057 },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/d0/3d64218c9724e91f3d1574d12eb7ff8f19f937643815d8daf792046d88ab/sqlalchemy-2.0.45-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2c0b74aa79e2deade948fe8593654c8ef4228c44ba862bb7c9585c8e0db90f33", size = 3222279 },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/10/dd7688a81c5bc7690c2a3764d55a238c524cd1a5a19487928844cb247695/sqlalchemy-2.0.45-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8a420169cef179d4c9064365f42d779f1e5895ad26ca0c8b4c0233920973db74", size = 3244508 },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/41/db75756ca49f777e029968d9c9fee338c7907c563267740c6d310a8e3f60/sqlalchemy-2.0.45-cp314-cp314-win32.whl", hash = "sha256:e50dcb81a5dfe4b7b4a4aa8f338116d127cb209559124f3694c70d6cd072b68f", size = 2113204 },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/a2/0e1590e9adb292b1d576dbcf67ff7df8cf55e56e78d2c927686d01080f4b/sqlalchemy-2.0.45-cp314-cp314-win_amd64.whl", hash = "sha256:4748601c8ea959e37e03d13dcda4a44837afcd1b21338e637f7c935b8da06177", size = 2138785 },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/39/f05f0ed54d451156bbed0e23eb0516bcad7cbb9f18b3bf219c786371b3f0/sqlalchemy-2.0.45-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd337d3526ec5298f67d6a30bbbe4ed7e5e68862f0bf6dd21d289f8d37b7d60b", size = 3522029 },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/0f/d15398b98b65c2bce288d5ee3f7d0a81f77ab89d9456994d5c7cc8b2a9db/sqlalchemy-2.0.45-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9a62b446b7d86a3909abbcd1cd3cc550a832f99c2bc37c5b22e1925438b9367b", size = 3475142 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/e1/3ccb13c643399d22289c6a9786c1a91e3dcbb68bce4beb44926ac2c557bf/sqlalchemy-2.0.45-py3-none-any.whl", hash = "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0", size = 1936672 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/4b/fa7838fe20bb752810feed60e45625a9a8b0102c0c09971e2d1d95362992/sqlalchemy-2.0.46-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:93a12da97cca70cea10d4b4fc602589c4511f96c1f8f6c11817620c021d21d00", size = 2150268 },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/c1/b34dccd712e8ea846edf396e00973dda82d598cb93762e55e43e6835eba9/sqlalchemy-2.0.46-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af865c18752d416798dae13f83f38927c52f085c52e2f32b8ab0fef46fdd02c2", size = 3276511 },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/48/a04d9c94753e5d5d096c628c82a98c4793b9c08ca0e7155c3eb7d7db9f24/sqlalchemy-2.0.46-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8d679b5f318423eacb61f933a9a0f75535bfca7056daeadbf6bd5bcee6183aee", size = 3292881 },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/f4/06eda6e91476f90a7d8058f74311cb65a2fb68d988171aced81707189131/sqlalchemy-2.0.46-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64901e08c33462acc9ec3bad27fc7a5c2b6491665f2aa57564e57a4f5d7c52ad", size = 3224559 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/a2/d2af04095412ca6345ac22b33b89fe8d6f32a481e613ffcb2377d931d8d0/sqlalchemy-2.0.46-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e8ac45e8f4eaac0f9f8043ea0e224158855c6a4329fd4ee37c45c61e3beb518e", size = 3262728 },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/48/1980c7caa5978a3b8225b4d230e69a2a6538a3562b8b31cea679b6933c83/sqlalchemy-2.0.46-cp313-cp313-win32.whl", hash = "sha256:8d3b44b3d0ab2f1319d71d9863d76eeb46766f8cf9e921ac293511804d39813f", size = 2111295 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/54/f8d65bbde3d877617c4720f3c9f60e99bb7266df0d5d78b6e25e7c149f35/sqlalchemy-2.0.46-cp313-cp313-win_amd64.whl", hash = "sha256:77f8071d8fbcbb2dd11b7fd40dedd04e8ebe2eb80497916efedba844298065ef", size = 2137076 },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/ba/9be4f97c7eb2b9d5544f2624adfc2853e796ed51d2bb8aec90bc94b7137e/sqlalchemy-2.0.46-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1e8cc6cc01da346dc92d9509a63033b9b1bda4fed7a7a7807ed385c7dccdc10", size = 3556533 },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/a6/b1fc6634564dbb4415b7ed6419cdfeaadefd2c39cdab1e3aa07a5f2474c2/sqlalchemy-2.0.46-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:96c7cca1a4babaaf3bfff3e4e606e38578856917e52f0384635a95b226c87764", size = 3523208 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/d8/41e0bdfc0f930ff236f86fccd12962d8fa03713f17ed57332d38af6a3782/sqlalchemy-2.0.46-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b2a9f9aee38039cf4755891a1e50e1effcc42ea6ba053743f452c372c3152b1b", size = 3464292 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/8b/9dcbec62d95bea85f5ecad9b8d65b78cc30fb0ffceeb3597961f3712549b/sqlalchemy-2.0.46-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:db23b1bf8cfe1f7fda19018e7207b20cdb5168f83c437ff7e95d19e39289c447", size = 3473497 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/f8/5ecdfc73383ec496de038ed1614de9e740a82db9ad67e6e4514ebc0708a3/sqlalchemy-2.0.46-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:56bdd261bfd0895452006d5316cbf35739c53b9bb71a170a331fa0ea560b2ada", size = 2152079 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/bf/eba3036be7663ce4d9c050bc3d63794dc29fbe01691f2bf5ccb64e048d20/sqlalchemy-2.0.46-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33e462154edb9493f6c3ad2125931e273bbd0be8ae53f3ecd1c161ea9a1dd366", size = 3272216 },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/45/1256fb597bb83b58a01ddb600c59fe6fdf0e5afe333f0456ed75c0f8d7bd/sqlalchemy-2.0.46-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bcdce05f056622a632f1d44bb47dbdb677f58cad393612280406ce37530eb6d", size = 3277208 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/a0/2053b39e4e63b5d7ceb3372cface0859a067c1ddbd575ea7e9985716f771/sqlalchemy-2.0.46-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e84b09a9b0f19accedcbeff5c2caf36e0dd537341a33aad8d680336152dc34e", size = 3221994 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/87/97713497d9502553c68f105a1cb62786ba1ee91dea3852ae4067ed956a50/sqlalchemy-2.0.46-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4f52f7291a92381e9b4de9050b0a65ce5d6a763333406861e33906b8aa4906bf", size = 3243990 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/87/5d1b23548f420ff823c236f8bea36b1a997250fd2f892e44a3838ca424f4/sqlalchemy-2.0.46-cp314-cp314-win32.whl", hash = "sha256:70ed2830b169a9960193f4d4322d22be5c0925357d82cbf485b3369893350908", size = 2114215 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/20/555f39cbcf0c10cf452988b6a93c2a12495035f68b3dbd1a408531049d31/sqlalchemy-2.0.46-cp314-cp314-win_amd64.whl", hash = "sha256:3c32e993bc57be6d177f7d5d31edb93f30726d798ad86ff9066d75d9bf2e0b6b", size = 2139867 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/f0/f96c8057c982d9d8a7a68f45d69c674bc6f78cad401099692fe16521640a/sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4dafb537740eef640c4d6a7c254611dca2df87eaf6d14d6a5fca9d1f4c3fc0fa", size = 3561202 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/53/3b37dda0a5b137f21ef608d8dfc77b08477bab0fe2ac9d3e0a66eaeab6fc/sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42a1643dc5427b69aca967dae540a90b0fbf57eaf248f13a90ea5930e0966863", size = 3526296 },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/75/f28622ba6dde79cd545055ea7bd4062dc934e0621f7b3be2891f8563f8de/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ff33c6e6ad006bbc0f34f5faf941cfc62c45841c64c0a058ac38c799f15b5ede", size = 3470008 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/42/4afecbbc38d5e99b18acef446453c76eec6fbd03db0a457a12a056836e22/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:82ec52100ec1e6ec671563bbd02d7c7c8d0b9e71a0723c72f22ecf52d1755330", size = 3476137 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/a1/9c4efa03300926601c19c18582531b45aededfb961ab3c3585f1e24f120b/sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e", size = 1937882 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1698,6 +1748,23 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/41/bf/945d527ff706233636c73880b22c7c953f3faeb9d6c7e2e85bfbfd0134a0/trio-0.32.0-py3-none-any.whl", hash = "sha256:4ab65984ef8370b79a76659ec87aa3a30c5c7c83ff250b4de88c29a8ab6123c5", size = 512030 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trio-typing"
|
||||
version = "0.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "async-generator" },
|
||||
{ name = "importlib-metadata" },
|
||||
{ name = "mypy-extensions" },
|
||||
{ name = "packaging" },
|
||||
{ name = "trio" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b5/74/a87aafa40ec3a37089148b859892cbe2eef08d132c816d58a60459be5337/trio-typing-0.10.0.tar.gz", hash = "sha256:065ee684296d52a8ab0e2374666301aec36ee5747ac0e7a61f230250f8907ac3", size = 38747 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/89/ff/9bd795273eb14fac7f6a59d16cc8c4d0948a619a1193d375437c7f50f3eb/trio_typing-0.10.0-py3-none-any.whl", hash = "sha256:6d0e7ec9d837a2fe03591031a172533fbf4a1a95baf369edebfc51d5a49f0264", size = 42224 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trio-websocket"
|
||||
version = "0.12.2"
|
||||
|
|
@ -1712,6 +1779,24 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/c7/19/eb640a397bba49ba49ef9dbe2e7e5c04202ba045b6ce2ec36e9cadc51e04/trio_websocket-0.12.2-py3-none-any.whl", hash = "sha256:df605665f1db533f4a386c94525870851096a223adcb97f72a07e8b4beba45b6", size = 21221 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-certifi"
|
||||
version = "2021.10.8.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/52/68/943c3aeaf14624712a0357c4a67814dba5cea36d194f5c764dad7959a00c/types-certifi-2021.10.8.3.tar.gz", hash = "sha256:72cf7798d165bc0b76e1c10dd1ea3097c7063c42c21d664523b928e88b554a4f", size = 2095 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/63/2463d89481e811f007b0e1cd0a91e52e141b47f9de724d20db7b861dcfec/types_certifi-2021.10.8.3-py3-none-any.whl", hash = "sha256:b2d1e325e69f71f7c78e5943d410e650b4707bb0ef32e4ddf3da37f54176e88a", size = 2136 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-urllib3"
|
||||
version = "1.26.25.14"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/73/de/b9d7a68ad39092368fb21dd6194b362b98a1daeea5dcfef5e1adb5031c7e/types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f", size = 11239 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e", size = 15377 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
|
|
@ -1770,11 +1855,11 @@ socks = [
|
|||
|
||||
[[package]]
|
||||
name = "w3lib"
|
||||
version = "2.3.1"
|
||||
version = "2.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bf/7d/1172cfaa1e29beb9bf938e484c122b3bdc82e8e37b17a4f753ba6d6e009f/w3lib-2.3.1.tar.gz", hash = "sha256:5c8ac02a3027576174c2b61eb9a2170ba1b197cae767080771b6f1febda249a4", size = 49531 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f1/91/186665abf1a6d16c0c5ea1f0e681d9c852b45c3a750aa8657f8f956690a8/w3lib-2.4.0.tar.gz", hash = "sha256:e233ad21649b69d0e047a10f30181ae9677524a29f6f71f6f3c758dc0c8d2648", size = 48302 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/58/dd/56f0d8af71e475ed194d702f8b4cf9cea812c95e82ad823d239023c6558c/w3lib-2.3.1-py3-none-any.whl", hash = "sha256:9ccd2ae10c8c41c7279cd8ad4fe65f834be894fe7bfdd7304b991fd69325847b", size = 21751 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/f5/ce3ab627e0cb51591c9e3dc4b9b173f15d7f2bec1c0010420b15fc442940/w3lib-2.4.0-py3-none-any.whl", hash = "sha256:260b5a22aeb86ae73213857f69ed20829a45150f8d5b12050b1f02ada414db79", size = 21603 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1914,11 +1999,11 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "yt-dlp"
|
||||
version = "2025.12.8"
|
||||
version = "2026.2.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/14/77/db924ebbd99d0b2b571c184cb08ed232cf4906c6f9b76eed763cd2c84170/yt_dlp-2025.12.8.tar.gz", hash = "sha256:b773c81bb6b71cb2c111cfb859f453c7a71cf2ef44eff234ff155877184c3e4f", size = 3088947 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/16/be/8e099f3f34bac6851490525fb1a8b62d525a95fcb5af082e8c52ba884fb5/yt_dlp-2026.2.4.tar.gz", hash = "sha256:24733ef081116f29d8ee6eae7a48127101e6c56eb7aa228dd604a60654760022", size = 3100305 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/2f/98c3596ad923f8efd32c90dca62e241e8ad9efcebf20831173c357042ba0/yt_dlp-2025.12.8-py3-none-any.whl", hash = "sha256:36e2584342e409cfbfa0b5e61448a1c5189e345cf4564294456ee509e7d3e065", size = 3291464 },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/38/b17cbeaf6712a4c1b97f7f9ec3a55f3a8ddee678cc88742af47dca0315b7/yt_dlp-2026.2.4-py3-none-any.whl", hash = "sha256:d6ea83257e8127a0097b1d37ee36201f99a292067e4616b2e5d51ab153b3dbb9", size = 3299165 },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
|
|
@ -1936,11 +2021,11 @@ default = [
|
|||
|
||||
[[package]]
|
||||
name = "yt-dlp-ejs"
|
||||
version = "0.3.2"
|
||||
version = "0.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/de/72/57d02cf78eb45126bd171298d6a58a5bd48ce1a398b6b7ff00fc904f1f0c/yt_dlp_ejs-0.3.2.tar.gz", hash = "sha256:31a41292799992bdc913e03c9fac2a8c90c82a5cbbc792b2e3373b01da841e3e", size = 34678 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e9/80/4b6c7f91b373e01cdc18080f41fa399592945abce7db74c2e6d0fb8468db/yt_dlp_ejs-0.4.0.tar.gz", hash = "sha256:3c67e0beb6f9f3603fbcb56f425eabaa37c52243d90d20ccbcce1dd941cfbd07", size = 96768 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/0d/1f0d7a735ca60b87953271b15d00eff5eef05f6118390ddf6f81982526ed/yt_dlp_ejs-0.3.2-py3-none-any.whl", hash = "sha256:f2dc6b3d1b909af1f13e021621b0af048056fca5fb07c4db6aa9bbb37a4f66a9", size = 53252 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/90/8911146822364666be47f184c4180cec20fcc537a268ef40d1ab077dd25b/yt_dlp_ejs-0.4.0-py3-none-any.whl", hash = "sha256:19278cff397b243074df46342bb7616c404296aeaff01986b62b4e21823b0b9c", size = 53600 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1993,6 +2078,7 @@ installer = [
|
|||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "debugpy" },
|
||||
{ name = "pip" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-asyncio" },
|
||||
{ name = "ruff" },
|
||||
|
|
@ -2042,11 +2128,21 @@ provides-extras = ["installer"]
|
|||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "debugpy", specifier = ">=1.8.16" },
|
||||
{ name = "pip", specifier = ">=26.0.0" },
|
||||
{ name = "pytest", specifier = ">=8.4.2" },
|
||||
{ name = "pytest-asyncio", specifier = ">=1.1.0" },
|
||||
{ name = "ruff", specifier = ">=0.13.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.23.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zipstream-ng"
|
||||
version = "1.9.0"
|
||||
|
|
|
|||
Loading…
Reference in a new issue