From 24493885aaa7b7a15f14aa55d5e296c53769ad10 Mon Sep 17 00:00:00 2001 From: arabcoders Date: Sun, 26 Oct 2025 21:42:48 +0300 Subject: [PATCH] minor fixes and style update --- API.md | 40 ++++++++++++++++++++++ app/library/Utils.py | 16 ++++----- app/library/ytdlp.py | 4 ++- app/routes/api/yt_dlp.py | 58 ++++++++++++++++++++++++++++++++ ui/app/components/Connection.vue | 17 +++++----- ui/eslint.config.js | 2 +- 6 files changed, 119 insertions(+), 18 deletions(-) diff --git a/API.md b/API.md index 6ec10e00..0f1fff6f 100644 --- a/API.md +++ b/API.md @@ -64,6 +64,7 @@ This document describes the available endpoints and their usage. All endpoints r - [GET /api/notifications](#get-apinotifications) - [PUT /api/notifications](#put-apinotifications) - [POST /api/yt-dlp/archive\_id/](#post-apiyt-dlparchive_id) + - [POST /api/yt-dlp/save\_cookies/](#post-apiyt-dlpsave_cookies) - [POST /api/notifications/test](#post-apinotificationstest) - [GET /api/yt-dlp/options](#get-apiyt-dlpoptions) - [POST /api/system/pause](#post-apisystempause) @@ -1449,6 +1450,45 @@ or an error: --- +### POST /api/yt-dlp/save_cookies/ +**Purpose**: Save cookies to a file for use with yt-dlp CLI operations. Requires console to be enabled (`console_enabled` in configuration). +**Body**: JSON object with `cookies` field containing the cookie string. +```json +{ + "cookies": "cookie_string_or_netscape_format" +} +``` + +**Response on Success**: +```json +{ + "status": true, + "cookie_file": "/path/to/temp/c_uuid.txt" +} +``` + +**Response on Error**: +```json +{ + "error": "error_message" +} +``` + +**Status Codes**: +- `200 OK` if cookies were successfully saved. +- `400 Bad Request` if the request body is invalid or missing the `cookies` field. +- `403 Forbidden` if console is disabled. +- `413 Payload Too Large` if cookies exceed 1MB. +- `500 Internal Server Error` if cookie file creation fails. + +**Notes**: +- Console must be enabled in configuration (`console_enabled: true`). +- Cookies must be a valid string (≤ 1MB). +- Cookies are stored in the temporary directory with a UUID-based filename. +- Cookie files can be used with subsequent yt-dlp operations. + +--- + ### POST /api/notifications/test **Purpose**: Triggers a test notification event to all configured targets. diff --git a/app/library/Utils.py b/app/library/Utils.py index 3781878e..d23f5169 100644 --- a/app/library/Utils.py +++ b/app/library/Utils.py @@ -21,7 +21,7 @@ from yt_dlp.utils import age_restricted from .LogWrapper import LogWrapper from .mini_filter import match_str -from .ytdlp import YTDLP +from .ytdlp import YTDLP, make_archive_id LOG: logging.Logger = logging.getLogger("Utils") @@ -1242,21 +1242,21 @@ def get_archive_id(url: str) -> dict[str, str | None]: } ) - for key, ie in YTDLP_INFO_CLS._ies.items(): + for key, _ie in YTDLP_INFO_CLS._ies.items(): try: - if not ie.suitable(url): + if not _ie.suitable(url): continue - if not ie.working(): - break + if not _ie.working(): + continue - temp_id = ie.get_temp_id(url) + temp_id = _ie.get_temp_id(url) if not temp_id: - break + continue idDict["id"] = temp_id idDict["ie_key"] = key - idDict["archive_id"] = YTDLP_INFO_CLS._make_archive_id(idDict) + idDict["archive_id"] = make_archive_id(_ie, temp_id) break except Exception as e: LOG.exception(e) diff --git a/app/library/ytdlp.py b/app/library/ytdlp.py index d0a49dd8..d52a97c8 100644 --- a/app/library/ytdlp.py +++ b/app/library/ytdlp.py @@ -1,8 +1,10 @@ +# flake8: noqa: F401 from typing import Any import yt_dlp +from yt_dlp.utils import make_archive_id -import app.postprocessors # noqa: F401 +import app.postprocessors class _ArchiveProxy: diff --git a/app/routes/api/yt_dlp.py b/app/routes/api/yt_dlp.py index 873be860..fcd222bf 100644 --- a/app/routes/api/yt_dlp.py +++ b/app/routes/api/yt_dlp.py @@ -2,6 +2,7 @@ import json import logging import time from collections import OrderedDict +from pathlib import Path from typing import Any from aiohttp import web @@ -272,3 +273,60 @@ async def get_archive_ids(request: Request, config: Config) -> Response: response.append(dct) return web.json_response(data=response, status=web.HTTPOk.status_code) + + +@route("POST", "api/yt-dlp/save_cookies/", "save_cookies") +async def save_cookies(request: Request, config: Config) -> Response: + """ + Save cookies for use with CLI. + + Returns: + Response: The response object with the yt-dlp CLI options. + + """ + if not config.console_enabled: + return web.json_response( + data={"error": "Console is disabled."}, + status=web.HTTPForbidden.status_code, + ) + + data = (await request.json()) if request.body_exists else None + if not data or not isinstance(data, dict): + return web.json_response( + data={"error": "Invalid request. expecting dict with 'cookies' field."}, + status=web.HTTPBadRequest.status_code, + ) + + cookies = data.get("cookies") + if not cookies or not isinstance(cookies, str): + return web.json_response( + data={"error": "Invalid request. 'cookies' field is required and must be a string."}, + status=web.HTTPBadRequest.status_code, + ) + + if len(cookies) > 1_000_000: + return web.json_response( + data={"error": "Cookie size exceeds the maximum limit of 1MB."}, + status=web.HTTPBadRequest.status_code, + ) + + import uuid + + from app.library.Utils import load_cookies + + cookie_file: Path = Path(config.temp_path) / f"c_{uuid.uuid4()!s}.txt" + + try: + cookie_file.write_text(cookies) + file_path = str(cookie_file) + load_cookies(cookie_file) + except Exception as e: + return web.json_response( + data={"error": f"Failed to create cookie file. '{e!s}'."}, + status=web.HTTPInternalServerError.status_code, + ) + + return web.json_response( + data={"status": True, "cookie_file": file_path}, + status=web.HTTPOk.status_code, + ) diff --git a/ui/app/components/Connection.vue b/ui/app/components/Connection.vue index 0e5ac902..2aa7587e 100644 --- a/ui/app/components/Connection.vue +++ b/ui/app/components/Connection.vue @@ -1,15 +1,16 @@