Retry transient video download failures, friendlier fallback link text, enable previews
- yt-dlp: retry transient failures (stall/timeout) up to 2x before falling back to a link-only post; permanent errors (private/removed) still fail fast - Fallback note: friendlier wording, "Смотреть видео" as link text instead of a bare "ссылка", plus a link to the original VK wall post as a backup - TG: enable link preview for text-only fallback posts (was unconditionally disabled, leaving fallback posts with no visual at all) - MAX: attach the VK video's own thumbnail as an image so failed/oversized video fallbacks still show a preview picture (MAX has no OG-preview for arbitrary URLs, but does accept a remote image url without upload) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,7 @@ class ProcessedMedia:
|
||||
height: Optional[int] = None
|
||||
error: Optional[str] = None
|
||||
is_link_only: bool = False
|
||||
thumbnail_url: Optional[str] = None
|
||||
|
||||
|
||||
class MediaProcessor:
|
||||
@@ -100,6 +101,26 @@ class MediaProcessor:
|
||||
|
||||
async def download_video_ytdlp(
|
||||
self, url: str, prefix: str = "video_"
|
||||
) -> tuple[Optional[Path], Optional[str], bool]:
|
||||
"""Retries transient failures (stalls, timeouts, one-off yt-dlp/network hiccups)
|
||||
a couple of times before giving up - a single flaky attempt used to fall straight
|
||||
through to the link-only fallback even though the video was perfectly downloadable."""
|
||||
last_result: tuple[Optional[Path], Optional[str], bool] = (None, "video download failed", False)
|
||||
for attempt in range(1, settings.yt_dlp_retry_attempts + 2):
|
||||
path, err, is_permanent = await self._download_video_ytdlp_attempt(url, prefix)
|
||||
if path or is_permanent:
|
||||
return path, err, is_permanent
|
||||
last_result = (path, err, is_permanent)
|
||||
if attempt <= settings.yt_dlp_retry_attempts:
|
||||
logger.warning(
|
||||
"yt-dlp attempt {}/{} failed transiently for {}: {} - retrying",
|
||||
attempt, settings.yt_dlp_retry_attempts + 1, url, err,
|
||||
)
|
||||
await asyncio.sleep(3.0)
|
||||
return last_result
|
||||
|
||||
async def _download_video_ytdlp_attempt(
|
||||
self, url: str, prefix: str = "video_"
|
||||
) -> tuple[Optional[Path], Optional[str], bool]:
|
||||
"""Returns (path, error_message, is_permanent_error)"""
|
||||
output_path = self.cache_dir / f"{prefix}{uuid.uuid4().hex[:12]}.mp4"
|
||||
@@ -249,6 +270,7 @@ class MediaProcessor:
|
||||
duration_sec=item.duration_sec,
|
||||
error="video duration exceeds maximum",
|
||||
is_link_only=True,
|
||||
thumbnail_url=item.thumbnail_url,
|
||||
)
|
||||
)
|
||||
continue
|
||||
@@ -277,6 +299,7 @@ class MediaProcessor:
|
||||
duration_sec=item.duration_sec,
|
||||
error=err or "failed to download video",
|
||||
is_link_only=True,
|
||||
thumbnail_url=item.thumbnail_url,
|
||||
)
|
||||
)
|
||||
return results
|
||||
|
||||
Reference in New Issue
Block a user