Commit Graph
115 Commits
Author SHA1 Message Date
LeoVasanko 29cda926a2 Improve search-detail back navigation and focus restore 2026-05-27 21:12:39 +00:00
LeoVasanko 81be850e0c Sliding layout between details and category views. 2026-05-27 20:58:19 +00:00
LeoVasanko e78774613a More compact and consistent layout for the release badges. Bluer release group color. 2026-05-27 20:50:43 +00:00
LeoVasanko 96c2d52ee0 perf(frontend): fix resource leaks and disable deep reactivity on media index
- useMediaWebSocket: shallowRef mediaIndex/tasks/loading/error/connected
  to eliminate Proxy overhead on the entire library data structure.
- useMediaWebSocket: replace per-task setTimeout leak with single 3s
  sweep interval for completed task cleanup.
- App.vue: remove {deep:true} watcher on mediaIndex; shallow ref change
  is sufficient to trigger search worker sync.
- useGamepadNavigation: rAF only when gamepads are connected; idle
  fallback to 500ms setTimeout to stop permanent 60fps CPU drain.
- useKeyboardNavigation: deduplicate synced scroll rAF requests to
  prevent overlapping animation frames.
- MediaDetail/SeriesFullView/CollageHero: pause, clear src, and load()
  video elements on unmount and before ref replacement to release
  decoder/memory resources.
- MediaDetail/SeriesFullView: clear all volume fade intervals on
  unmount to stop interval timer leaks.
2026-05-27 20:28:51 +00:00
LeoVasanko 79d3f40162 Unify gamepad repeat model with accelerating hold and analog scaling 2026-05-27 14:40:49 +00:00
LeoVasanko f982785850 Fix HexKeyboard X/Y gamepad keypress animations 2026-05-27 14:28:08 +00:00
LeoVasanko 4c33cee4ac Move frontend search to worker and improve people-name matching 2026-05-26 20:43:10 +00:00
LeoVasanko cf2b90809a HexKeyboard: refactor to row-based flex layout
Replace 39 per-key absolute positioning CSS rules with 4 row divs
using flexbox. Rows overlap via negative margin-top to preserve
honeycomb staggering. Horizontal offsets via 4 margin-left rules.

- Add RowKeyDef with globalIndex for row-based rendering
- Add rows computed to group layoutKeys into 4 arrays
- Remove all .hex-key-N { top; left } positioning rules
- Keys are now flex children, position: relative, fixed width

Also includes prior changes:
- Row-based greyscale gradients (lighter top, darker home row)
- Per-key re-triggerable press animation (DOM reflow reset)
- Green-to-white exponential fade on keypress
- Gamepad repeat: 90ms horizontal/buttons, 140ms vertical
2026-05-26 16:37:12 +00:00
LeoVasanko 43ca8ea1d1 Implement OSD keyboard for gamepads. Using hex tiles of course. 2026-05-26 04:52:13 +00:00
LeoVasanko 8cb7ab5938 Adjust no search results label. 2026-05-26 04:49:28 +00:00
LeoVasanko 7fa8ddad65 Fix movie details header layout and space division with cast display. 2026-05-25 19:21:21 +00:00
LeoVasanko f219840967 refactor(synced-scroll): rewrite with global metrics + per-row clamping
Replace the fragile per-row tail/maxVirtual state with a clean global-
metrics approach:

- Measure cardWidth, stride, paddingLeft, viewportWidth, rightDeadzone
  once from the first synced row; use the same values for all rows.
- Per-row max scroll computed purely from math:
    max(0, paddingLeft + (N-1)*stride - maxVisibleLeft)
  where maxVisibleLeft = viewportWidth - cardWidth - rightDeadzone.
- Global virtual offset (syncedRowsCurrentOffset/targetOffset) is shared
  across all rows; each row clamps independently in applySyncedRowScroll.
- Tail is a global constant (= rightDeadzone) applied to all rows.
- Fix scrolling-back bug: desiredOffset was stuck at currentOffset when
  moving left; now always computed from anchor column position.
- Avoid full animation sweep on view entry: init current/target offset
  from existing DOM scrollLeft on first use.

