From 1b2036b57b4cf17107d49dff2df47bc8919ba39c Mon Sep 17 00:00:00 2001 From: MasutaYunikon Date: Tue, 21 Apr 2026 10:27:48 +0200 Subject: [PATCH] fix: ajout des boutons pour les episodes sans torrent --- server/routes/series.ts | 20 +++++++++ src/views/settings/DownloadClientView.vue | 52 +++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/server/routes/series.ts b/server/routes/series.ts index 07d69fc..36fcc0c 100644 --- a/server/routes/series.ts +++ b/server/routes/series.ts @@ -65,6 +65,14 @@ router.get('/series/:id', requireAuth, async (req, res) => { } } if (serieData) { + // Lookup rapide hash → torrent pack (intégrale ou saison) + const torrentByHash = new Map() + for (const t of (serieData.torrents ?? [])) + if (t.infohash) torrentByHash.set(t.infohash.toLowerCase(), { torrent_url: t.torrent_url, magnet: t.magnet, type: 'pack_integrale', raw: t.title ?? '', fankai: t.fankai ?? true }) + for (const sd_s of (serieData.seasons ?? [])) + for (const t of (sd_s.torrents ?? [])) + if (t.infohash) torrentByHash.set(t.infohash.toLowerCase(), { torrent_url: t.torrent_url, magnet: t.magnet, type: 'pack_saison', raw: t.title ?? '', fankai: t.fankai ?? true }) + for (const t of (serieData.torrents ?? [])) { integraleTorrents.push({ ...t, raw: t.title }) const resolved = buildResolvedEpisodes(serieData, t.infohash) @@ -101,6 +109,18 @@ router.get('/series/:id', requireAuth, async (req, res) => { organizedEpisodeIds.add(ep.id) } } + // Fallback : si l'épisode n'a pas de torrent individuel, + // on crée un torrent synthétique depuis ep.paths (fichier dans un pack) + if (!episodeTorrentMap[ep.id]) { + for (const pathEntry of (ep.paths ?? [])) { + if (typeof pathEntry !== 'object' || !pathEntry.infohash) continue + const pack = torrentByHash.get(pathEntry.infohash.toLowerCase()) + if (!pack) continue + episodeTorrentMap[ep.id] = { torrent_url: pack.torrent_url, magnet: pack.magnet, type: pack.type, raw: pack.raw, manual: false, fankai: pack.fankai, file_index: pathEntry.file_index ?? null, file_path: pathEntry.path ?? null } + availableEpisodeIds.add(ep.id) + break + } + } } } } diff --git a/src/views/settings/DownloadClientView.vue b/src/views/settings/DownloadClientView.vue index f67c537..a1f5650 100644 --- a/src/views/settings/DownloadClientView.vue +++ b/src/views/settings/DownloadClientView.vue @@ -40,6 +40,50 @@ + +
+

Comparatif des clients

+

Fonctionnalités supportées par chaque client.

+
+ + + + + + + + + + + + + + + + + + + +
ClientSélection fichierCatégoriesDossier cibleRemap. chemin
+
+ + {{ row.label }} +
+
+ + {{ row.fileSelect }} + + {{ row.categories ? '✓' : '✗' }}✓✓
+
+

+ ✓ Natif — appliqué à l'ajout · + Async — appliqué après récupération des métadonnées · + ✗ — non supporté, torrent complet téléchargé +

+
+
([]) const availableClients = ref([]) const healthStatus = ref>({}) +const clientMatrix = [ + { id: 'qbittorrent', label: 'qBittorrent', fileSelect: 'Async', categories: true }, + { id: 'transmission', label: 'Transmission', fileSelect: '✓ Natif', categories: true }, + { id: 'rtorrent', label: 'rTorrent / ruTorrent', fileSelect: 'Async', categories: true }, + { id: 'utorrent', label: 'uTorrent', fileSelect: '✗', categories: true }, + { id: 'synology-ds', label: 'Synology Download Station', fileSelect: '✗', categories: false }, +] + const modal = ref({ open : false, uuid : null as string | null,