fix: PWA Direct-Play statt HLS + Template-Fix series_detail
- Browser/PWA nutzt jetzt direkte MP4-Wiedergabe mit Range-Requests - Codec-Pruefung (H.264/HEVC/AV1) mit automatischem HLS-Fallback - direct_play_url zur Library Video-Info-Route hinzugefuegt - Doppeltes endblock in series_detail.html entfernt (500er Fehler) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0d1619c6c9
commit
78368db582
3 changed files with 84 additions and 5 deletions
|
|
@ -1717,6 +1717,9 @@ def setup_library_routes(app: web.Application, config: Config,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Direct-Play URL fuer Browser/PWA (MP4 mit Range-Requests)
|
||||||
|
video["direct_play_url"] = f"/tv/api/direct-stream/{video_id}"
|
||||||
|
|
||||||
return web.json_response(video)
|
return web.json_response(video)
|
||||||
|
|
||||||
# === Episoden-Thumbnails ===
|
# === Episoden-Thumbnails ===
|
||||||
|
|
|
||||||
|
|
@ -88,11 +88,16 @@ function initPlayer(opts) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Prioritaet 3: HLS-Streaming (Browser, kein nativer Player)
|
// Prioritaet 3: Browser/PWA - Direct-Play (MP4) bevorzugt, HLS als Fallback
|
||||||
else {
|
else {
|
||||||
const infoReady = loadVideoInfo();
|
showLoading();
|
||||||
startHLSStream(opts.startPos || 0);
|
const startPos = opts.startPos || 0;
|
||||||
infoReady.then(() => updatePlayerButtons());
|
loadVideoInfo().then(() => {
|
||||||
|
updatePlayerButtons();
|
||||||
|
_tryBrowserDirectPlay(startPos);
|
||||||
|
}).catch(() => {
|
||||||
|
startHLSStream(startPos);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
|
|
@ -621,6 +626,78 @@ function _nativeFallbackToHLS(startPosSec) {
|
||||||
infoReady.then(function() { updatePlayerButtons(); });
|
infoReady.then(function() { updatePlayerButtons(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === Browser Direct-Play (MP4 mit Range-Requests) ===
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Versucht direkte MP4-Wiedergabe im Browser (PWA).
|
||||||
|
* Faellt auf HLS zurueck wenn Codec nicht unterstuetzt oder Fehler.
|
||||||
|
*/
|
||||||
|
function _tryBrowserDirectPlay(seekSec) {
|
||||||
|
if (!videoInfo || !videoInfo.direct_play_url) {
|
||||||
|
console.info("[Player] Keine Direct-Play-URL, Fallback auf HLS");
|
||||||
|
startHLSStream(seekSec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var directUrl = videoInfo.direct_play_url;
|
||||||
|
console.info("[Player] Browser Direct-Play: " + directUrl);
|
||||||
|
|
||||||
|
// Pruefen ob der Browser den Codec abspielen kann
|
||||||
|
var codec = (videoInfo.video_codec || "").toLowerCase();
|
||||||
|
var canPlay = false;
|
||||||
|
if (codec === "h264" || codec === "avc1") {
|
||||||
|
canPlay = !!videoEl.canPlayType('video/mp4; codecs="avc1.640028"');
|
||||||
|
} else if (codec === "hevc" || codec === "h265" || codec === "hvc1") {
|
||||||
|
canPlay = !!videoEl.canPlayType('video/mp4; codecs="hvc1.1.6.L120"');
|
||||||
|
} else if (codec === "av1") {
|
||||||
|
canPlay = !!videoEl.canPlayType('video/mp4; codecs="av01.0.08M.08"');
|
||||||
|
} else {
|
||||||
|
// Unbekannter Codec - einfach versuchen
|
||||||
|
canPlay = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canPlay) {
|
||||||
|
console.info("[Player] Browser unterstuetzt Codec '" + codec + "' nicht, Fallback auf HLS");
|
||||||
|
startHLSStream(seekSec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct-Play starten
|
||||||
|
useDirectPlay = true;
|
||||||
|
videoEl.src = directUrl;
|
||||||
|
|
||||||
|
// Seek-Position setzen sobald Metadaten geladen
|
||||||
|
if (seekSec > 0) {
|
||||||
|
videoEl.addEventListener("loadedmetadata", function() {
|
||||||
|
videoEl.currentTime = seekSec;
|
||||||
|
}, { once: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fehler-Handler: Bei Fehler auf HLS wechseln
|
||||||
|
var directErrorHandler = function(e) {
|
||||||
|
console.warn("[Player] Direct-Play Fehler, wechsle zu HLS:", e);
|
||||||
|
videoEl.removeEventListener("error", directErrorHandler);
|
||||||
|
useDirectPlay = false;
|
||||||
|
videoEl.removeAttribute("src");
|
||||||
|
videoEl.load();
|
||||||
|
startHLSStream(seekSec);
|
||||||
|
};
|
||||||
|
videoEl.addEventListener("error", directErrorHandler, { once: true });
|
||||||
|
|
||||||
|
// Abspielen sobald bereit
|
||||||
|
videoEl.addEventListener("canplay", function() {
|
||||||
|
videoEl.removeEventListener("error", directErrorHandler);
|
||||||
|
}, { once: true });
|
||||||
|
|
||||||
|
videoEl.play().catch(function(e) {
|
||||||
|
console.warn("[Player] Autoplay blockiert (Direct-Play):", e);
|
||||||
|
hideLoading();
|
||||||
|
showControls();
|
||||||
|
if (playBtn) playBtn.innerHTML = "▶";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// === HLS Streaming ===
|
// === HLS Streaming ===
|
||||||
|
|
||||||
async function startHLSStream(seekSec) {
|
async function startHLSStream(seekSec) {
|
||||||
|
|
|
||||||
|
|
@ -385,4 +385,3 @@ document.addEventListener('focusin', function(e) {
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endblock %}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue