Adds an About section at the bottom of Settings displaying the app
version. In WEB mode it fetches /api/version and appends the live
server build tag so you can confirm which deploy is running.
The sidebar contained two .playlist-list blocks each with flex:1 and its own
overflow-y:auto, nested inside the sidebar's own scroll. On screens too short
to fit everything, those inner flex regions collapsed toward zero height and
the playlists became unreachable. Drop the inner scroll/flex-grow and let the
whole sidebar scroll as a single unit at any screen size.
The PWA conversion shipped sw.js, opfs.js, manifest and icons, but app.js
was never updated to use them — it still routed cache_* calls through the
native bridge (call('cache.list', ...)), which throws 'No native bridge
available' in a browser. That surfaced as 'Offline cache unavailable /
not available in this build' on the Saved videos and Settings pages.
- Add WEB mode detection (no Tauri/zero bridge present)
- Route cache_* through OPFS (opfsDownload/Status/List/Delete/Clear)
- Proxy downloads via /api/download so the browser never hits YouTube CDN
- Load fingerprint.js + opfs.js; add manifest link and PWA meta tags
- Relax CSP to allow blob: media/img and worker-src 'self' for the SW
Fixed bar at bottom of window when video is playing. Shows title,
channel, progress, play/pause toggle. Click to restore player view.
Files:
- frontend/index.html: mini-bar markup
- frontend/app.js: showMiniBar/hideMiniBar/updateMiniBar, wiring
- frontend/styles.css: .mini-bar, .mini-bar-inner, .mini-progress styles
Shows upcoming videos in the autoplay queue below now-playing meta.
Clickable to jump to any video. Hidden when queue has 1 item or empty.
Updates on playFromList, playNext, playPrev. Hidden in empty player state.
Files:
- frontend/index.html: upnext section in player pane
- frontend/app.js: renderUpNext(), wired into playFromList/playNext/playPrev
- frontend/styles.css: .upnext, .upnext-item, .upnext-list styles
Cards in playlist view are draggable. Visual feedback: opacity on
source card, accent border on drop target. Reorder persists to store.
Files:
- frontend/app.js: dragSource state, drag/drop handlers on cards,
container-level dragover guard in wireUI
- frontend/styles.css: .card.dragging, .card.drag-over styles
Multiple toasts can appear simultaneously, capped at 3. Oldest
toast auto-evicts when cap is reached. Each toast auto-dismisses
with a fade-up exit animation.
- frontend/app.js: toast() now creates DOM elements in toastContainer
- frontend/index.html: single #toast replaced with #toastContainer
- frontend/styles.css: .toast-container flexbox row, .toast-exit animation
Replaces pulse-only state with a visible progress bar animation:
- Indeterminate bar slides across the bottom of card thumbnails during download
- markCardCacheState dynamically adds/removes the bar element
- renderCard includes the bar for newly rendered downloading cards
- Now-playing button already showed '⏳ Saving…' state
Files:
- frontend/app.js: dl-progress in renderCard, markCardCacheState dynamic bar
- frontend/styles.css: .dl-progress, .dl-bar with dlSlide animation
Press '?' to open a styled overlay showing all keyboard shortcuts,
Esc to close. Lists Space (play/pause), arrow keys (seek/volume),
F (fullscreen), M (mute), ? (help), Esc (close).
Files:
- frontend/app.js: toggleShortcutHelp(), wireShortcutHelp(), '?' and Esc handlers
- frontend/index.html: shortcut-overlay markup with .shortcut-grid
- frontend/styles.css: .shortcut-overlay, .shortcut-panel, .shortcut-row, kbd styles
Replace bare 'Searching…' text with 8 animated skeleton cards that
mirror the real card layout (thumbnail, title, channel, menu dot).
Shimmer animation sweeps across placeholder blocks until results arrive.
Files:
- frontend/app.js: showSearchSkeletons() function, wired into search submit
- frontend/styles.css: .skeleton-card, .skeleton-shimmer, .skeleton-line, .skeleton-dot styles with shimmer animation
Desktop YouTube player with no login and no ads. Extracts direct
video/audio streams with yt-dlp and plays them in a native window via
zero-native (Zig + system WebView) for a tiny footprint vs Electron.
- Dual-stream engine: muted video synced with separate audio track for
high quality without ffmpeg muxing; progressive fallback
- On-device playlists, watch history, audio-only mode
- Full custom controls: seek, volume, speed, quality, fullscreen, queue
- Zig bridge handlers spawn yt-dlp and return slimmed JSON to the web UI
- Cinematic dark UI: Bricolage/Hanken/JetBrains Mono, vermilion accent