feat: Add FFmpeg audio transcoding for Dolby/AC3/EAC3 compatibility

- Add /api/transcode endpoint for audio-only transcoding
- Video passthrough (no re-encoding) for fast performance
- Audio transcode to AAC for browser compatibility
- Add 'Force Audio Transcode' setting toggle in UI
- Add ffmpeg-static as optional dependency
- Handle Electron asar.unpacked path for packaged apps
This commit is contained in:
Trevor Mears
2025-12-29 16:52:01 -08:00
parent 61fe03f950
commit 32e0434785
7 changed files with 385 additions and 1 deletions
+11
View File
@@ -343,6 +343,17 @@
directly.</span>
</div>
</div>
<div class="setting-item">
<label class="setting-toggle">
<input type="checkbox" id="setting-force-transcode">
<span class="toggle-slider"></span>
</label>
<div class="setting-info">
<span class="setting-label">Force Audio Transcode</span>
<span class="setting-hint">Transcode audio to AAC for browser compatibility. Enable if you get video
but no audio (fixes Dolby/AC3/EAC3). Requires ffmpeg-static.</span>
</div>
</div>
<div class="setting-item">
<div class="setting-info" style="flex: 1;">
<span class="setting-label">Stream Output Format</span>
+28 -1
View File
@@ -33,7 +33,8 @@ class VideoPlayer {
rememberVolume: true, // Persist volume between sessions
lastVolume: 80, // Last used volume (if rememberVolume is true)
autoPlayNextEpisode: false, // Auto-play next episode in series
forceProxy: false // Force all streams through backend proxy
forceProxy: false, // Force all streams through backend proxy
forceTranscode: false // Force audio transcoding (fixes Dolby/AC3 audio)
};
try {
const saved = localStorage.getItem('nodecast_tv_player_settings');
@@ -202,6 +203,25 @@ class VideoPlayer {
// Determine if HLS or direct stream
this.currentUrl = streamUrl;
// CHECK: Force Transcode Priority - transcoded streams bypass HLS.js
if (this.settings.forceTranscode) {
console.log('[Player] Force Transcode enabled. Routing through ffmpeg...');
const transcodeUrl = this.getTranscodeUrl(streamUrl);
this.currentUrl = transcodeUrl;
// Transcoded streams are fragmented MP4 - play directly with <video> element
console.log('[Player] Playing transcoded stream directly:', transcodeUrl);
this.video.src = transcodeUrl;
this.video.play().catch(e => console.log('[Player] Autoplay prevented:', e));
// Update UI and dispatch events
this.updateNowPlaying(channel);
this.showNowPlayingOverlay();
this.fetchEpgData(channel);
window.dispatchEvent(new CustomEvent('channelChanged', { detail: channel }));
return; // Exit early - don't use HLS.js path
}
// Proactively use proxy for:
// 1. User enabled "Force Proxy" in settings
// 2. Known CORS-restricted domains (like Pluto TV)
@@ -377,6 +397,13 @@ class VideoPlayer {
return `/api/proxy/stream?url=${encodeURIComponent(url)}`;
}
/**
* Get transcoded URL for a stream (audio transcoding for browser compatibility)
*/
getTranscodeUrl(url) {
return `/api/transcode?url=${encodeURIComponent(url)}`;
}
/**
* Decode base64 EPG data
*/
+10
View File
@@ -29,6 +29,7 @@ class SettingsPage {
const rememberVolumeToggle = document.getElementById('setting-remember-volume');
const autoPlayNextToggle = document.getElementById('setting-autoplay-next');
const forceProxyToggle = document.getElementById('setting-force-proxy');
const forceTranscodeToggle = document.getElementById('setting-force-transcode');
// Load current settings
if (this.app.player?.settings) {
@@ -41,6 +42,9 @@ class SettingsPage {
if (forceProxyToggle) {
forceProxyToggle.checked = this.app.player.settings.forceProxy || false;
}
if (forceTranscodeToggle) {
forceTranscodeToggle.checked = this.app.player.settings.forceTranscode || false;
}
}
// Arrow keys toggle
@@ -83,6 +87,12 @@ class SettingsPage {
this.app.player.saveSettings();
});
// Force transcode toggle
forceTranscodeToggle?.addEventListener('change', () => {
this.app.player.settings.forceTranscode = forceTranscodeToggle.checked;
this.app.player.saveSettings();
});
// EPG refresh interval
const epgRefreshSelect = document.getElementById('epg-refresh-interval');
if (epgRefreshSelect) {