fix(supression): supprime maintenant le dossier de la serie et l'ajoute a organized.json

This commit is contained in:
MasutaYunikon committed 2026-05-23 19:40:04 +02:00
1 parent 858a5b34bf
commit 161f4f5051
4 files changed
+43 -5

No files matched your search

+22
View File
@@ -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<string, Record<string, any>> = 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)
+6 -5
View File
@@ -28,6 +28,7 @@ export interface OrgEntry {
src_filename : string
dest_filename: string
dest_path : string
dest_dir : string
}
// organized.json : Record<hash, Record<episode_id_string, OrgEntry>>
@@ -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)
}
+1
View File
@@ -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<string, Record<string, OrgEntry>>
+14
View File
@@ -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')