Commit Graph

39 Commits

Author SHA1 Message Date
Jonathan Sykes
e6f032a6f2 feat: add shuffle toggle for upcoming tracks with S shortcut 2026-07-02 21:01:28 +08:00
Jonathan Sykes
f36f6aeee1 fix: only treat a waiting service worker as an update when a controller exists 2026-07-02 13:40:36 +08:00
Claude Worker
8018060d26 feat: update ready keeps showing even after updating
Task #61 completed by ClaudeQueue

ClaudeQueue
2026-07-01 17:40:50 +00:00
Claude Worker
42ff13b135 feat: audio playback issue
Task #60 completed by ClaudeQueue

ClaudeQueue
2026-07-01 07:26:33 +00:00
Claude Worker
50cf655b71 feat: fullscreen video button not working in pwa mode
Task #52 completed by ClaudeQueue

ClaudeQueue
2026-07-01 02:18:50 +00:00
Claude Worker
ffeef5d520 feat: audio playback intermittent issue
Task #50 completed by ClaudeQueue

ClaudeQueue
2026-07-01 01:53:09 +00:00
Claude Worker
7cf3517dd3 feat: ensure ui automatically updates regardless of version number
Task #53 completed by ClaudeQueue

ClaudeQueue
2026-06-30 21:14:06 +00:00
Jonathan Sykes
d01f51a7d0 fix: send SKIP_WAITING to waiting SW, not active controller, to break reload loop 2026-07-01 04:43:33 +08:00
Jonathan Sykes
ebe60a7be2 fix: start next track at beginning (or A point) instead of resuming, and store A-B per playlist
When auto-advancing through a queue or playlist — or stepping with
next/prev — the next video previously jumped to its saved resume
timestamp. A freshly selected track now starts at the beginning, or at
the A marker when an A-B loop is set for it. Resuming still applies when
you reopen a single video directly.

A-B markers set while playing from a playlist are now stored on that
playlist's own copy of the video (entry.ab), so each playlist keeps its
own loop and the markers sync to the database alongside the playlist.
Non-playlist playback keeps using the global per-video marker map.

Bumps service worker to v1.0.3 to bust the client cache.
2026-07-01 04:29:00 +08:00
Jonathan Sykes
79359dba44 feat: show app version and server build tag in settings
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.
2026-07-01 04:04:15 +08:00
Jonathan Sykes
041fc6a974 feat: add Reset UI section in settings (force refresh + full reset app) 2026-07-01 01:18:45 +08:00
Jonathan Sykes
6738644d4b feat: poll /api/version buildTag to detect new deploys and prompt reload
Server stamps a BUILD_TAG (stable per process, changes on restart/deploy)
into GET /api/version alongside the existing version string. Cache-Control
is set to no-store so the response is never cached by the SW or browser.

Client (WEB mode only) baselines the tag on first fetch after boot, then
rechecks every 5 minutes. On mismatch it calls the existing showUpdateBanner()
so the user sees the 'Update ready — Reload now' toast and can reload at will.

This mirrors the build-id polling pattern used across the BukidBountyApp
derivatives to avoid stale UI after deploys.
2026-07-01 01:13:37 +08:00
Claude Worker
d9371fdea4 feat: fix portrait mode design in pwa — YouTube-style bottom bar
Task #46 completed by ClaudeQueue

ClaudeQueue
2026-06-30 17:02:25 +00:00
Claude Worker
fc61defba5 feat: fix portrait mode design in pwa
Task #44 completed by ClaudeQueue

ClaudeQueue
2026-06-30 15:36:12 +00:00
Claude Worker
136e21f1fa feat: Follow-up: add portrait orientation design for mobile that only triggers in portrait pwa mode
Task #43 completed by ClaudeQueue

ClaudeQueue
2026-06-30 08:01:54 +00:00
ClaudeQueue
05e78677b0 feat: side bar playlist and other items not present on some screensizes. make completely responsive
Task #40 completed by ClaudeQueue

ClaudeQueue
2026-06-30 01:06:54 +00:00
Jonathan Sykes
84d6487125 feat: wire up WEB-mode OPFS offline cache for PWA
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
2026-06-30 08:37:45 +08:00
Jonathan Sykes
fea26fd435 feat: make channel names clickable in related, up-next, and mini-bar 2026-06-21 21:13:44 +08:00
Jonathan Sykes
20cd2f29ba feat: sleep timer, A-B loop, related panel, smart playlists, history delete/search, batch ops, auto-backup 2026-06-21 18:43:26 +08:00
Jonathan Sykes
3ad2e40606 Refresh Windows release artifacts and sync build outputs 2026-06-21 16:15:30 +08:00
Jonathan Sykes
f497eecebd Merge branch 'main' of ssh://git2.hesed.sbs:6612/josh/ytplayer
# Conflicts:
#	frontend/app.js
2026-06-21 15:43:45 +08:00
Jonathan Sykes
38511fa450 feat: queue, channel view, downloads/saved pages, repeat/loop, accessibility, perf, multithreading 2026-06-21 15:39:58 +08:00
Claude Worker
44fa24ca52 refactor: tidy playlist-menu label and catch blocks
Pre-push code analysis pass for task #1