Also removes per-row --sync-row-max-virtual CSS var and simplifies
.media-row padding to use only --sync-row-tail.
2026-05-25 18:54:21 +00:00
LeoVasanko eee8c973ed fix: per-row tail padding for synced horizontal scroll
- Tail is now computed and applied per-row instead of globally.
- Right-side-only tail padding so item positions don't shift when tail grows.
- Removed anchor-row clamping from effectiveAnchorOffset and targetOffset;
  each row independently clamps the shared virtual offset.
- Rows that fit entirely on screen (maxOffset == 0) keep left alignment.
- Short rows retain their scrolled position when focus moves to longer rows.

Fixes erratic scrolling and zig-zag when navigating across rows of different
lengths in movie/series/search categories.
2026-05-25 17:30:06 +00:00
LeoVasanko a3f5ef5dac Smooth-scroll focused release items into view 2026-05-25 16:20:50 +00:00
LeoVasanko fbf35f7242 Refine movie detail cast rail and nav behavior 2026-05-25 16:18:35 +00:00
LeoVasanko ab1dfffdf3 Restore flex-based people layout in media cards 2026-05-25 15:45:13 +00:00
LeoVasanko 5b57640949 fix: clicking search result no longer redirects to category page
When clicking a search result, showDetail navigates to the detail page.
The route.fullPath watcher then clears searchQuery, which propagates to
Header's localSearch watcher, which emits @search='', which calls
updateSearchQuery(''). This in turn called clearSearch(), which did a
router.replace() to the category page because it didn't check whether
the current route actually had a search query.

The fix: in clearSearch(), if there's no search query in the current
URL, just clear reactive state and return without navigating. This
breaks the circular flow that was overwriting the detail-page
navigation.
2026-05-25 15:32:33 +00:00
LeoVasanko f484ab2606 Clean up movie details metadata layout 2026-05-25 15:24:05 +00:00
LeoVasanko 598cef8926 Adjust media row edge spacing without section padding 2026-05-25 14:57:42 +00:00
LeoVasanko f39473e26e Link header logo to front page 2026-05-25 14:52:36 +00:00
LeoVasanko 31fedcea6c Disable browser fullscreen auto-toggle 2026-05-25 14:49:31 +00:00
LeoVasanko b8cdd460b6 Scroll to view only on mouseup to avoid erratic scrolling during clicks. 2026-05-25 14:43:16 +00:00
LeoVasanko cfa1781192 refactor: hero featured item is a plain link like all other cards
Remove the separate Play and Info buttons from the CollageHero featured
item. All collage items (including the featured one) are now uniform
<a href> links that navigate to the detail page.

- CollageHero: remove hasResumePosition prop, play/info emits, and
  associated play button logic
