Add Force Proxy setting, fix redirect URL handling (PR #7)
This commit is contained in:
@@ -296,6 +296,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-section">
|
||||||
|
<h3>Streaming</h3>
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="setting-toggle">
|
||||||
|
<input type="checkbox" id="setting-force-proxy">
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
<div class="setting-info">
|
||||||
|
<span class="setting-label">Force Backend Proxy</span>
|
||||||
|
<span class="setting-hint">Route all streams through the proxy server. Enable if streams don't play directly.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h3>Keyboard Shortcuts</h3>
|
<h3>Keyboard Shortcuts</h3>
|
||||||
<div class="shortcuts-grid">
|
<div class="shortcuts-grid">
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ class VideoPlayer {
|
|||||||
defaultVolume: 80, // 0-100
|
defaultVolume: 80, // 0-100
|
||||||
rememberVolume: true, // Persist volume between sessions
|
rememberVolume: true, // Persist volume between sessions
|
||||||
lastVolume: 80, // Last used volume (if rememberVolume is true)
|
lastVolume: 80, // Last used volume (if rememberVolume is true)
|
||||||
autoPlayNextEpisode: false // Auto-play next episode in series
|
autoPlayNextEpisode: false, // Auto-play next episode in series
|
||||||
|
forceProxy: false // Force all streams through backend proxy
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const saved = localStorage.getItem('nodecast_tv_player_settings');
|
const saved = localStorage.getItem('nodecast_tv_player_settings');
|
||||||
@@ -201,10 +202,12 @@ class VideoPlayer {
|
|||||||
// Determine if HLS or direct stream
|
// Determine if HLS or direct stream
|
||||||
this.currentUrl = streamUrl;
|
this.currentUrl = streamUrl;
|
||||||
|
|
||||||
// Proactively use proxy for known CORS-restricted domains (like Pluto TV)
|
// Proactively use proxy for:
|
||||||
|
// 1. User enabled "Force Proxy" in settings
|
||||||
|
// 2. Known CORS-restricted domains (like Pluto TV)
|
||||||
// Note: Xtream sources are NOT auto-proxied because many providers IP-lock streams
|
// Note: Xtream sources are NOT auto-proxied because many providers IP-lock streams
|
||||||
const proxyRequiredDomains = ['pluto.tv'];
|
const proxyRequiredDomains = ['pluto.tv'];
|
||||||
const needsProxy = proxyRequiredDomains.some(domain => streamUrl.includes(domain));
|
const needsProxy = this.settings.forceProxy || proxyRequiredDomains.some(domain => streamUrl.includes(domain));
|
||||||
|
|
||||||
this.isUsingProxy = needsProxy;
|
this.isUsingProxy = needsProxy;
|
||||||
const finalUrl = needsProxy ? this.getProxiedUrl(streamUrl) : streamUrl;
|
const finalUrl = needsProxy ? this.getProxiedUrl(streamUrl) : streamUrl;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class SettingsPage {
|
|||||||
const volumeValueDisplay = document.getElementById('volume-value');
|
const volumeValueDisplay = document.getElementById('volume-value');
|
||||||
const rememberVolumeToggle = document.getElementById('setting-remember-volume');
|
const rememberVolumeToggle = document.getElementById('setting-remember-volume');
|
||||||
const autoPlayNextToggle = document.getElementById('setting-autoplay-next');
|
const autoPlayNextToggle = document.getElementById('setting-autoplay-next');
|
||||||
|
const forceProxyToggle = document.getElementById('setting-force-proxy');
|
||||||
|
|
||||||
// Load current settings
|
// Load current settings
|
||||||
if (this.app.player?.settings) {
|
if (this.app.player?.settings) {
|
||||||
@@ -37,6 +38,9 @@ class SettingsPage {
|
|||||||
volumeValueDisplay.textContent = this.app.player.settings.defaultVolume + '%';
|
volumeValueDisplay.textContent = this.app.player.settings.defaultVolume + '%';
|
||||||
rememberVolumeToggle.checked = this.app.player.settings.rememberVolume;
|
rememberVolumeToggle.checked = this.app.player.settings.rememberVolume;
|
||||||
autoPlayNextToggle.checked = this.app.player.settings.autoPlayNextEpisode;
|
autoPlayNextToggle.checked = this.app.player.settings.autoPlayNextEpisode;
|
||||||
|
if (forceProxyToggle) {
|
||||||
|
forceProxyToggle.checked = this.app.player.settings.forceProxy || false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arrow keys toggle
|
// Arrow keys toggle
|
||||||
@@ -73,6 +77,12 @@ class SettingsPage {
|
|||||||
this.app.player.saveSettings();
|
this.app.player.saveSettings();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Force proxy toggle
|
||||||
|
forceProxyToggle?.addEventListener('change', () => {
|
||||||
|
this.app.player.settings.forceProxy = forceProxyToggle.checked;
|
||||||
|
this.app.player.saveSettings();
|
||||||
|
});
|
||||||
|
|
||||||
// EPG refresh interval
|
// EPG refresh interval
|
||||||
const epgRefreshSelect = document.getElementById('epg-refresh-interval');
|
const epgRefreshSelect = document.getElementById('epg-refresh-interval');
|
||||||
if (epgRefreshSelect) {
|
if (epgRefreshSelect) {
|
||||||
|
|||||||
@@ -295,17 +295,19 @@ router.get('/stream', async (req, res) => {
|
|||||||
// Check if it's an HLS manifest by looking at first bytes (#EXTM3U = 23 45 58 54 4D 33 55)
|
// Check if it's an HLS manifest by looking at first bytes (#EXTM3U = 23 45 58 54 4D 33 55)
|
||||||
const textPrefix = String.fromCharCode(...bytes.slice(0, 7));
|
const textPrefix = String.fromCharCode(...bytes.slice(0, 7));
|
||||||
const contentLooksLikeHls = textPrefix === '#EXTM3U';
|
const contentLooksLikeHls = textPrefix === '#EXTM3U';
|
||||||
const urlLooksLikeHls = contentType.includes('mpegurl') || contentType.includes('application/x-mpegURL') || url.toLowerCase().includes('.m3u8');
|
|
||||||
|
|
||||||
if (contentLooksLikeHls) {
|
if (contentLooksLikeHls) {
|
||||||
console.log(`[Proxy] Processing HLS manifest from: ${url.substring(0, 80)}...`);
|
// Use the final URL after redirects for base URL calculation
|
||||||
|
// This is critical for Xtream CDNs that redirect to different servers
|
||||||
|
const finalUrl = response.url || url;
|
||||||
|
console.log(`[Proxy] Processing HLS manifest from: ${finalUrl.substring(0, 80)}...`);
|
||||||
res.set('Content-Type', 'application/vnd.apple.mpegurl');
|
res.set('Content-Type', 'application/vnd.apple.mpegurl');
|
||||||
|
|
||||||
let manifest = Buffer.from(buffer).toString('utf-8');
|
let manifest = Buffer.from(buffer).toString('utf-8');
|
||||||
// Rewrite URLs inside manifest
|
// Rewrite URLs inside manifest
|
||||||
|
|
||||||
const urlObj = new URL(url);
|
const finalUrlObj = new URL(finalUrl);
|
||||||
const baseUrl = urlObj.origin + urlObj.pathname.substring(0, urlObj.pathname.lastIndexOf('/') + 1);
|
const baseUrl = finalUrlObj.origin + finalUrlObj.pathname.substring(0, finalUrlObj.pathname.lastIndexOf('/') + 1);
|
||||||
console.log(`[Proxy] Base URL for rewriting: ${baseUrl}`);
|
console.log(`[Proxy] Base URL for rewriting: ${baseUrl}`);
|
||||||
|
|
||||||
manifest = manifest.split('\n').map(line => {
|
manifest = manifest.split('\n').map(line => {
|
||||||
|
|||||||
Reference in New Issue
Block a user