ClaudeQueue
2026-06-18 18:48:07 +00:00
Claude Worker
95dc9e3f98 feat: Prevent UI hanging during video save or playlist add
Task #1 completed by ClaudeQueue

ClaudeQueue
2026-06-18 18:43:48 +00:00
Jonathan Sykes
d15d9021b7 Add cache cap, playlist export/import, yt-dlp build flag
Cache cap: dropdown setting (no limit / 1/2/5/10 GB) stored in
settings.cacheCap (actual eviction handled by native side).
Export: downloads playlists as JSON via Blob. Import: file reader
merges new playlists by id. yt-dlp: feature gate 'embed-ytdlp'
(default on), skip with --no-default-features for faster debug builds.

Files:
- frontend/app.js: exportPlaylists/importPlaylists, cache cap select
- src-tauri/Cargo.toml: [features] embed-ytdlp
- src-tauri/src/main.rs: #[cfg(feature = embed-ytdlp)] guards
2026-06-14 15:29:10 +08:00
Jonathan Sykes
c6b8dfceb8 Add rotating quick-search chips, video_id sanitize, retry button
Rotating chips: 4 sets of 4 chips rotate every 8 seconds on the
hero landing. Sanitize video_id: new sanitizeId() strips path
separators and dangerous chars. Retry button: appears on stream
extraction failure, re-triggers Player.loadVideo.

Files:
- frontend/app.js: sanitizeId(), CHIP_SETS + rotateChips(),
  retry button in loadVideo catch
2026-06-14 15:23:14 +08:00
Jonathan Sykes
c1855a1a91 Add persistent mini now-playing bar
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
2026-06-14 15:18:57 +08:00
Jonathan Sykes
4376cd9e88 Add up-next queue panel
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
2026-06-14 14:44:52 +08:00
Jonathan Sykes
0ba0f56a54 Add drag-to-reorder within playlists
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
2026-06-14 14:41:05 +08:00
Jonathan Sykes
a4d6b825d5 Replace single toast with stacked toast queue
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
2026-06-14 14:36:07 +08:00
Jonathan Sykes
ddfa1494c6 Remember and restore last playback position per video
Saves playback position to store on pause and periodically every
10s during playback. Restores position (>1s) when the same video
is loaded again, showing a 'Resumed from 0:42' toast.

Files:
- frontend/app.js: resumePositions in data, save in pause/timeupdate,
  restore in Player.afterLoad, boot merge includes resumePositions
2026-06-14 14:31:19 +08:00
Jonathan Sykes
81aced9bc5 Add download progress bar on card thumbnails
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
2026-06-14 14:23:52 +08:00
Jonathan Sykes
c676786144 Add keyboard-shortcut help overlay
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
2026-06-14 14:19:42 +08:00
Jonathan Sykes
da2ad27244 Add loading skeletons for search results
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
2026-06-14 14:14:05 +08:00
Jonathan Sykes
460aaae234 Add empty-state designs for empty playlists and history
Replaces bare status text with visual empty-state components:
- History: clock icon, 'Nothing watched yet' title, description, 'Search videos' CTA
- Playlist: music icon, 'This playlist is empty' title, description with tip, 'Browse videos' CTA
- Search: unchanged (hero landing handles this case)
- CTA buttons navigate to search view for quick action
2026-06-14 13:55:48 +08:00
Jonathan Sykes
4d5d105e70 Redesign landing page: hero with gradient brand wordmark, value pills (no ads / no sign-in / offline playlists), and clickable quick-search chips; refresh Windows installers 2026-06-14 12:03:14 +08:00
Jonathan Sykes
63560a8e61 Add offline cache & preload, Save/add-to-playlist UI, Settings page; player stream fallback + progressive-first ordering; protocol-asset feature; refresh Windows installers 2026-06-14 11:36:01 +08:00
Jonathan Sykes
bac6665b3d Add Windows support via a Tauri (WebView2) shell
zero-native has no Windows target yet, so add a parallel Tauri shell
for Windows that reuses the same frontend:

- src-tauri/: Rust commands (yt_search, yt_streams, store_load,
  store_save) mirroring the Zig bridge; spawns bundled yt-dlp.exe with
  CREATE_NO_WINDOW; data stored in app_data_dir
- frontend bridge now auto-detects window.__TAURI__ vs window.zero and
  routes accordingly; CSP updated for Tauri IPC
- tauri.conf.json bundles yt-dlp.exe as a resource and builds nsis/msi
- scripts/make-icon.js generates appicon.png for 'tauri icon'
- README: native Windows build steps + WSLg fallback note
2026-06-14 10:04:27 +08:00
Jonathan Sykes
a171cae417 Add ad-free YouTube player built on zero-native
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
2026-06-13 23:33:16 +08:00