"""Media stabilization service for the formal acquisition pipeline.""" from __future__ import annotations from dataclasses import dataclass import time from typing import Callable from acquisition.media.oss_client import to_oss from core.config import Settings @dataclass(frozen=True) class StabilizedMedia: media_type: str source_url: str cdn_url: str position: int status: str = "ready" error_message: str = "" Uploader = Callable[[str, str], str] def stabilize_media_urls( *, image_urls: list[str] | None = None, video_urls: list[str] | None = None, settings: Settings | None = None, uploader: Uploader | None = None, video_fallback_to_source: bool = True, video_retry_delays_seconds: tuple[float, ...] = (), sleep: Callable[[float], None] = time.sleep, ) -> list[StabilizedMedia]: """Transfer image/video URLs to OSS/CDN and return DB-ready media rows. Images keep the old soft-fallback behavior. Videos can opt into strict mode so expiring source URLs do not leak into classification/decode. """ upload = uploader or ( lambda url, media_type: to_oss(url, media_type, settings=settings) ) rows: list[StabilizedMedia] = [] position = 0 for url in image_urls or []: if not url: continue position += 1 try: cdn = upload(url, "image") except Exception: cdn = url rows.append( StabilizedMedia( media_type="image", source_url=url, cdn_url=cdn, position=position, status="ready" if cdn else "failed", ) ) for url in video_urls or []: if not url: continue position += 1 cdn = "" error_message = "" attempts = len(video_retry_delays_seconds) + 1 for attempt in range(attempts): try: cdn = upload(url, "video") if cdn and (video_fallback_to_source or cdn != url): error_message = "" break error_message = "oss_upload_returned_source_url" cdn = "" except Exception as exc: error_message = str(exc) if attempt < len(video_retry_delays_seconds): sleep(video_retry_delays_seconds[attempt]) if not cdn and video_fallback_to_source: cdn = url rows.append( StabilizedMedia( media_type="video", source_url=url, cdn_url=cdn, position=position, status="ready" if cdn else "failed", error_message=error_message, ) ) return rows