← All topicsOpen Browse →

Browse is the screen you use before something is yours. It reaches out to Telegram or Instagram, shows you what is there, and downloads only the clips you tick. Media is the opposite end of the same pipe: the gallery of everything already ingested. If you are looking at a clip on Media you already own it; if you are looking at one here, you do not yet.

There is no nav entry for Browse. The item is commented out of the global nav's item list, so nothing in the app's navigation reaches /browse or /browse/instagram — type the URL. The Telegram half is different, though — see below.

The point of the whole surface is that Telegram and Instagram are firehoses. A chat-wide sync would pull down hundreds of clips you do not want; here you scrub thumbnails, tick a handful, and ingest those.

Getting here

  • /browse — the hub. Two cards, Telegram and Instagram, under the heading "Browse sources". Type the URL.
  • /browse/telegram — the chat picker. Also reachable from Media → Telegram: the per-chat refresh control on /media/telegram navigates into the browse preview for that chat rather than syncing it.
  • /browse/telegram/<chat> — the preview grid for one chat. Also reachable from the Browse new videos button on that chat's ingested gallery at /media/telegram/<chat>.
  • /browse/instagram — the explore feed. Type the URL.

There is no Reddit browse. Reddit is synced subreddit-wide from Settings, not picked clip by clip.

Telegram

Choosing a chat

/browse/telegram looks almost exactly like /media/telegram — same component, and it even carries the same Telegram Media heading. Three things separate them. A card here takes you to the preview grid rather than to the ingested gallery; and the Media version's cards additionally carry a "N% captioned" pill and a wand-icon Caption uncaptioned media button, neither of which this page renders. If you are unsure which you are on, check the URL — or look for the wand.

The list is your enrolled chats, not everything in your Telegram account. It comes from the Enrolled chats list in Settings → Sources → Telegram Source, and a chat you have not enrolled cannot be browsed here at all. Enrolled chats with nothing ingested yet still appear, so a fresh enrollment is browsable immediately. The "N posts" count under each name is how much of that chat is already in the library — it says nothing about how much is waiting to be browsed.

Previewing and picking

/browse/telegram/<chat> fetches recent video messages from the chat and lays them out as a 9:16 grid. The subheading tells you where you stand: "Showing N videos · M not yet ingested".

Two settings decide what you see, both under Sync defaults in Settings → Sources → Telegram Source:

  • Preview limit — how many recent messages are pulled per fetch. It defaults to 8, which is small; most of a batch gets filtered out, so a fetch often yields only one or two cards.
  • Max duration (seconds) — defaults to 20. Anything longer is dropped at the metadata stage, before a single byte of video is downloaded.

Each card shows the clip's duration, the chat handle, the message date, and the caption if there is one. Already-ingested items carry a green Ingested badge and cannot be selected — they are shown so you can see where you left off, not so you can re-download them.

Cards do not stop at a thumbnail. The thumbnail is what you see first — it is the tile's background from the moment the card renders — but once the card scrolls into view it streams the full clip through the app's own proxy so it can autoplay in place, with a percent counter over the tile while that downloads. At most two download at once, because Telegram drops parallel connections aggressively. This is why the grid feels heavy compared to the media gallery, and why a card can sit at "Queued" for a moment before it starts. A card that fails to load offers Retry on the tile itself.

Ingesting

Tick cards — tap anywhere on the tile, or the checkbox in its corner — and a bar appears at the bottom of the viewport with the count, Clear, and Ingest N. Or use the Ingest button on a single card's tile to take just that one without building a selection.

Ingest runs while you wait: the button reads Ingesting… until the clips have been downloaded, stored, and written into the media collection. When it finishes, the successful ids drop out of your selection, the grid refetches, and those cards flip to Ingested.

A failed ingest is quiet on this screen. There is no error toast here, and a failure does not even hold the selection open: a per-message failure is caught server-side and comes back as a normal result with a failed count, so the ids clear from your selection and the grid refetches exactly as if it had worked. The only signal is that the cards never flip to Ingested. The run's outcome is recorded as a Telegram ingest notification with an added / skipped / failed summary; if the clips you picked never appear on Media, that is where the reason is.

View ingested in the header jumps to the same chat's gallery under /media, pre-filtered to clips with no generation job and ≤20 seconds. Refresh re-fetches the preview from Telegram.

Scrolling and the end of the list

The grid pages as you scroll. Because the duration filter usually throws out most of a batch, a fetch can legitimately come back empty; when that happens the page chains straight into the next batch rather than leaving you at a blank stretch, up to six empty batches in a row. Past that it stops and offers Keep looking older — no eligible videos in the last N batches so a chat where almost nothing qualifies cannot spin forever. The footer otherwise reads "Scroll for more" or "No more videos in this chat."

That footer only exists once at least one card has come back. If the chat's very first fetches all resolve to nothing you get the bare empty state — "No videos in this chat match the current filter." — with no footer, no sentinel, and no Keep-looking button, because all of that lives inside the grid. Refresh is the only way on from there.

If the Telegram session has expired or been revoked, an amber banner appears above the grid with a Re-authenticate button that walks through the login code without leaving the page. A rate-limit hit shows the same banner with a retry-after time and no button — there is nothing to do but wait.

Instagram

/browse/instagram is the same preview-and-select pattern against Instagram's /explore recommendation feed. It is flatter than Telegram: /explore is one global feed, so there is no picker tier — you land straight on the grid, and Back to browse returns you to the hub.

The controls are the same — tick cards, Ingest N from the bottom bar or Ingest on a single tile, View ingested, Refresh. A 20-second duration cap applies here too, but unlike Telegram's it is fixed in code, not a setting — nothing on the Settings page moves it.

Ingest does two things here, not one. It saves the post to the AI VIDS collection on Instagram, so the bookmark persists on Instagram's side and the existing collection sync stays idempotent over it, and it fetches the post into the local media collection so it is immediately available for captioning and generation. That is why a single Instagram ingest is slower than a Telegram one.

This surface is degraded right now. The explore endpoint returns zero usable items on most pages, so the grid is frequently empty; the automatic empty-page chaining that Telegram uses is switched off here because it was firing several browser spawns per scroll for nothing.

That plays out in two different ways depending on whether anything came back:

  • Some reels loaded. The footer under the grid always shows the Keep looking — no eligible reels in the last N batches button rather than "Scroll for more", and you have to press it. Scrolling still fetches the next page normally.
  • Nothing loaded at all — the common case here. You get the bare empty state, "No reels in this batch match the current duration filter.", and there is no footer and no Keep-looking button to press, because both live inside the grid. Refresh is the only control that will try again.

Session problems surface as an amber banner reading one of three things: a rate limit with a retry-after, "Instagram refused the explore request. The session may be flagged.", or an invalid session that needs npm run seed:instagram re-run on the machine.

What Browse does not do

Nothing on these screens captions, tags, trims, queues, or archives anything. Ingest is the only write. Once a clip lands in the library, everything else happens on Media and Jobs — and the ingested clip arrives uncaptioned, so captioning it is the next step whether you do it by hand or leave it to the nightly pipeline.