diff --git a/server/index.ts b/server/index.ts
index 7a0c3c9..eb05336 100644
--- a/server/index.ts
+++ b/server/index.ts
@@ -511,7 +511,7 @@ app.get('/api/series/:id', requireAuth, async (req, res) => {
// ── Torrents niveau épisode ─────────────────────────────
for (const ep of season.episodes ?? []) {
for (const t of (ep.torrents ?? [])) {
- const ref = { torrent_url: t.torrent_url, magnet: t.magnet, type: 'episode', raw: t.title, manual: t.manual ?? false }
+ const ref = { torrent_url: t.torrent_url, magnet: t.magnet, type: 'episode', raw: t.title, manual: t.manual ?? false, fankai: t.fankai ?? true }
episodeTorrentMap[ep.id] = ref
availableEpisodeIds.add(ep.id)
@@ -536,13 +536,38 @@ app.get('/api/series/:id', requireAuth, async (req, res) => {
// ── Enrichissement des saisons API ───────────────────────────────
const enrichedSeasons = seasonsWithEpisodes.map((season: any) => {
const eps = season.episodes.map((ep: any) => {
- // Chercher le torrent : niveau épisode d'abord, sinon le torrent de saison/intégrale sert juste de disponibilité
const epTorrent = episodeTorrentMap[ep.id] ?? null
- // original_filename vient de l'API Fankai directement
+
+ // Si pas de torrent épisode, chercher le fankai du torrent qui couvre cet épisode via paths
+ let fankai: boolean | null = epTorrent ? (epTorrent.fankai ?? true) : null
+ if (fankai === null && serieData) {
+ // Chercher dans les torrents série/saison quel torrent a un path pour cet épisode
+ outer: for (const sd_season of serieData.seasons ?? []) {
+ for (const sdEp of sd_season.episodes ?? []) {
+ if (sdEp.id !== ep.id) continue
+ for (const p of sdEp.paths ?? []) {
+ const ih = typeof p === 'object' ? p.infohash?.toLowerCase() : null
+ if (!ih) continue
+ // Chercher dans les torrents série
+ for (const t of serieData.torrents ?? []) {
+ if (t.infohash?.toLowerCase() === ih) { fankai = t.fankai ?? true; break outer }
+ }
+ // Chercher dans les torrents saison
+ for (const s of serieData.seasons ?? []) {
+ for (const t of s.torrents ?? []) {
+ if (t.infohash?.toLowerCase() === ih) { fankai = t.fankai ?? true; break outer }
+ }
+ }
+ }
+ }
+ }
+ }
+
return {
...ep,
available : availableEpisodeIds.has(ep.id),
- torrent : epTorrent,
+ torrent : epTorrent ? { ...epTorrent, fankai: fankai ?? true } : null,
+ fankai : fankai,
organized : organizedEpisodeIds.has(ep.id),
}
})
diff --git a/src/views/SerieView.vue b/src/views/SerieView.vue
index 90a257f..11a726f 100644
--- a/src/views/SerieView.vue
+++ b/src/views/SerieView.vue
@@ -60,7 +60,7 @@
{{ data.serie.plot }}
-
+
-
+
@@ -188,7 +188,6 @@
:key="ep.id"
class="px-5 py-3 hover:bg-white/[0.02] transition"
>
-
@@ -208,29 +207,29 @@
{{ formatDate(ep.aired) }}
- {{ ep.duration }} min
+ {{ formatDuration(ep.duration) }}
-
+
-
+
Hors Fankai
-
+
- ✓ organisé
+ ✓ importé
-
+
✓ téléchargé
@@ -263,7 +262,7 @@
-
+
@@ -308,7 +307,6 @@ import { useRoute } from 'vue-router'
import { useSeriesStore } from '@/stores/series'
import type { Season } from '@/stores/series'
-// ── Composant icône download ──────────────────────────────────
const DownloadIcon = defineComponent({
props: { spinning: Boolean, size: { type: Number, default: 14 } },
setup(props) {
@@ -320,7 +318,6 @@ const DownloadIcon = defineComponent({
}
})
-// ── Setup ─────────────────────────────────────────────────────
const route = useRoute()
const store = useSeriesStore()
@@ -329,7 +326,6 @@ const downloading = ref
>(new Set())
const downloaded = ref>(new Set())
const toast = ref<{ type: 'success' | 'error'; message: string } | null>(null)
-// ── Progression downloads ──────────────────────────────────────
interface ActiveTorrent { hash: string; progress: number; state: string; name: string }
const activeTorrents = ref([])
let pollTimer: ReturnType | null = null
@@ -360,7 +356,6 @@ function extractHash(torrent: { magnet?: string | null; torrent_url?: string | n
return m ? m[1].toLowerCase() : null
}
-// ── Data ───────────────────────────────────────────────────────
const data = computed(() => store.currentSerie)
function seasonAvailableCount(season: Season) {
@@ -377,6 +372,15 @@ function formatDate(d: string) {
return new Date(d).toLocaleDateString('fr-FR', { year: 'numeric', month: 'short', day: 'numeric' })
}
+// Durée en secondes → "1h 23min" ou "45 min"
+function formatDuration(seconds: number): string {
+ if (!seconds || seconds <= 0) return ''
+ const h = Math.floor(seconds / 3600)
+ const m = Math.floor((seconds % 3600) / 60)
+ if (h > 0) return m > 0 ? `${h}h ${m}min` : `${h}h`
+ return `${m} min`
+}
+
function showToast(type: 'success' | 'error', message: string) {
toast.value = { type, message }
setTimeout(() => { toast.value = null }, 3500)