From 161f4f5051a327421cede35b1d714286588e4f5b Mon Sep 17 00:00:00 2001 From: MasutaYunikon Date: Sat, 23 May 2026 19:40:04 +0200 Subject: [PATCH] fix(supression): supprime maintenant le dossier de la serie et l'ajoute a organized.json --- server/index.ts | 22 ++++++++++++++++++++++ server/organize-worker.ts | 11 ++++++----- server/organize.ts | 1 + server/routes/import.ts | 14 ++++++++++++++ 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/server/index.ts b/server/index.ts index c7deb81..d9b068e 100644 --- a/server/index.ts +++ b/server/index.ts @@ -152,6 +152,28 @@ server.listen(PORT, async () => { } } catch {} + // Migration organized.json : backfill dest_dir manquant sur les anciennes entrées + try { + if (fs.existsSync(ORGANIZED_PATH)) { + const raw: Record> = JSON.parse(fs.readFileSync(ORGANIZED_PATH, 'utf-8')) + let patched = 0 + for (const episodes of Object.values(raw)) { + for (const entry of Object.values(episodes)) { + if (!entry.dest_dir && entry.dest_path) { + entry.dest_dir = path.dirname(entry.dest_path) + patched++ + } + } + } + if (patched > 0) { + fs.writeFileSync(ORGANIZED_PATH, JSON.stringify(raw, null, 2)) + logger.info('api', `Migration organized.json : ${patched} entrée(s) backfillées avec dest_dir`) + } + } + } catch (err) { + logger.warn('api', `Migration dest_dir échouée : ${err instanceof Error ? err.message : err}`) + } + loadEnrichedSeriesData() .then(async seriesData => { await migrateOrganizedEpisodeIds(ORGANIZED_PATH, seriesData) diff --git a/server/organize-worker.ts b/server/organize-worker.ts index 8ed738a..680eb9d 100644 --- a/server/organize-worker.ts +++ b/server/organize-worker.ts @@ -28,6 +28,7 @@ export interface OrgEntry { src_filename : string dest_filename: string dest_path : string + dest_dir : string } // organized.json : Record> @@ -386,7 +387,7 @@ async function organizeTorrent( markOrganized(hash, ep.id, { at: new Date().toISOString(), season: season.season_number ?? 1, episode: ep.episode_number, episode_id: ep.id, - src_filename: filename, dest_filename: destName, dest_path: dest, + src_filename: filename, dest_filename: destName, dest_path: dest, dest_dir: destDir, }) await unlinkWithRetry(src) log(`${destName} → Saison ${season.season_number}`) @@ -397,7 +398,7 @@ async function organizeTorrent( markOrganized(hash, ep.id, { at: new Date().toISOString(), season: season.season_number ?? 1, episode: ep.episode_number, episode_id: ep.id, - src_filename: filename, dest_filename: destName, dest_path: dest, + src_filename: filename, dest_filename: destName, dest_path: dest, dest_dir: destDir, }) log(`${destName} → Saison ${season.season_number}`) return { ...result, total: 1, done: 1 } @@ -448,7 +449,7 @@ async function organizeTorrent( markOrganized(hash, episode_id, { at: new Date().toISOString(), season: season_number, episode: episode_number, episode_id, - src_filename: filename, dest_filename: nfo_filename, dest_path: dest, + src_filename: filename, dest_filename: nfo_filename, dest_path: dest, dest_dir: destDir, }) result.skipped++ continue @@ -463,14 +464,14 @@ async function organizeTorrent( markOrganized(hash, episode_id, { at: new Date().toISOString(), season: season_number, episode: episode_number, episode_id, - src_filename: filename, dest_filename: nfo_filename, dest_path: dest, + src_filename: filename, dest_filename: nfo_filename, dest_path: dest, dest_dir: destDir, }) } else { await fsp.copyFile(src, dest) markOrganized(hash, episode_id, { at: new Date().toISOString(), season: season_number, episode: episode_number, episode_id, - src_filename: filename, dest_filename: nfo_filename, dest_path: dest, + src_filename: filename, dest_filename: nfo_filename, dest_path: dest, dest_dir: destDir, }) await unlinkWithRetry(src) } diff --git a/server/organize.ts b/server/organize.ts index b2dea7c..6506d71 100644 --- a/server/organize.ts +++ b/server/organize.ts @@ -38,6 +38,7 @@ interface OrgEntry { src_filename : string dest_filename: string dest_path : string + dest_dir? : string // absent dans les anciennes entrées — backfillé au démarrage } type Organized = Record> diff --git a/server/routes/import.ts b/server/routes/import.ts index 5974d5e..2350337 100644 --- a/server/routes/import.ts +++ b/server/routes/import.ts @@ -262,10 +262,15 @@ router.delete('/organized/:serieId', requireAuth, async (req, res) => { let removed = 0 const errors: string[] = [] const emptyHashes: string[] = [] + let serieFolder: string | null = null for (const [hash, episodes] of Object.entries(organized)) { for (const epId of Object.keys(episodes)) { if (!episodeIds.has(epId)) continue const entry = episodes[epId] + if (!serieFolder && entry) { + const dir = entry.dest_dir ?? path.dirname(entry.dest_path) + serieFolder = path.dirname(dir) + } if (deleteFile && entry?.dest_path && fs.existsSync(entry.dest_path)) { try { fs.unlinkSync(entry.dest_path) } catch { errors.push(entry.dest_path) } } @@ -280,6 +285,15 @@ router.delete('/organized/:serieId', requireAuth, async (req, res) => { if (hash === 'manual') continue dispatchRemove(hash, false).catch(err => logger.warn('api', `Impossible de retirer le torrent ${hash.slice(0, 8)}… du client : ${err instanceof Error ? err.message : err}`)) } + // Supprimer le dossier de la série s'il existe encore + if (serieFolder && fs.existsSync(serieFolder)) { + try { + fs.rmSync(serieFolder, { recursive: true, force: true }) + logger.info('api', `Dossier série supprimé : ${serieFolder}`) + } catch (err) { + logger.warn('api', `Impossible de supprimer le dossier série "${serieFolder}" : ${err instanceof Error ? err.message : err}`) + } + } } // Supprimer les demandes "disponible" liées à cette série const completedRequests = readRequests().filter(r => r.serieId === Number(serieId) && r.status === 'completed')