196 lines
6 KiB
Python
196 lines
6 KiB
Python
import logging
|
|
import uuid
|
|
from collections import OrderedDict
|
|
|
|
from aiohttp import web
|
|
from aiohttp.web import Request, Response
|
|
|
|
from app.library.cache import Cache
|
|
from app.library.conditions import Condition, Conditions
|
|
from app.library.config import Config
|
|
from app.library.encoder import Encoder
|
|
from app.library.Events import EventBus, Events
|
|
from app.library.router import route
|
|
from app.library.Utils import extract_info, init_class, validate_uuid
|
|
from app.library.YTDLPOpts import YTDLPOpts
|
|
|
|
LOG: logging.Logger = logging.getLogger(__name__)
|
|
|
|
|
|
@route("GET", "api/conditions/", "conditions_list")
|
|
async def conditions_list(encoder: Encoder) -> Response:
|
|
"""
|
|
Get the conditions
|
|
|
|
Args:
|
|
encoder (Encoder): The encoder instance.
|
|
|
|
Returns:
|
|
Response: The response object.
|
|
|
|
"""
|
|
return web.json_response(
|
|
data=Conditions.get_instance().get_all(),
|
|
status=web.HTTPOk.status_code,
|
|
dumps=encoder.encode,
|
|
)
|
|
|
|
|
|
@route("PUT", "api/conditions/", "conditions_add")
|
|
async def conditions_add(request: Request, encoder: Encoder, notify: EventBus) -> Response:
|
|
"""
|
|
Save Conditions.
|
|
|
|
Args:
|
|
request (Request): The request object.
|
|
encoder (Encoder): The encoder instance.
|
|
notify (EventBus): The event bus instance.
|
|
|
|
Returns:
|
|
Response: The response object
|
|
|
|
"""
|
|
data = await request.json()
|
|
|
|
if not isinstance(data, list):
|
|
return web.json_response(
|
|
{"error": "Invalid request body expecting list with dicts."},
|
|
status=web.HTTPBadRequest.status_code,
|
|
)
|
|
|
|
items: list = []
|
|
|
|
cls = Conditions.get_instance()
|
|
|
|
for item in data:
|
|
if not isinstance(item, dict):
|
|
return web.json_response(
|
|
{"error": "Invalid request body expecting list with dicts."},
|
|
status=web.HTTPBadRequest.status_code,
|
|
)
|
|
|
|
if not item.get("name"):
|
|
return web.json_response(
|
|
{"error": "name is required.", "data": item}, status=web.HTTPBadRequest.status_code
|
|
)
|
|
|
|
if not item.get("filter"):
|
|
return web.json_response(
|
|
{"error": "filter is required.", "data": item}, status=web.HTTPBadRequest.status_code
|
|
)
|
|
|
|
if not item.get("cli"):
|
|
return web.json_response(
|
|
{"error": "command options for yt-dlp is required.", "data": item},
|
|
status=web.HTTPBadRequest.status_code,
|
|
)
|
|
|
|
if not item.get("id", None) or not validate_uuid(item.get("id"), version=4):
|
|
item["id"] = str(uuid.uuid4())
|
|
|
|
try:
|
|
cls.validate(item)
|
|
except ValueError as e:
|
|
return web.json_response(
|
|
{"error": f"Failed to validate condition '{item.get('name')}'. '{e!s}'"},
|
|
status=web.HTTPBadRequest.status_code,
|
|
)
|
|
|
|
items.append(init_class(Condition, item))
|
|
|
|
try:
|
|
items = cls.save(items=items).load().get_all()
|
|
except Exception as e:
|
|
LOG.exception(e)
|
|
return web.json_response(
|
|
{"error": "Failed to save conditions.", "message": str(e)},
|
|
status=web.HTTPInternalServerError.status_code,
|
|
)
|
|
|
|
await notify.emit(Events.CONDITIONS_UPDATE, data=items)
|
|
return web.json_response(data=items, status=web.HTTPOk.status_code, dumps=encoder.encode)
|
|
|
|
|
|
@route("POST", "api/conditions/test/", "conditions_test")
|
|
async def conditions_test(request: Request, encoder: Encoder, cache: Cache, config: Config) -> Response:
|
|
"""
|
|
Test condition against URL.
|
|
|
|
Args:
|
|
request (Request): The request object.
|
|
encoder (Encoder): The encoder instance.
|
|
cache (Cache): The cache instance.
|
|
config (Config): The configuration instance.
|
|
|
|
Returns:
|
|
Response: The response object
|
|
|
|
"""
|
|
params = await request.json()
|
|
|
|
if not isinstance(params, dict):
|
|
return web.json_response(
|
|
{"error": "Invalid request body expecting dict."},
|
|
status=web.HTTPBadRequest.status_code,
|
|
)
|
|
|
|
url: str | None = params.get("url")
|
|
if not url:
|
|
return web.json_response({"error": "url is required."}, status=web.HTTPBadRequest.status_code)
|
|
|
|
cond: str | None = params.get("condition")
|
|
if not cond:
|
|
return web.json_response({"error": "condition is required."}, status=web.HTTPBadRequest.status_code)
|
|
|
|
try:
|
|
preset: str = params.get("preset", config.default_preset)
|
|
key: str = cache.hash(url + str(preset))
|
|
if not cache.has(key):
|
|
opts = {}
|
|
if ytdlp_proxy := config.get_ytdlp_args().get("proxy", None):
|
|
opts["proxy"] = ytdlp_proxy
|
|
ytdlp_opts = YTDLPOpts.get_instance().preset(name=preset).add(opts).get_all()
|
|
|
|
data = extract_info(
|
|
config=ytdlp_opts,
|
|
url=url,
|
|
debug=False,
|
|
no_archive=True,
|
|
follow_redirect=True,
|
|
sanitize_info=True,
|
|
)
|
|
if not data:
|
|
return web.json_response(
|
|
data={"error": f"Failed to extract info from '{url!s}'."},
|
|
status=web.HTTPBadRequest.status_code,
|
|
)
|
|
cache.set(key=key, value=data, ttl=600)
|
|
else:
|
|
data = cache.get(key)
|
|
except Exception as e:
|
|
LOG.exception(e)
|
|
return web.json_response(
|
|
data={"error": f"Failed to extract video info. '{e!s}'"},
|
|
status=web.HTTPInternalServerError.status_code,
|
|
)
|
|
|
|
try:
|
|
from yt_dlp.utils import match_str
|
|
|
|
status = match_str(cond, data)
|
|
except Exception as e:
|
|
LOG.exception(e)
|
|
return web.json_response(
|
|
data={"error": str(e)},
|
|
status=web.HTTPBadRequest.status_code,
|
|
)
|
|
|
|
return web.json_response(
|
|
data={
|
|
"status": status,
|
|
"condition": cond,
|
|
"data": OrderedDict(sorted(data.items(), key=lambda item: len(str(item[1])))),
|
|
},
|
|
status=web.HTTPOk.status_code,
|
|
dumps=encoder.encode,
|
|
)
|