From f311c8e2f3b9f53b6d03a327cf1b5bfd69cc6424 Mon Sep 17 00:00:00 2001 From: MasutaYunikon Date: Mon, 8 Jun 2026 02:12:47 +0200 Subject: [PATCH] fix(organize): import manuel ne traite que les fichiers 100% complets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L'import manuel créait un fakeTorrent sans champ files, ce qui désactivait le filtre de complétion par fichier dans le worker. Sur Windows, tenter de déplacer un fichier encore écrit par qBittorrent provoque EBUSY ; les fichiers échouaient mais étaient quand même marqués importés en mémoire. Fix : - routes/organize.ts : appel dispatchGetFiles(hash) avant l'import pour récupérer la progression réelle par fichier depuis le client torrent - organize.ts : organizeTorrent accepte un param optionnel files[] transmis au worker via fakeTorrent ; sans fichiers (client injoignable), le comportement précédent (pas de filtre) est conservé en fallback --- server/organize.ts | 8 ++++++-- server/routes/organize.ts | 9 ++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/server/organize.ts b/server/organize.ts index 6506d71..7c84b7f 100644 --- a/server/organize.ts +++ b/server/organize.ts @@ -520,13 +520,17 @@ export async function organizeTorrent( hash : string, name : string, savePath : string, - seriesData: any[] + seriesData: any[], + files? : { name?: string; progress: number; priority?: number }[], ): Promise { logger.info('organize', `Import manuel lancé pour "${name}" (${hash})`) return new Promise((resolve, reject) => { const worker = new Worker(resolveWorkerPath()) - const fakeTorrent = { hash, name, save_path: savePath, state: 'seeding' } + // files : progression par fichier récupérée depuis le client torrent. + // Permet au worker de ne traiter que les fichiers à 100% et d'éviter + // les EBUSY sur Windows quand qBit est encore en train d'écrire les autres. + const fakeTorrent = { hash, name, save_path: savePath, state: 'seeding', files: files ?? [] } const result: OrganizeResult = { total: 0, skipped: 0, done: 0, errors: [] } worker.on('message', (msg: any) => { diff --git a/server/routes/organize.ts b/server/routes/organize.ts index 6c04943..3d3b46f 100644 --- a/server/routes/organize.ts +++ b/server/routes/organize.ts @@ -4,6 +4,7 @@ import { logger } from '../logger.js' import { organizeTorrent, migrateOrganizedEpisodeIds } from '../organize.js' import { loadEnrichedSeriesData } from '../lib/github-cache.js' import { recentOrganized, pushNotif } from '../lib/notifs.js' +import { dispatchGetFiles } from '../torrent-clients/index.js' import { DATA_DIR } from '../config.js' import path from 'path' @@ -36,7 +37,13 @@ router.post('/organize', requireAuth, async (req, res) => { if (!hash || !name || !save_path) { res.status(400).json({ error: 'hash, name et save_path requis' }); return } try { const seriesData = await loadEnrichedSeriesData() - const result = await organizeTorrent(hash, name, save_path, seriesData) + + // Récupère la progression par fichier depuis le client torrent. + // Permet au worker de sauter les fichiers encore en téléchargement (EBUSY sur Windows). + // En cas d'échec (client injoignable, hash non trouvé), on continue sans filtre. + const files = await dispatchGetFiles(hash).catch(() => []) + + const result = await organizeTorrent(hash, name, save_path, seriesData, files) if (result.done > 0 || result.errors.length > 0) { pushNotif({ hash, name, done: result.done, skipped: result.skipped, errors: result.errors.length, errorFiles: result.errors, at: new Date().toISOString() }) }