added new endpoint to get urls archive ids

This commit is contained in:
arabcoders 2025-08-27 16:28:19 +03:00
parent 21c7b0f208
commit 71bd40a2e8
3 changed files with 104 additions and 12 deletions

55
API.md
View file

@ -44,7 +44,9 @@ This document describes the available endpoints and their usage. All endpoints r
- [GET /api/logs](#get-apilogs)
- [GET /api/notifications](#get-apinotifications)
- [PUT /api/notifications](#put-apinotifications)
- [POST /api/yt-dlp/archive\_id/](#post-apiyt-dlparchive_id)
- [POST /api/notifications/test](#post-apinotificationstest)
- [GET /api/yt-dlp/options](#get-apiyt-dlpoptions)
- [Error Responses](#error-responses)
---
@ -824,6 +826,41 @@ Binary image data with appropriate `Content-Type` header.
"allowedTypes": ["added", "completed", "error", "cancelled", "cleared", "log_info", "log_success", ...]
}
```
---
### POST /api/yt-dlp/archive_id/
**Purpose**: Get the archive ID for a given URLs.
**Body**: Array of URLs.
```json
[
"https://youtube.com/...",
"https://..."
}
```
**Response**:
```json
[
{
"index": "index_of_the_url_in_request_array",
"url": "the_url",
"id": "the_video_id_or_null_if_not_found",
"ie_key": "the_extractor_key_or_null_if_not_found",
"archive_id": "the_archive_id_or_null_if_not_found",
"error": "error_message_if_any_or_null"
},
...
]
```
or an error:
```json
{
"error": "text"
}
```
- If the body is not a valid JSON array, returns `400 Bad Request`.
---
@ -840,6 +877,24 @@ Binary image data with appropriate `Content-Type` header.
---
### GET /api/yt-dlp/options
**Purpose**: Get the current yt-dlp CLI options as a JSON object.
**Response**:
```json
[
{
"description": "Description of the option",
"flags":[ "--option", "-o" ],
"group": "Option Group",
"ignored": false, // true if this option is ignored by ytptube.
},
...
]
```
---
## Error Responses
Most endpoints return standard error codes (`400`, `403`, `404`, `500`, etc.) and a JSON body on failure. For example:

View file

@ -405,13 +405,9 @@ def check_id(file: Path) -> bool | str:
@lru_cache(maxsize=512)
def is_private_address(hostname: str) -> bool:
try:
ip = socket.gethostbyname(hostname)
ip_obj = ipaddress.ip_address(ip)
return ip_obj.is_private or ip_obj.is_loopback or ip_obj.is_reserved or ip_obj.is_link_local
except socket.gaierror:
# Could not resolve - treat as invalid or restricted
return True
ip = socket.gethostbyname(hostname)
ip_obj = ipaddress.ip_address(ip)
return ip_obj.is_private or ip_obj.is_loopback or ip_obj.is_reserved or ip_obj.is_link_local
def validate_url(url: str, allow_internal: bool = False) -> bool:
@ -447,10 +443,20 @@ def validate_url(url: str, allow_internal: bool = False) -> bool:
raise ValueError(msg)
hostname: str | None = parsed_url.host
if allow_internal is False and (not hostname or is_private_address(hostname)):
msg = "Access to internal urls or private networks is not allowed."
if not hostname:
msg = "Invalid hostname."
raise ValueError(msg)
if allow_internal is False:
try:
if is_private_address(hostname):
msg = "Access to internal urls or private networks is not allowed."
raise ValueError(msg)
except socket.gaierror as e:
LOG.error(f"Error resolving hostname '{hostname}': {e!s}")
msg = "Invalid hostname."
raise ValueError(msg) from e
return True

View file

@ -309,6 +309,37 @@ async def get_options() -> Response:
"""
from app.library.ytdlp import ytdlp_options
return web.json_response(
body=json.dumps(ytdlp_options(), indent=4, default=str), status=web.HTTPOk.status_code
)
return web.json_response(body=json.dumps(ytdlp_options(), indent=4, default=str), status=web.HTTPOk.status_code)
@route("POST", "api/yt-dlp/archive_id/", "get_archive_ids")
async def get_archive_ids(request: Request) -> Response:
"""
Get the yt-dlp CLI options.
Returns:
Response: The response object with the yt-dlp CLI options.
"""
from app.library.Utils import get_archive_id
data = (await request.json()) if request.body_exists else None
if not data or not isinstance(data, list):
return web.json_response(
data={"error": "Invalid request. expecting list with URLs."},
status=web.HTTPBadRequest.status_code,
)
response = []
for i, url in enumerate(data):
dct = {"index": i, "url": url}
try:
validate_url(url)
dct.update(get_archive_id(url))
except ValueError as e:
dct.update({"id": None, "ie_key": None, "archive_id": None, "error": str(e)})
response.append(dct)
return web.json_response(data=response, status=web.HTTPOk.status_code)