Carousels: deliver every video, and stop shouting about photos - #28
Merged
Conversation
An Instagram photo carousel has no video, so yt-dlp fails once per photo item. In a group that produced a 💥 report quoting yt-dlp's raw plumbing: "Dbnd91uAyMW: No video formats found!; please report this issue on https://github.com/yt-dlp/yt-dlp/issues?q= ...". The same went for any link whose target is not media at all: an archive.ph page holding a PDF was reported as a download failure. Worse, a post that mixes photos and videos delivered only its first video. The rest were dropped silently, because a post resolved to a single info. A post is now scraped as a list. One job per message URL delivers every video it holds, in order, one reply per video, capped at ten (the scrape looks at fifty, because a carousel spends a playlist index on each of its photos too). The bookkeeping that used to track "the video" is now per-entry, keyed on yt-dlp's identity minus the format so a re-scrape that drifts still matches: which videos are settled, which have been announced, whether anything reached the chat at all. A run whose only casualties are photo items is salvaged: the videos that did resolve are kept and cached, and the photos are not treated as a failure. A post whose items are ALL photos, and a link to a non-media file, are both "not a video": one attempt, no retry, and a group hears nothing, matching the existing policy for photo posts. A lone item that reports no formats is still a real failure the chat is told about, since a carousel is what emits one such line per item (verified against the real yt-dlp: a nine-photo post gives nine). User-facing errors no longer carry yt-dlp's "please report this issue" boilerplate, and a post's one report is now elected: a retryable failure outranks a permanent one, and a photo item never speaks for a sibling that failed for a real reason. - A bare playlist or channel URL now delivers its first ten videos with a notice, where it used to take the first only. - A confirmation parked for one video of a post no longer un-records the whole message, so cancelling it cannot re-send what already landed. - Migration 6 drops the cached video_info rows: the payload went from one - yt-dlp introduces its issue-tracker paragraph with a clause of its own in some errors; the whole invitation is stripped, not just its tail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K7QTJrxfmVdrARFcmmKtXN
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Three ways a link could go wrong in a group chat, all reported from real chats:
Dbnd91uAyMW: No video formats found!; please report this issue on https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using yt-dlp -U. A photo post is not a failure, and nobody in a group chat can act on that text.Fix
A post is now scraped as a list. One job per message URL delivers every video it holds, in order, one reply per video, capped at ten (the scrape looks at fifty, because a carousel spends a playlist index on each of its photos too). The bookkeeping that used to track "the video" is now per-entry, keyed on yt-dlp's identity minus the format so a re-scrape that drifts still matches: which videos are settled, which have been announced, whether anything reached the chat at all.
A run whose only casualties are photo items is salvaged: the videos that did resolve are kept and cached, and the photos are not treated as a failure. A post whose items are all photos, and a link to a non-media file, are both "not a video": one attempt, no retry, and a group hears nothing, matching the policy that already existed for photo posts. A lone item reporting no formats is still a real failure the chat is told about, since a carousel is what emits one such line per item (verified against the real yt-dlp: the nine-photo post above emits nine).
User-facing errors no longer carry yt-dlp's bug-report invitation, and a post's one report is elected rather than taken from whichever entry failed first: a retryable failure outranks a permanent one, and a photo item never speaks for a sibling that failed for a real reason.
Worth a reviewer's eye
video_inforows: the payload went from one object to an array, and it is a six-hour cache.Verification
442 unit tests and 11 live e2e cases pass, including the exact carousel from the report above (group-silent) and a real three-video-plus-photo post (all three delivered). Every new behavioural constraint is pinned by a test verified to fail when the behaviour is mutated away. QA against the live dev bot on real Telegram confirmed the three videos arrive as three replies and the boilerplate is gone from the verdict.
Written by Claude Opus 5