Nouvelle version réécrite de zéro : recherche multi-sources (Vostfree, French-Manga), extraction 2 niveaux, proxy vidéo intégré, streaming/téléchargement HLS, métadonnées Kitsu, bibliothèque locale, comptes JWT + administration, découverte fusionnée, indexeur Torznab (Sonarr/Prowlarr).
63 lines
2.1 KiB
HTML
63 lines
2.1 KiB
HTML
{% extends "base.html" %}
|
|
{% set active = 'library' %}
|
|
{% block title %}Lecture — Ohm Stream{% endblock %}
|
|
|
|
{% block content %}
|
|
<div x-data="watchPage({{ download_id }})" x-init="load()">
|
|
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.2rem">
|
|
<a href="/library" class="btn btn-ghost btn-sm">← Bibliothèque</a>
|
|
<h1 class="page-title" style="margin:0" x-text="file ? file.title : '…'"></h1>
|
|
<div style="flex:1"></div>
|
|
<a class="btn btn-ghost btn-sm" x-show="neighbors.previous" :href="'/watch/' + neighbors.previous">⏮ Précédent</a>
|
|
<a class="btn btn-sm" x-show="neighbors.next" :href="'/watch/' + neighbors.next">Suivant ⏭</a>
|
|
</div>
|
|
|
|
<div class="player-wrap">
|
|
<video x-ref="video" :src="`/api/stream/${id}`" controls
|
|
@timeupdate.throttle.5s="saveProgress"
|
|
@loadedmetadata="restorePosition">
|
|
</video>
|
|
</div>
|
|
<p class="page-sub" x-show="position > 0">⏵ Reprise automatique à ta position précédente.</p>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
function watchPage(id) {
|
|
return {
|
|
id, file: null, neighbors: {}, position: 0,
|
|
|
|
async load() {
|
|
const [fileRes, neighRes] = await Promise.all([
|
|
fetch('/api/downloads/' + id),
|
|
fetch(`/api/library/${id}/neighbors`),
|
|
]);
|
|
this.file = await fileRes.json();
|
|
this.neighbors = await neighRes.json();
|
|
document.title = (this.file.title || 'Lecture') + ' — Ohm Stream';
|
|
// Position enregistrée côté serveur via /api/library
|
|
const lib = await fetch('/api/library').then(r => r.json());
|
|
const entry = lib.find(f => f.id === id);
|
|
this.position = entry?.position_seconds || 0;
|
|
},
|
|
|
|
restorePosition() {
|
|
if (this.position > 5 && this.$refs.video.duration - this.position > 10) {
|
|
this.$refs.video.currentTime = this.position;
|
|
}
|
|
},
|
|
|
|
saveProgress() {
|
|
const t = this.$refs.video.currentTime;
|
|
if (!t) return;
|
|
fetch(`/api/stream/${id}/progress`, {
|
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ position_seconds: t }),
|
|
});
|
|
},
|
|
};
|
|
}
|
|
</script>
|
|
{% endblock %}
|