mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-05-28 01:28:27 +01:00
Closes #1312 Fixes #883 Adds a unified segment skip feature using the Jellyfin 10.11+ MediaSegments API. Replaces the legacy intro-only and credits-only hooks with a single useSegmentSkipper hook covering Intro, Outro, Recap, Commercial, and Preview. Three modes per segment type: none, ask (show button), auto (skip automatically). A dedicated submenu under Playback Controls keeps the main settings page uncluttered. Highlights: - utils/segments.ts uses getMediaSegmentsApi from @jellyfin/sdk so includeSegmentTypes is serialized as repeated keys instead of the bracket-encoded form axios produces by default (the Jellyfin server silently ignored the filter otherwise). Falls back to the pre-10.11 intro-skipper / chapter-credits plugin endpoints when the new API is unavailable. - hooks/useSegmentSkipper.ts stores seek and haptic in refs so the auto-skip effect does not re-run when their identities change (useHaptic returns a fresh no-op every render when disabled). currentSegment is memoized; the per-segment-type setting lookup uses a small map instead of a switch IIFE. - components/video-player/controls/Controls.tsx prioritizes Commercial > Recap > Intro > Preview > Outro when multiple segments overlap and exposes the active type to BottomControls via skipButtonText. - components/video-player/controls/BottomControls.tsx accepts the dynamic skipButtonText/skipCreditButtonText props. - providers/Downloads/types.ts extends DownloadedItem with the three new segment buckets for offline playback. - utils/atoms/settings.ts adds SegmentSkipMode and the five skip settings, defaulting to "ask". - app/(auth)/(tabs)/(home)/settings/segment-skip/page.tsx renders the five dropdowns from a data table. - translations/en.json and translations/fr.json add the new keys.
Downloads Module
This module handles all download functionality for the Streamyfin app, including video downloads, subtitles, trickplay images, and cover images.
Architecture
The downloads module is structured with a clean separation of concerns:
Core Files
database.ts- Pure functions for MMKV database operationsfileOperations.ts- Pure functions for file system operationsutils.ts- Pure utility functions (filename generation, URI conversion)additionalDownloads.ts- Pure functions for downloading additional assetsnotifications.ts- Pure functions for notification handlingtypes.ts- TypeScript type definitions
Hooks
useDownloadOperations.ts- Hook providing download operations (start, cancel, delete)useDownloadEventHandlers.ts- Hook setting up native download event listeners
Main Provider
DownloadProvider.tsx- React context provider that orchestrates all download functionality
Features
Video Downloads
- Background download support using native module
- Progress tracking and reporting
- Pause/resume capability (future enhancement)
- Download queue management
Additional Assets (Automatic)
When a video download completes, the following are automatically downloaded:
- Trickplay Images - Preview thumbnail sheets for video scrubbing
- Subtitles - External subtitle files (for non-transcoded content)
- Cover Images - Primary item images and series images
- Segments - Intro and credit skip timestamps
File Management
- Automatic cleanup of all associated files (video, subtitles, trickplay)
- Size calculation including all assets
- Batch delete operations
Implementation Details
Pure Functions
All core logic is implemented as pure functions that:
- Take explicit parameters
- Return explicit values
- Have no side effects
- Are easily testable
Imperative Design
The module uses imperative function calls rather than reactive patterns:
- Direct function invocation
- Explicit error handling
- Clear control flow
- Minimal side effects
Storage
- MMKV - Used for persistent database storage
- expo-file-system - Used for file operations
- Native module - Used for background downloads
Usage
import { useDownload } from '@/providers/DownloadProvider';
function MyComponent() {
const {
startBackgroundDownload,
cancelDownload,
deleteFile,
getDownloadedItems,
processes,
} = useDownload();
// Start a download
await startBackgroundDownload(url, item, mediaSource, bitrate);
// Cancel a download
await cancelDownload(itemId);
// Delete a download
await deleteFile(itemId);
// Get all downloads
const items = getDownloadedItems();
}
Event Flow
-
Start Download
- Pre-download cover images
- Start video download via native module
- Track progress via event listeners
-
Download Progress
- Native module emits progress events
- React state updated with progress percentage
- UI reflects current download state
-
Download Complete
- Video file saved to disk
- Additional assets downloaded in parallel:
- Trickplay images
- Subtitles (if applicable)
- Segments data
- Item saved to database
- Notification sent
- Process removed from queue
-
Delete
- Item removed from database
- All associated files deleted:
- Video file
- Subtitle files
- Trickplay directory
File Structure
providers/Downloads/
├── additionalDownloads.ts # Trickplay, subtitles, cover images
├── database.ts # MMKV operations
├── fileOperations.ts # File system operations
├── notifications.ts # Notification helpers
├── types.ts # TypeScript types
├── utils.ts # Utility functions
├── index.ts # Module exports
├── hooks/
│ ├── useDownloadEventHandlers.ts
│ └── useDownloadOperations.ts
└── README.md # This file
Future Enhancements
- Background download scheduling
- Network condition awareness
- Download priority management
- Automatic cleanup of old downloads
- Series season download management