Share decoder live sources and bound web playback startup
This commit is contained in:
@@ -1,22 +1,63 @@
|
||||
// Jellyfin Web's supported window plugin API supplies the native playback manager.
|
||||
window.DecoderChannelPlayback = async () => class DecoderChannelPlayback {
|
||||
constructor({ playbackManager, toast }) {
|
||||
constructor({ playbackManager, toast, appRouter, loading, events }) {
|
||||
this.id = 'decoder-channel-playback';
|
||||
this.name = 'Decoder channel playback';
|
||||
this.type = 'integration';
|
||||
const play = async (id, serverId) => {
|
||||
const api = window.ApiClient;
|
||||
if (!api?.getCurrentUserId() || (serverId && api.serverId() !== serverId)) return false;
|
||||
const item = await api.getItem(api.getCurrentUserId(), id);
|
||||
if (item.Type !== 'TvChannel') throw Error('Expected a TV channel');
|
||||
await playbackManager.play({ items: [item] });
|
||||
return true;
|
||||
let generation = 0, starting = null, cancelButton = null, watcher = null;
|
||||
const clearControls = () => { clearInterval(watcher); watcher = null; cancelButton?.remove(); cancelButton = null; };
|
||||
events.on(playbackManager, 'playbackstop', () => { if (!starting) clearControls(); });
|
||||
document.addEventListener('fullscreenchange', () => {
|
||||
if (cancelButton) (document.fullscreenElement || document.body).append(cancelButton);
|
||||
});
|
||||
const leave = async () => {
|
||||
++generation; starting = null; clearControls();
|
||||
try { await playbackManager.stop(); } finally { loading.hide(); await appRouter.show('livetv?tab=2'); }
|
||||
};
|
||||
const play = (id, serverId) => {
|
||||
if (starting) return starting;
|
||||
const ticket = ++generation;
|
||||
let request;
|
||||
request = (async () => {
|
||||
const api = window.ApiClient;
|
||||
if (!api?.getCurrentUserId() || (serverId && api.serverId() !== serverId)) return false;
|
||||
const item = await api.getItem(api.getCurrentUserId(), id);
|
||||
if (ticket !== generation) return false;
|
||||
if (item.Type !== 'TvChannel') throw Error('Expected a TV channel');
|
||||
clearControls();
|
||||
cancelButton = document.createElement('button');
|
||||
cancelButton.id = 'decoderPlaybackExit'; cancelButton.textContent = 'Zatrzymaj i wróć do kanałów';
|
||||
cancelButton.style.cssText = 'position:fixed;right:16px;top:72px;z-index:2147483647;background:#252525;color:white;border:1px solid #aaa;border-radius:6px;padding:12px;font:16px system-ui;cursor:pointer';
|
||||
cancelButton.onclick = () => void leave(); document.body.append(cancelButton);
|
||||
let opened = false; const deadline = Date.now() + 25000;
|
||||
watcher = setInterval(() => {
|
||||
if (ticket !== generation) return;
|
||||
const video = document.querySelector('video');
|
||||
const player = playbackManager.getCurrentPlayer();
|
||||
if (player?.isLocalPlayer === false) { clearControls(); return; }
|
||||
if (!opened && video && player) { opened = true; void appRouter.showVideoOsd(); }
|
||||
if (video?.readyState >= 2 && video.currentTime > 0) return;
|
||||
if (Date.now() >= deadline) { void leave(); toast('Kanał nie przesyła obrazu. Powrót do listy kanałów.'); }
|
||||
}, 250);
|
||||
try { await playbackManager.play({ items: [item], fullscreen: true }); }
|
||||
catch (error) { if (ticket !== generation) return false; await leave(); throw error; }
|
||||
return true;
|
||||
})().finally(() => { if (starting === request) starting = null; });
|
||||
starting = request; return request;
|
||||
};
|
||||
window.addEventListener('keydown', event => {
|
||||
if (event.key === 'Escape' && cancelButton) { event.preventDefault(); event.stopImmediatePropagation(); void leave(); }
|
||||
}, true);
|
||||
let pending;
|
||||
const handleRoute = () => {
|
||||
clearTimeout(pending);
|
||||
const route = location.hash;
|
||||
const query = new URLSearchParams(route.split('?')[1] || '');
|
||||
if (route.split('?')[0].toLowerCase() === '#/livetv' && !query.has('tab')) {
|
||||
query.set('tab', '2');
|
||||
location.replace('#/livetv?' + query);
|
||||
return;
|
||||
}
|
||||
const id = query.get('decoderPlay');
|
||||
if (!id || !/^[a-f\d]{32}$|^[a-f\d-]{36}$/i.test(id)) return;
|
||||
const deadline = Date.now() + 30000;
|
||||
|
||||
Reference in New Issue
Block a user