Skip to content

Carousels: deliver every video, and stop shouting about photos - #28

Merged
miridius merged 1 commit into
mainfrom
worktree-instagram-photo-carousel
Aug 5, 2026
Merged

Carousels: deliver every video, and stop shouting about photos#28
miridius merged 1 commit into
mainfrom
worktree-instagram-photo-carousel

Conversation

@miridius

@miridius miridius commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Problem

Three ways a link could go wrong in a group chat, all reported from real chats:

  • An Instagram photo carousel has no video, so yt-dlp fails once per photo. The group got a 💥 report quoting yt-dlp's plumbing verbatim: 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.
  • An archive.ph page holding a PDF was reported the same way, as a download failure, for a link that was never going to be a video.
  • A post that mixes photos and videos delivered only its first video. The rest were dropped silently, because a post resolved to a single video.

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

  • A bare playlist or channel URL now delivers its first ten videos behind a "More than 10 videos here" notice, where it used to deliver 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 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

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
@miridius
miridius merged commit a10028b into main Aug 5, 2026
3 checks passed
@miridius
miridius deleted the worktree-instagram-photo-carousel branch August 5, 2026 19:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant