diff --git a/server/index.ts b/server/index.ts index d9b6bc3..1475511 100644 --- a/server/index.ts +++ b/server/index.ts @@ -647,18 +647,29 @@ app.post('/api/manual-import', requireAuth, async (req, res) => { try { if (!fs.existsSync(file_path)) throw new Error('Fichier source introuvable') fs.mkdirSync(destDir, { recursive: true }) - if (!fs.existsSync(destPath)) { - if (organizeMode === 'hardlink') { - try { fs.linkSync(file_path, destPath) } - catch { await fs.promises.copyFile(file_path, destPath) } - } else if (organizeMode === 'move') { - await fs.promises.copyFile(file_path, destPath) - await fs.promises.unlink(file_path) - } else { - // copy - await fs.promises.copyFile(file_path, destPath) + + if (file_path !== destPath) { + // Si le fichier est déjà dans mediaPath/[série]/ → rename sur place + const serieRootPath = path.join(mediaPath, serieTitle) + const isInSeriePath = file_path.startsWith(serieRootPath + path.sep) || file_path.startsWith(serieRootPath + '/') + + if (isInSeriePath && !fs.existsSync(destPath)) { + fs.renameSync(file_path, destPath) + logger.info('api', `Import manuel (rename) : "${srcFilename}" → "${destFilename}"`) + } else if (!isInSeriePath && !fs.existsSync(destPath)) { + if (organizeMode === 'hardlink') { + try { fs.linkSync(file_path, destPath) } + catch { await fs.promises.copyFile(file_path, destPath) } + } else if (organizeMode === 'move') { + await fs.promises.copyFile(file_path, destPath) + await fs.promises.unlink(file_path) + } else { + await fs.promises.copyFile(file_path, destPath) + } + logger.info('api', `Import manuel : "${srcFilename}" → "${destPath}"`) } } + const torrentHash = String(hash || '').toLowerCase() || 'manual' if (!organized[torrentHash]) organized[torrentHash] = {} organized[torrentHash][String(episode_id)] = { @@ -667,7 +678,6 @@ app.post('/api/manual-import', requireAuth, async (req, res) => { src_filename: srcFilename, dest_filename: destFilename, dest_path: destPath, } done.push(episode_id) - logger.info('api', `Import manuel : "${srcFilename}" → "${destPath}"`) } catch (err) { const msg = err instanceof Error ? err.message : 'Erreur inconnue' errors.push({ file: srcFilename, error: msg }) diff --git a/src/components/ManualImportModal.vue b/src/components/ManualImportModal.vue index 822fee1..1aab39f 100644 --- a/src/components/ManualImportModal.vue +++ b/src/components/ManualImportModal.vue @@ -7,14 +7,17 @@

Import manuel — {{ serieName }}

-

Associez vos fichiers existants aux épisodes du catalogue

+

+ {{ step === 'folder' ? 'Sélectionnez le dossier contenant vos fichiers vidéo' : + step === 'match' ? 'Associez vos fichiers aux épisodes du catalogue' : + 'Import terminé' }} +

-

Sélectionnez le dossier contenant vos fichiers vidéo :

@@ -49,28 +53,35 @@ v-for="(item, i) in items" :key="item.file.path" class="flex items-center gap-3 p-3 rounded-lg border transition-colors" - :class="item.episode_id - ? 'border-green-500/20 bg-green-500/5' - : 'border-border bg-shell'" + :class="item.alreadyImported + ? 'border-blue-500/20 bg-blue-500/5' + : item.episode_id + ? 'border-green-500/20 bg-green-500/5' + : 'border-border bg-shell'" > -
- +
+ +

{{ item.file.name }}

-

{{ formatSize(item.file.size) }}

+

+ {{ formatSize(item.file.size) }} + — déjà importé +