Ranking improvements:
- Wider candidate pool (4x limit) with ±12pt score perturbation so
same-score videos shuffle differently each load
- Recent channel engagement signal: channels watched in past 30 days
get a +4pts/watch boost
- Bail penalty: -25pts for videos started but abandoned before 20%
- Impression penalty: -3pts per prior feed appearance (capped at 10),
so repeatedly-skipped videos sink naturally
- rn cap raised to 5 for more candidates; Python-side sampling picks top limit
Feed UX:
- Reshuffle button now available on For You (ranked) mode, not just Explore
- shuffleKey now always included in query key (not just random mode)
- Ranked mode staleTime reduced from 10min to 90s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Channel page:
- "Explore older videos" button fetches 100 videos at a time further back
in the channel history using yt-dlp --playlist-start/--playlist-end
- "Fetch entire history" still available for full crawl
- Backend: /channels/{id}/explore?page=N endpoint + playlist offset support
in fetch_channel_metadata(start_video=N)
Home feed:
- New "Rediscover" mode: older unwatched videos (90+ days old) from
followed channels, randomly sampled then re-ranked by tag affinity
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace yellow accent (#f5a623) with white (#ffffff) across the entire
app. Flatten VideoCard grid variant by removing zinc-900 card background
so content sits directly on the page. Simplify active states, badges,
progress bars, and hover effects throughout.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Default list view across all pages (Home, Following, History, Queue,
ContinueWatching, Liked, Discovery, SearchResults, Channel)
- Watch.jsx mobile: smaller chips/title/avatar/meta, hide tags + keyboard
hint on mobile, tighter gaps, compact description padding
- Fix mobile bottom nav showing focus outline on tap
- Fix _update_affinity to write negative entries (not just positive) so
dislikes/dismissals on unseen content actually register
- Dismissing a discovery video now fires -3.0 affinity against its tags,
matching the dislike weight
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- App-shell layout (height:100dvh, only main scrolls) so the bottom nav
is a natural flex child and never disappears regardless of browser
chrome show/hide behaviour
- Bottom nav reduced from h-16 to h-14, icons from 20px to 18px, labels
from 10px to 9px — slimmer bar, still readable
- Header: min-w-0 on search prevents horizontal overflow; user/sign-out
hidden on mobile (accessible via Settings); logo shortened to "YT" on
mobile; px-3 / h-12 on mobile instead of px-4 / h-14
- Grid card descriptions hidden on mobile (hidden sm:block) — reduces
height cramping in the 2-column feed
- scrollToTop() utility replaces window.scrollTo so pagination still
scrolls to top within the new scroll container
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Self-hosted personal YouTube management app.
FastAPI + SQLite backend, React + Vite + Tailwind frontend.
Dockerfiles and compose included for Portainer deployment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>