Instancia transcoder t1: cambios locales
This commit is contained in:
@@ -28,6 +28,9 @@ class VideoPlayer {
|
||||
this.isUsingProxy = false;
|
||||
this.currentUrl = null;
|
||||
this.settingsLoaded = false;
|
||||
this.switchInProgress = false;
|
||||
this.queuedSwitch = null;
|
||||
this.lastSwitchAt = 0;
|
||||
|
||||
// Settings - start with defaults, load from server async
|
||||
this.settings = this.getDefaultSettings();
|
||||
@@ -53,7 +56,7 @@ class VideoPlayer {
|
||||
forceTranscode: false,
|
||||
forceRemux: false,
|
||||
autoTranscode: true,
|
||||
streamFormat: 'm3u8',
|
||||
streamFormat: 'ts',
|
||||
epgRefreshInterval: '24'
|
||||
};
|
||||
}
|
||||
@@ -71,7 +74,7 @@ class VideoPlayer {
|
||||
console.warn('[Player] Failed to load settings from server, using defaults:', err.message);
|
||||
// Fall back to localStorage for backwards compatibility
|
||||
try {
|
||||
const saved = localStorage.getItem('nodecast_tv_player_settings');
|
||||
const saved = localStorage.getItem('kiratv_player_settings');
|
||||
if (saved) {
|
||||
this.settings = { ...this.getDefaultSettings(), ...JSON.parse(saved) };
|
||||
console.log('[Player] Settings loaded from localStorage (fallback)');
|
||||
@@ -93,7 +96,7 @@ class VideoPlayer {
|
||||
console.error('[Player] Error saving settings to server:', err);
|
||||
// Also save to localStorage as backup
|
||||
try {
|
||||
localStorage.setItem('nodecast_tv_player_settings', JSON.stringify(this.settings));
|
||||
localStorage.setItem('kiratv_player_settings', JSON.stringify(this.settings));
|
||||
} catch (localErr) {
|
||||
console.error('[Player] Error saving to localStorage:', localErr);
|
||||
}
|
||||
@@ -813,37 +816,58 @@ class VideoPlayer {
|
||||
* Start a HLS transcode session
|
||||
*/
|
||||
async startTranscodeSession(url, options = {}) {
|
||||
try {
|
||||
console.log('[Player] Starting HLS transcode session...', options);
|
||||
const res = await fetch('/api/transcode/session', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ url, ...options })
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to start session');
|
||||
const session = await res.json();
|
||||
this.currentSessionId = session.sessionId;
|
||||
return session.playlistUrl;
|
||||
} catch (err) {
|
||||
console.error('[Player] Session start failed:', err);
|
||||
// Fallback to direct transcode if session fails
|
||||
return `/api/transcode?url=${encodeURIComponent(url)}`;
|
||||
console.log('[Player] Starting HLS transcode session...', options);
|
||||
let lastError = null;
|
||||
|
||||
// Retry a couple of times to ride out provider-side 5xx/rate-limit spikes.
|
||||
for (let attempt = 1; attempt <= 3; attempt++) {
|
||||
try {
|
||||
const res = await fetch('/api/transcode/session', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ url, ...options })
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to start session (${res.status})`);
|
||||
}
|
||||
const session = await res.json();
|
||||
this.currentSessionId = session.sessionId;
|
||||
return session.playlistUrl;
|
||||
} catch (err) {
|
||||
lastError = err;
|
||||
console.warn(`[Player] Session start failed (attempt ${attempt}/3):`, err?.message || err);
|
||||
if (attempt < 3) {
|
||||
await new Promise(resolve => setTimeout(resolve, 900));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid fallback to /api/transcode direct stream: it tends to overlap sessions
|
||||
// and breaks providers with strict single-connection limits.
|
||||
throw lastError || new Error('Failed to start transcode session');
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop and cleanup current transcode session
|
||||
*/
|
||||
async stopTranscodeSession() {
|
||||
if (this.currentSessionId) {
|
||||
console.log('[Player] Stopping transcode session:', this.currentSessionId);
|
||||
try {
|
||||
// Fire and forget cleanup
|
||||
fetch(`/api/transcode/${this.currentSessionId}`, { method: 'DELETE' });
|
||||
} catch (err) {
|
||||
if (!this.currentSessionId) return;
|
||||
|
||||
const sessionId = this.currentSessionId;
|
||||
this.currentSessionId = null;
|
||||
console.log('[Player] Stopping transcode session:', sessionId);
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), 1500);
|
||||
await fetch(`/api/transcode/${sessionId}`, {
|
||||
method: 'DELETE',
|
||||
signal: controller.signal
|
||||
});
|
||||
clearTimeout(timer);
|
||||
} catch (err) {
|
||||
if (err?.name !== 'AbortError') {
|
||||
console.error('Failed to stop session:', err);
|
||||
}
|
||||
this.currentSessionId = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -851,14 +875,26 @@ class VideoPlayer {
|
||||
* Play a channel
|
||||
*/
|
||||
async play(channel, streamUrl) {
|
||||
// Avoid overlapping channel changes; keep only the latest zap request.
|
||||
if (this.switchInProgress) {
|
||||
this.queuedSwitch = { channel, streamUrl };
|
||||
return;
|
||||
}
|
||||
this.switchInProgress = true;
|
||||
this.currentChannel = channel;
|
||||
|
||||
try {
|
||||
// Stop any WatchPage playback (movies/series) before starting Live TV
|
||||
window.app?.pages?.watch?.stop?.();
|
||||
|
||||
// Stop current playback
|
||||
this.stop();
|
||||
// Stop current playback (sends DELETE to worker → FFmpeg dies → Dispatcharr frees the slot)
|
||||
await this.stop();
|
||||
|
||||
// Give Dispatcharr enough time to release the stream slot before probing the new channel.
|
||||
// 2500ms covers most providers; retries in the probe endpoint handle the edge cases.
|
||||
await new Promise(resolve => setTimeout(resolve, 2500));
|
||||
|
||||
this.lastSwitchAt = Date.now();
|
||||
this.updateTranscodeStatus('hidden');
|
||||
|
||||
// Hide "select a channel" overlay
|
||||
@@ -932,15 +968,18 @@ class VideoPlayer {
|
||||
window.dispatchEvent(new CustomEvent('channelChanged', { detail: channel }));
|
||||
return;
|
||||
} else if (info.needsRemux) {
|
||||
// Raw .ts container - use remux
|
||||
console.log('[Player] Auto: Using remux (.ts container)');
|
||||
this.updateTranscodeStatus('remuxing', 'Remux (Auto)');
|
||||
const remuxUrl = `/api/remux?url=${encodeURIComponent(streamUrl)}`;
|
||||
this.currentUrl = remuxUrl;
|
||||
this.video.src = remuxUrl;
|
||||
this.video.play().catch(e => {
|
||||
if (e.name !== 'AbortError') console.log('[Player] Autoplay prevented:', e);
|
||||
// Algunos streams TS fallan en remux directo (ffmpeg mp4 mux errors).
|
||||
// En ese caso es mas estable usar sesion HLS con video copy.
|
||||
console.log('[Player] Auto: Using HLS transcode session (copy for remux-needed stream)');
|
||||
this.updateTranscodeStatus('transcoding', 'Transcoding (Auto)');
|
||||
const playlistUrl = await this.startTranscodeSession(streamUrl, {
|
||||
videoMode: 'copy',
|
||||
videoCodec: info.video,
|
||||
audioCodec: info.audio,
|
||||
audioChannels: info.audioChannels
|
||||
});
|
||||
this.currentUrl = playlistUrl;
|
||||
this.playHls(playlistUrl);
|
||||
this.updateNowPlaying(channel);
|
||||
this.showNowPlayingOverlay();
|
||||
this.fetchEpgData(channel);
|
||||
@@ -1183,6 +1222,13 @@ class VideoPlayer {
|
||||
} catch (err) {
|
||||
console.error('Error playing channel:', err);
|
||||
this.showError('Failed to play channel');
|
||||
} finally {
|
||||
this.switchInProgress = false;
|
||||
if (this.queuedSwitch) {
|
||||
const next = this.queuedSwitch;
|
||||
this.queuedSwitch = null;
|
||||
this.play(next.channel, next.streamUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1387,9 +1433,9 @@ class VideoPlayer {
|
||||
/**
|
||||
* Stop playback
|
||||
*/
|
||||
stop() {
|
||||
async stop() {
|
||||
// Stop any running transcode session first
|
||||
this.stopTranscodeSession();
|
||||
await this.stopTranscodeSession();
|
||||
|
||||
if (this.hls) {
|
||||
this.hls.destroy();
|
||||
|
||||
Reference in New Issue
Block a user