From b15fa23b8aed8ca05723614fab09c057d56f3af6 Mon Sep 17 00:00:00 2001 From: hl-valdemar Date: Mon, 12 Oct 2026 01:22:42 +0200 Subject: [PATCH] fix: cap feed requests at 60 videos total --- README.md | 8 +- src/main.rs | 702 +++++++++++++++++++++++++------------ src/youtube.rs | 931 +++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 1255 insertions(+), 386 deletions(-) diff --git a/README.md b/README.md index e07294f..31c15a1 100644 --- a/README.md +++ b/README.md @@ -286,13 +286,13 @@ Using the same binding for overview and description preserves the default cycle. ## Loading and previews -Search loads 60 results per page; Feed and category views request 60 uploads per channel per page. Feed requests divide channels into disjoint batches across at most four concurrent yt-dlp processes. Individual channel views use one batch. Search uses one extractor to preserve relevance without repeating the same continuation traversal in parallel. +Search loads up to 60 results per page. Feed and category views share a **60-upload total request budget per load**, distributed fairly across active channels—not 60 per channel. Each channel retains its own offset; exhausted channels stop receiving requests, and feeds with more than 60 channels rotate through them across loads. Matching ranges are batched across at most four concurrent yt-dlp processes, with further batches queued. Individual channel views can use the full 60-row budget. -In normal mode, the next page starts fetching when 20 loaded rows remain, preserving selection and existing rows. Only one page request runs at a time; insert mode and open popups pause automatic prefetch. A feed page is accepted only after every batch succeeds. Switching views cancels all pending batches; returning resumes the same unfinished range. Deep channel archives can get slower because yt-dlp offsets traverse earlier pages again. +In normal mode, forward video navigation authorizes prefetch when 20 loaded rows remain. Each successful page clears that intent, so short, duplicate-only, or unavailable batches do not immediately chain additional loads at startup. Only one page request runs at a time; insert mode and open popups pause automatic prefetch. A feed page is accepted only after every batch succeeds. Switching views cancels running and queued batches; returning resumes the same unaccepted per-channel ranges. Deep channel archives can get slower because yt-dlp offsets traverse earlier pages again. -Malformed individual entries—including invalid video IDs, missing required fields, and wrong field types—are discarded without losing valid videos from the same page. Skipped entries still count toward pagination, so a full page of bad or unavailable entries does not hide later results. Invalid JSON, malformed playlist-level metadata, and extractor failures still fail the page. +Malformed individual entries—including invalid video IDs, missing required fields, and wrong field types—are discarded without losing valid videos from the same page. Raw entries, including skipped and duplicate rows, consume the request budget and determine each channel's exhaustion; a full unavailable batch therefore does not hide later results. Invalid JSON, malformed playlist-level metadata, missing/extra playlists, oversized responses, and extractor failures still fail the page without advancing channel offsets. -Feed views merge newest-first using available upload dates. Older uploads wait while newer channel pages catch up; undated uploads appear when the feed is exhausted. Publication labels use `YYYY-MM-DD`; `~` marks an estimated UTC date, and `Unknown` means unavailable metadata. +Feed views sort all loaded videos newest-first using available upload dates, with undated videos last. The budget limits what has been inspected: later loads may discover newer videos and insert them above older rows, while selection and pending description requests stay attached to the same video ID. Publication labels use `YYYY-MM-DD`; `~` marks an estimated UTC date, and `Unknown` means unavailable metadata. Pane titles show animated spinners while content loads. Errors retain loaded rows and stop automatic retries; `r` refreshes the current view. diff --git a/src/main.rs b/src/main.rs index e121203..a213c6e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -79,16 +79,16 @@ //! r reloads config and refreshes the current view. //! Feed includes saved `[channels]` entries, even untagged, plus direct tag entries, without duplicates. //! Untagging is not unsubscribing: remove mappings and tag references from the file to unsubscribe. -//! Search pages contain 60 results; Feed/tag pages request 60 uploads per channel's /videos tab. -//! Search uses one extractor; feeds batch disjoint channels across up to four concurrent extractors. +//! Search pages contain 60 results; Feed/tag pages share a total request budget of 60 uploads. +//! Search uses one extractor; feeds batch matching channel ranges across up to four concurrent extractors. //! Invalid individual video entries are discarded; raw entry counts still determine pagination. //! Invalid JSON, playlist-level metadata, and extractor failures remain page errors. -//! In unobstructed normal mode, 20 rows before the loaded end fetches the next page without replacing rows/selection. +//! Forward video navigation authorizes prefetch within 20 rows of the loaded end in unobstructed normal mode. +//! Each accepted page clears that intent, so short or invalid batches never auto-chain on startup. //! Loading result/preview panes animate a spinner after their title, including additional pages. //! Info spinners cover image download/decode/resize and description fetching; errors stop them. -//! Feed rows use approximate upload dates; older rows wait until newer channel pages catch up. -//! Undated feed rows appear at exhaustion. Cached views retain their page position across switches. -//! Switching views cancels in-flight extraction; returning resumes the same pending range. +//! Feed rows, including undated rows, are globally newest-first among loaded uploads; selection follows video ID. +//! Switching views cancels in-flight extraction; returning retains the unaccepted request and per-channel offsets. //! Errors keep loaded rows and stop automatic retries; r reloads config and restarts the current view. //! Deep pages may slow down because yt-dlp offsets re-traverse earlier continuation pages. //! Video tables show Published as YYYY-MM-DD; ~ marks estimated UTC dates, Unknown missing metadata. @@ -309,7 +309,9 @@ struct View { loaded: bool, next_start: usize, has_more: bool, - pending: Vec