- App.vue: remove @play and @info bindings from CollageHero
- Delete unused HeroSection.vue component and its styles
2026-05-25 14:25:58 +00:00
LeoVasanko 76c426546b refactor: media cards use proper <a href> links instead of JS navigation
MediaCard, MediaRow, CollageHero, HeroSection, and MediaDetail cast
cards now render as <a> tags with real hrefs. Modified clicks
(ctrl+click, middle-click) navigate natively, enabling open-in-new-tab
and link copying. Plain left-clicks continue through the existing
showDetail flow for side-effects like focus-state saving.
2026-05-25 14:21:13 +00:00
LeoVasanko 1d3d682b60 fix: don't steal focus from search input during focus restoration
When typing in the search bar on a detail page, navigating to search
results would trigger restoreFocusForPage(), which focused the 'last
viewed' card and interrupted typing. Skip focus restoration whenever
the search input is currently the active element.
2026-05-25 13:20:38 +00:00
LeoVasanko 0330a3023a frontend: clamp series hero synopsis to 10 lines 2026-05-25 13:11:12 +00:00
LeoVasanko 1cf3e6a08f frontend: place releases beside poster on narrow movie detail 2026-05-25 13:11:08 +00:00
LeoVasanko 17f8f60f6e fix: constant slant angle for season poster collage hero
The clip-path slant on collage slices previously varied with the number
of posters (hard-coded 10% steps). Express the slant as a percentage
of each slice's own width so the horizontal offset always equals the
fixed 5% container overlap, giving a constant angle for any count >= 2.
2026-05-25 13:02:15 +00:00
LeoVasanko 23379dc2c1 frontend: reduce movie detail poster width under 900px 2026-05-25 03:31:35 +00:00
LeoVasanko b1e775a29b Tuning server.run args for Windows: disable reloads (broken) and use Proactor loop regardless of dev mode. 2026-05-25 03:17:41 +00:00
LeoVasanko f6a40babc9 frontend: add OXC lint/format setup and apply semicolon fixes 2026-05-25 02:54:30 +00:00
LeoVasanko 836a563897 Pathlib fixes. Remaining errors to suppression for now. 2026-05-25 02:42:38 +00:00
LeoVasanko 17c5a47936 Misc. fixes #2. 2026-05-25 02:37:51 +00:00
LeoVasanko e86f1e22de Ignore copyright WTF rule and pylint complexity errors. 2026-05-25 02:32:08 +00:00
LeoVasanko 6646068adc Line too long errors 2026-05-25 02:27:39 +00:00
LeoVasanko 6115a3ff0a Misc. ruff fixes. 2026-05-25 02:22:55 +00:00
LeoVasanko 8d3e872d41 More ignores. 2026-05-25 02:21:44 +00:00
LeoVasanko 3768967e7d BLE001 except Exception replaced for more specific types. 2026-05-25 02:19:41 +00:00
LeoVasanko 54a4b57230 Unsafe fixes. 2026-05-25 02:12:31 +00:00
LeoVasanko 95081ca50e Suppress useless families. 2026-05-25 02:07:38 +00:00
LeoVasanko 0e5251ab91 Ruff automatic fixes and formatting. 2026-05-25 01:57:17 +00:00
LeoVasanko 5f69b5365f Add strict ruff config. 2026-05-25 01:55:51 +00:00
LeoVasanko b835b82e94 Add ETag and 10-minute cache for /api/media 2026-05-24 22:39:29 +00:00
LeoVasanko 93d89e32e2 Handle ffmpeg probe non-zero exits separately 2026-05-24 19:59:12 +00:00
LeoVasanko eeb28e991f Use Windows Shell API for reliable Explorer file selection
Use SHParseDisplayName + SHOpenFolderAndSelectItems to open the parent folder and select files with special-character paths. Keep explorer.exe /n,/select as a fallback when the API path fails.
2026-05-24 19:32:36 +00:00
LeoVasanko 780f223b82 Fix uvicorn forcing SelectorEventLoop on Windows dev mode
Uvicorn's asyncio_loop_factory returns SelectorEventLoop on Windows
whenever reload=True (use_subprocess=True). SelectorEventLoop does not
support asyncio subprocess APIs, causing NotImplementedError in the app.

Fix: pass loop='none' so uvicorn respects the ProactorEventLoop policy
we configure, instead of overriding it. Also suppress the Py3.14
DeprecationWarning on the policy class itself.
2026-05-24 19:14:31 +00:00
LeoVasanko 8586bd26e1 Remove PWA/SW and fix blocking startup I/O
- Remove vite-plugin-pwa and all service worker code. The app no longer
  registers a service worker; legacy SWs are unregistered on load.
- Move snapshot parsing (thousands of sync Path.exists() calls) into a
  thread pool via asyncio.to_thread() so the health check responds
  immediately on startup.
- Wrap aiopathlib AsyncPath.iterdir() (sync os.scandir under the hood)
  in asyncio.to_thread() in scanner and scanning modules so directory
  walks do not monopolize the event loop.
2026-05-24 19:01:13 +00:00
LeoVasanko b574c974a7 Harden ffmpeg subprocess handling and Windows loop policy 2026-05-24 18:06:07 +00:00
LeoVasanko 94f2f10dcd Fix root path handling and release action menus 2026-05-24 17:40:55 +00:00
LeoVasanko 487e410a8f Remove scrollbar. 2026-05-24 02:49:57 +00:00