feat: add MPEG-DASH support with type refactoring#32
Merged
jvillegasd merged 13 commits intomainfrom Mar 3, 2026
Merged
Conversation
Extends the FFmpeg pre-warm logic to cover HlsRecordingHandler. Previously, createOffscreenDocument + WARMUP_FFMPEG only fired for HLS/M3U8 format downloads in handleDownloadRequest. Recordings went through handleStartRecordingMessage which had no pre-warm, so FFmpeg only began loading when the user hit Stop — adding latency at the start of the merge phase. Now recordings pre-warm on the same condition (first active task), matching the behaviour of regular HLS/M3U8 downloads. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Document why IndexedDB is used as the cross-context shared state store, the dual-channel progress update strategy (IDB + sendMessage), and the BasePlaylistHandler cachedState/throttle optimizations. Include an explicit warning against adding getDownload() calls in the onProgress hot path, referencing the UI freeze bug from commit 9f2a21e. Also correct VideoFormat from string union to string enum. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add VideoFormat.DASH and OFFSCREEN_PROCESS_DASH message types - Add mpd-parser utility wrapping the mpd-parser npm package - Add DashDetectionHandler for .mpd URL detection with DRM/live detection - Add DashDownloadHandler for static DASH VOD downloads (video+audio streams) - Add DashRecordingHandler for live DASH stream recording - Extract BaseRecordingHandler from HlsRecordingHandler (template method pattern) - Refactor HlsRecordingHandler to extend BaseRecordingHandler - Add processDashChunks() to offscreen FFmpeg worker (no bsf filter, .mp4 intermediates) - Wire DASH into DetectionManager, DownloadManager, and service worker Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Split parseLevelsPlaylist into two steps: parseMediaPlaylist (HLS) / getVideoPlaylist / getAudioPlaylist (DASH) produce a ParsedPlaylist, then a single parseLevelsPlaylist in playlist-utils.ts converts to Fragment[] for both protocols - Add ParsedSegment and ParsedPlaylist to core types as the shared protocol-agnostic intermediate - Move src/core/types.ts → src/core/types/index.ts; add parser.d.ts alongside it for mpd-parser ambient declarations (replaces orphan src/types/ folder) - Remove MpdPlaylist from public API; handlers now use getVideoPlaylist() instead of inline sort logic Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ning modules Move ParsedSegment and ParsedPlaylist from core/types/index.ts to playlist-utils.ts, where they are produced and consumed. Move FetchFn to fetch-utils.ts as an unexported internal type. Update imports in m3u8-parser.ts and mpd-parser.ts accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Relocate src/core/types/parser.d.ts → src/types/mpd-parser.d.ts to separate vendor type shims from project domain types. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reduces src/core/utils/ from 20 to 11 files by relocating subsystem-specific modules to the directories that own them: core/ffmpeg/ ← ffmpeg-bridge, ffmpeg-singleton, offscreen-manager core/parsers/ ← m3u8-parser, mpd-parser, playlist-utils core/detection/ ← thumbnail-utils core/downloader/ ← crypto-utils, header-rules No logic changes — pure file-move + import-update refactor. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Show a quality picker in the Manifest tab when a DASH MPD contains multiple representations. Highest bandwidth is pre-selected; audio is always auto-included. Single-rep MPDs continue to auto-select with no picker shown. The selected bandwidth flows through the full stack: popup → service worker → DownloadManager / DashRecordingHandler → mpd-parser.getVideoPlaylistByBandwidth(). Also completes DASH live recording audio support: BaseRecordingHandler now carries a separate audioSegmentIndex and storeId for concurrent audio fragment downloads, and resolveMediaUrl() returns both the polling URL and the post-redirect URL for declarativeNetRequest rules. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ave audio loss DASH VOD and HLS master playlist downloads used sequential video-then-audio segment downloading. If the user stopped during the video phase, chunkCount <= videoLength so the stop-and-save formula produced effectiveAudioLength = 0 — no audio in the saved file. Fix: switch both handlers to concurrent download using Promise.allSettled, with audio stored under a separate `downloadId + "_a"` namespace (matching DashRecordingHandler). Stop-and-save now counts video and audio chunks independently via getChunkCount. The offscreen adds processHlsVideoAndAudioSeparate (mirrors the DASH equivalent) and processHLSChunks now requires audioDownloadId for dual-stream mux. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
processVideoAndAudio() and processDashVideoAndAudio() are unreachable now that both HLS and DASH VOD handlers always pass audioDownloadId for separate namespace processing. Replace the if/else branches with a guard throw, matching the pattern already used in processHLSChunks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ment counts Without -shortest, if audio downloaded more segments than video (common since audio segments are smaller and finish faster), the output would have audio extending beyond video end causing a frozen/black frame with audio. Matches the existing -shortest behavior in processHlsVideoAndAudioSeparate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changelog:
DashRecordingHandler inherits the same polling loop
fetch-utils.ts), removing them from the central core/types/index.ts