Commit Graph

229 Commits

Author SHA1 Message Date
Gauvain
c7c3aa8a34 fix(player): correct prev/next episode buttons at boundaries & for missing episodes
Previous/next were derived from the adjacentTo response's array length,
which wrongly surfaced the current episode as "previous" on the first
episode (e.g. S1E1) and offered "Virtual" (missing) episodes — like an
empty Specials entry — as navigation/autoplay targets.

Derive them from the current item's actual index in the list and skip
neighbours that are the current item or have LocationType 'Virtual'. This
also stops autoplay from advancing into a missing episode.
2026-06-02 00:04:00 +02:00
Gauvain
985cb0f337 Merge origin/develop into refactor-chromecast
Bring 323 commits of develop (incl. the Expo SDK 56 / TV-branch work) into
the chromecast refactor. Conflict resolutions:

- chapters: take develop's reviewed version (ChapterList/ChapterTicks/
  chapters.ts/test) — adds chapterNameAt, markers API, themed Colors.
- auto-skip: keep chromecast's unified useSegmentSkipper for the phone
  player; restore develop's useCreditSkipper/useIntroSkipper (deleted on
  chromecast) so develop's Controls.tv.tsx compiles. TV->useSegmentSkipper
  migration left as follow-up.
- en.json: union the two player blocks (kept chromecast casting keys +
  develop's subtitle/playback keys).
- TechnicalInfoOverlay/PlatformDropdown: take develop's TV-safe versions
  (kept chromecast's disabled-prop branch, aliased to avoid shadowing the
  @expo/ui disabled modifier).
- SDK 56 fixes: expo-router Router -> ImperativeRouter in cast components;
  ChapterTicks markers API in CastPlayerProgressBar.
- restore utils/profiles/chromecast* (deleted on chromecast, still used by
  PlayButton).

Typecheck passes; bun.lock regenerated against merged package.json.
2026-06-01 23:14:35 +02:00
Fredrik Burmester
2166bb3867 feat(sync): auto-refresh on Jellyfin LibraryChanged events
Handle the server's LibraryChanged WebSocket message to invalidate
library-dependent React Query caches when items are added/updated/
removed, so newly added episodes/movies appear without a manual
refresh. Debounced to coalesce a scan's burst of events.

Add useRefreshLibraryOnFocus as a fallback that re-checks on screen
focus (throttled, online-only, skips first focus), wired into home
(mobile + TV) and the library pages.
2026-05-30 13:05:43 +02:00
Fredrik Burmester
a190122eea Merge branch 'develop' into feat/tv-interface
# Conflicts:
#	.gitignore
#	app/(auth)/(tabs)/(home)/_layout.tsx
#	components/PlatformDropdown.tsx
#	components/search/DiscoverFilters.tsx
#	components/video-player/controls/BottomControls.tsx
#	components/video-player/controls/TrickplayBubble.tsx
#	modules/mpv-player/ios/MPVLayerRenderer.swift
2026-05-30 11:08:22 +02:00
Fredrik Burmester
0e531da2e0 fix(watchlists): invalidate watchlists list query on add/remove 2026-05-30 10:03:55 +02:00
lostb1t
07b79de203 fix: Do not cache background request for mediasources (#1602) 2026-05-30 09:11:59 +02:00
Gauvain
0ba3f44615 chore: upgrade Biome to 2.4.16, clean up lint, and fix TV password modal (#1598) 2026-05-29 08:32:21 +02:00
lance chant
eb02ac253a chore: expo 55 upgrade (#1594)
Signed-off-by: Lance Chant <13349722+lancechant@users.noreply.github.com>
Co-authored-by: Fredrik Burmester <fredrik.burmester@gmail.com>
2026-05-27 21:38:08 +02:00
Uruk
2c2a7137d3 fix(autoplay): make Cancel stop the timer and fix stale cast capture state 2026-05-23 23:36:38 +02:00
Uruk
d9e25135c4 feat(casting): add cast autoplay watcher hook 2026-05-23 23:23:54 +02:00
Uruk
57cfa5ce78 feat(casting): extract reusable next-episode helpers 2026-05-23 23:18:55 +02:00
Uruk
c3a9b451b6 fix(casting): clamp trickplay bubble via slider bubbleWidth 2026-05-22 09:55:23 +02:00
Uruk
119b7ad937 refactor(casting): drop unused liveProgress export 2026-05-22 02:43:52 +02:00
Uruk
8b94f491e4 fix(playback): dispatch each remote command once; stabilise controllers 2026-05-22 02:30:29 +02:00
Uruk
e9f61a2f7c fix(casting): guard against stale currentItem during episode load 2026-05-22 02:24:13 +02:00
Uruk
0cc3a8469d fix(casting): report the real PlayMethod to Jellyfin 2026-05-22 02:20:51 +02:00
Uruk
7e2ef0f2da feat(playback): add useRemoteControl dispatch hook 2026-05-22 02:06:12 +02:00
Uruk
1ea7f0f491 refactor(casting): extract useCastPlayerProgress hook 2026-05-22 01:32:21 +02:00
Uruk
79c2829444 refactor(casting): extract useCastDismissGesture hook 2026-05-22 01:22:21 +02:00
Uruk
87e0b0006b refactor(casting): extract useCastEpisodes hook 2026-05-22 01:18:08 +02:00
Uruk
3c71c08591 refactor(casting): extract useCastPlayerItem hook 2026-05-22 01:15:29 +02:00
Uruk
4f50ec6665 feat(casting): add useCastSelection hook 2026-05-21 23:49:23 +02:00
Uruk
bcf6b705e1 refactor(casting): route all cast loads through loadCastMedia
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 02:27:20 +02:00
Uruk
fcd7e46599 fix: resolve 13 review issues across casting components
- casting-player: remove redundant self-navigation useEffect
- casting-player: derive Type from metadata instead of hardcoding 'Movie'
- casting-player: pass null to useTrickplay instead of empty BaseItemDto
- casting-player: use != null for skip time labels (allow 0 to render)
- Chromecast: case-insensitive m3u8 detection via regex
- Chromecast: fix UUID hyphen indices to 4,6,8,10 for proper v4 format
- CastingMiniPlayer: use SeriesPrimaryImageTag for series poster URL
- ChromecastConnectionMenu: send rounded volume to castSession.setVolume
- ChromecastConnectionMenu: use isMutedRef in onValueChange to avoid stale closure
- ChromecastDeviceSheet: skip volume sync during active sliding
- ChromecastDeviceSheet: move unmute logic from onValueChange to onSlidingStart
- useCasting: detect playback start via isPlaying/playerState, not just progress>0
- useCasting: derive isChromecastAvailable from castState instead of hardcoding true
- useTrickplay: accept BaseItemDto|null with null guards on Id access
2026-05-21 00:47:31 +02:00
Uruk
6bf00abb9b fix: Refactors casting player and components
Refactors the casting player screen and related components for improved code clarity, performance, and maintainability.

- Removes unused code and simplifies logic, especially around audio track selection and recommended stereo track handling.
- Improves the formatting of trickplay time displays for consistency.
- Streamlines UI elements and removes unnecessary conditional checks.
- Updates the Chromecast component to use hooks for side effects, ensuring the Chromecast session remains active.
- Improves the display of the language in the audio track display.
2026-05-21 00:47:31 +02:00
Uruk
ac405af3b2 Fix: Improves Chromecast casting experience
Fixes several issues and enhances the Chromecast casting experience:

- Prevents errors when loading media by slimming down the customData payload to avoid exceeding message size limits.
- Improves logic for selecting custom data from media status.
- Fixes an issue with subtitle track selection.
- Recommends stereo audio tracks for better Chromecast compatibility.
- Improves volume control and mute synchronization between the app and the Chromecast device.
- Adds error handling for `loadMedia` in `PlayButton`.
- Fixes image caching issue for season posters in mini player.
- Implements cleanup for scroll retry timeout in episode list.
- Ensures segment skipping functions are asynchronous.
- Resets `hasReportedStartRef` after stopping casting.
- Prevents seeking past the end of Outro segments.
- Reports playback progress more accurately by also taking player state changes into account.
2026-05-21 00:47:31 +02:00
Uruk
9ec81cfa1d Fix: Improves Chromecast casting experience
Fixes several issues and improves the overall Chromecast casting experience:

- Implements an AbortController for fetching item data to prevent race conditions.
- Syncs live progress in the mini player more accurately using elapsed real time.
- Prevents event propagation in the mini player's play/pause button.
- Ensures the disconnect callback in the connection menu is always called.
- Retries scrolling in the episode list on failure.
- Handles unmute failures gracefully in volume controls.
- Clamps seek positions to prevent exceeding duration.
- Fixes reporting playback start multiple times
- Improves segment calculation in `useChromecastSegments`
- Prevents race condition with `isPlaying` state in `Controls` component

Also includes minor UI and timing adjustments for a smoother user experience.
2026-05-21 00:47:31 +02:00
Uruk
28bf1489c1 Fix: Improve casting and segment skipping
Fixes several issues and improves the casting player experience.

- Adds the ability to disable segment skipping options based on plugin settings.
- Improves Chromecast integration by:
  - Adding PlaySessionId for better tracking.
  - Improves audio track selection
  - Uses mediaInfo builder for loading media.
  - Adds support for loading next/previous episodes
  - Translation support
- Updates progress reporting to Jellyfin to be more accurate and reliable.
- Fixes an error message in the direct player.
2026-05-21 00:47:31 +02:00
Uruk
9dcbcdc41d fix: Refactors Chromecast casting player
Refactors the Chromecast casting player for better compatibility, UI improvements, and stability.

- Adds auto-selection of stereo audio tracks for improved Chromecast compatibility
- Refactors episode list to filter out virtual episodes and allow season selection
- Improves UI layout and styling
- Removes connection quality indicator
- Fixes progress reporting to Jellyfin
- Updates volume control to use CastSession for device volume
2026-05-21 00:47:31 +02:00
Uruk
99775b353f feat: Enhances casting player with API data
Enriches the casting player screen by fetching item details from the Jellyfin API for a more reliable and complete user experience.

The casting player now prioritizes item data fetched directly from the API, providing richer metadata and ensuring accurate information display.

- Fetches full item data based on content ID.
- Uses fetched data as the primary source of item information, falling back to customData or minimal info if unavailable.
- Improves UI by showing connection quality and bitrate.
- Enhances episode list display and scrolling.
- Adds a stop casting button.
- Minor UI adjustments for better readability and aesthetics.

This change enhances the accuracy and reliability of displayed information, improving the overall user experience of the casting player.
2026-05-21 00:47:31 +02:00
Uruk
51bd8a92da refactor(casting): remove AirPlay references, keep extensible architecture
- Remove AirPlay from CastProtocol type union (Chromecast only for now)
- Replace AirPlay TODOs with generic 'Future: Add X for other protocols' comments
- Remove PROTOCOL_COLORS export, use hardcoded Chromecast color (#F9AB00)
- Update all component headers to be protocol-agnostic
- Keep switch statements extensible for future protocol additions
- Maintain clean architecture for easy integration of new casting protocols

Architecture remains flexible for future protocols (AirPlay, DLNA, etc.)
2026-05-21 00:47:31 +02:00
Uruk
7126564f72 feat(casting): complete all remaining TODOs
- Expose RemoteMediaClient from useCasting for advanced operations
- Implement episode fetching from Jellyfin API for TV shows
- Add next episode detection with countdown UI showing episode name
- Wire audio/subtitle track changes to RemoteMediaClient.setActiveTrackIds
- Wire playback speed to RemoteMediaClient.setPlaybackRate
- Add tap-to-seek functionality to progress bar
- Update segment skip buttons to use remoteMediaClient seek wrapper
- Create comprehensive AirPlay implementation documentation

All casting system features are now complete before PR submission.
2026-05-21 00:47:31 +02:00
Uruk
6894decdba feat: optimize and complete casting system implementation
Performance Optimizations:
- Add progress tracking to skip redundant Jellyfin API calls (< 5s changes)
- Debounce volume changes (300ms) to reduce API load
- Memoize expensive calculations (protocol colors, icons, progress percent)
- Remove dead useChromecastPlayer hook (redundant with useCasting)

Feature Integrations:
- Add ChromecastEpisodeList modal with Episodes button for TV shows
- Add ChromecastDeviceSheet modal accessible via device indicator
- Add ChromecastSettingsMenu modal with settings icon
- Integrate segment detection with Skip Intro/Credits/Recap buttons
- Add next episode countdown UI (30s before end)

AirPlay Support:
- Add comprehensive documentation for AirPlay detection approaches
- Document integration requirements with AVRoutePickerView
- Prepare infrastructure for native module or AVPlayer integration

UI Improvements:
- Make device indicator tappable to open device sheet
- Add settings icon in header
- Show segment skip buttons dynamically based on current playback
- Display next episode countdown with cancel option
- Optimize hook ordering to prevent conditional hook violations

TODOs for future work:
- Fetch actual episode list from Jellyfin API
- Wire media source/audio/subtitle track selectors to player
- Implement episode auto-play logic
- Create native module for AirPlay state detection
- Add RemoteMediaClient to segment skip functions
2026-05-21 00:47:31 +02:00
Uruk
72c050b9a5 refactor: clean up dead code and consolidate casting utilities
- Remove dead Chromecast files (ChromecastMiniPlayer, chromecast-player)
- Remove dead AirPlay files (AirPlayMiniPlayer, airplay-player, useAirPlayPlayer)
- Remove duplicate AirPlay utilities (options.ts, helpers.ts)
- Consolidate unique Chromecast helpers into unified casting helpers
  - Add formatEpisodeInfo and shouldShowNextEpisodeCountdown
- Update all imports to use unified casting utilities
- Fix TypeScript errors:
  - Use correct MediaStatus properties (playerState vs isPaused/isBuffering)
  - Use getPlaystateApi from Jellyfin SDK
  - Use setStreamVolume for RemoteMediaClient
  - Fix calculateEndingTime signature
  - Fix segment auto-skip to use proper settings (skipIntro, skipOutro, etc)
  - Remove unused imports
- Update ChromecastSettingsMenu to use unified types from casting/types.ts
2026-05-21 00:47:31 +02:00
Uruk
1da3d7cfc6 feat(casting): unify Chromecast and AirPlay into single casting interface
BREAKING CHANGE: Merged separate Chromecast and AirPlay implementations into unified casting system

- Created unified casting types and helpers (utils/casting/)
- Built useCasting hook that manages both protocols
- Single CastingMiniPlayer component works with both Chromecast and AirPlay
- Single casting-player modal for full-screen controls
- Protocol-aware UI: Red for Chromecast, Blue for AirPlay
- Shows device type icon (TV for Chromecast, Apple logo for AirPlay)
- Detects active protocol automatically
- Previous separate implementations (ChromecastMiniPlayer, AirPlayMiniPlayer) superseded

Benefits:
- Better UX: One cast button shows all available devices
- Cleaner architecture: Protocol differences abstracted
- Easier maintenance: Single UI codebase
- Protocol-specific logic isolated in adapters
2026-05-21 00:47:31 +02:00
Uruk
25730a24d6 fix: update dependencies in skipSegment callback for accurate state tracking 2026-05-21 00:47:31 +02:00
Uruk
203c6d59b0 refactor: address GitHub Copilot review comments
- Remove unnecessary currentSegment from skipSegment dependency array
- Remove redundant wrappedSeek wrapper (ref guard prevents issues)
- Document 200ms setTimeout delay for seek operations
- Improve code clarity and reduce unnecessary re-renders
2026-05-21 00:47:31 +02:00
Uruk
0b6639fc4e feat: add comprehensive segment skip with all 5 types and settings submenu
- Add SegmentSkipMode type ('none', 'ask', 'auto') in settings.ts
- Create 5 segment skip settings: skipIntro, skipOutro, skipRecap, skipCommercial, skipPreview
- Update segments.ts to fetch all 5 segment types from Jellyfin MediaSegments API (10.11+)
- Create unified useSegmentSkipper hook supporting all segment types with 3 modes
- Update video player Controls.tsx with priority system (Commercial > Recap > Intro > Preview > Outro)
- Add dynamic skip button text in BottomControls.tsx
- Create dedicated settings submenu at settings/segment-skip/page.tsx
- Simplify PlaybackControlsSettings.tsx with navigation to submenu
- Extend DownloadedItem interface with all segment types for offline support
- Add 13+ translation keys for segment skip UI
2026-05-21 00:47:31 +02:00
Steve Byatt
4bef386b82 fix(tvOS): Patches for udp and screens menu button handling (#1564) 2026-05-20 15:30:40 +02:00
Steve Byatt
ca4f24ded0 fix: handle TV menu and back navigation (#1559) 2026-05-20 09:57:19 +02:00
Fredrik Burmester
c35e97f388 feat(tv): persist downloaded opensubtitles across app restarts 2026-02-01 19:19:32 +01:00
Fredrik Burmester
7d0b3be8c2 chore(tv): remove debug logs from back handler 2026-02-01 16:27:32 +01:00
Fredrik Burmester
85a74a9a6a refactor: login page 2026-01-31 10:52:21 +01:00
Fredrik Burmester
6e85c8d54a feat(tv): add user switching from settings 2026-01-31 09:53:54 +01:00
Fredrik Burmester
8ecb7c205b feat(tv): add smart back button handler to prevent unwanted app exit 2026-01-29 21:53:45 +01:00
Fredrik Burmester
2c0a9b6cd9 feat(tv): migrate login to white design with navigation modals 2026-01-29 12:12:20 +01:00
Fredrik Burmester
4bea01c963 fix(tv): prevent theme music from playing twice on shared transitions 2026-01-29 07:31:34 +01:00
Fredrik Burmester
409629bb4a feat(tv): add background theme music playback 2026-01-28 22:08:32 +01:00
Fredrik Burmester
2ff9625903 feat(tv): add long-press mark as watched action using alert dialog 2026-01-28 20:36:57 +01:00
Fredrik Burmester
7fe24369c0 feat(tv): add language-based audio and subtitle track selection 2026-01-26 19:32:06 +01:00