Files
media_crawler/backend/services/media_service.py
renjue 9368b5d80c Fix HDHive response unwrapping for resources and unlock data.
Parse nested openapi envelopes from HDHive search/unlock endpoints so resource lists and links are extracted from inner data instead of incorrectly falling back to empty arrays.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-09 17:49:35 +08:00

94 lines
3.0 KiB
Python

from adapters.hdhive_adapter import normalize_resource, search_resource, unlock_link
from adapters.tmdb_adapter import get_media_detail, search_media
from error_handling import AppServiceError
def _extract_hdhive_items(hdhive_result):
payload = (hdhive_result or {}).get("data")
# HDHive openapi uses envelope: { success, data, ... }
if isinstance(payload, dict) and isinstance(payload.get("data"), list):
return payload.get("data") or []
if isinstance(payload, list):
return payload
if isinstance(payload, dict):
return payload.get("items") or []
return []
def _extract_hdhive_unlock_data(unlock_result):
payload = (unlock_result or {}).get("data")
# HDHive unlock response is usually envelope with inner data object.
if isinstance(payload, dict) and isinstance(payload.get("data"), dict):
return payload.get("data") or {}
if isinstance(payload, dict):
return payload
return {}
def search_media_by_keyword(query, media_type):
result = search_media(query, media_type)
raw_items = result.get("items") or []
items = []
for item in raw_items:
items.append(
{
"id": item.get("id"),
"type": media_type,
"title": item.get("title") or item.get("name"),
"overview": item.get("overview") or "",
"posterPath": item.get("poster_path") or "",
"releaseDate": item.get("release_date") or item.get("first_air_date") or "",
"voteAverage": item.get("vote_average"),
}
)
return {"items": items}
def get_media_resources(media_type, tmdb_id):
detail = get_media_detail(tmdb_id, media_type)
hdhive = search_resource(media_type, tmdb_id)
search_data = _extract_hdhive_items(hdhive)
resources = []
for item in search_data:
slug = (item or {}).get("slug")
unlock_data = {}
unlock_error = None
if slug:
try:
unlock = unlock_link(slug)
unlock_data = _extract_hdhive_unlock_data(unlock)
except Exception as error:
unlock_error = str(error)
normalized = normalize_resource(item, unlock_data)
normalized["unlockError"] = unlock_error
resources.append(normalized)
return {
"media": detail.get("normalized"),
"resources": resources,
}
def validate_media_query(query, media_type):
if not query:
raise AppServiceError(
"query is required",
category="validation",
code="INVALID_INPUT",
status=400,
provider="api",
)
validate_media_type(media_type)
def validate_media_type(media_type):
if media_type not in ("movie", "tv"):
raise AppServiceError(
"type must be movie or tv",
category="validation",
code="INVALID_INPUT",
status=400,
provider="api",
)