Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b84229510 | ||
|
|
23c46a621e | ||
|
|
4dc7255bb0 | ||
|
|
180513c98a |
No files matched your search
@@ -1,5 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.12.0](https://github.com/Masutayunikon/FanKarr/compare/v1.11.10...v1.12.0) (2026-03-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* now rename episodes with original_filename from api ([9bdb21a](https://github.com/Masutayunikon/FanKarr/commit/9bdb21a673ebb9871548aea6691bafbd049554ce))
|
||||||
|
|
||||||
## [1.11.10](https://github.com/Masutayunikon/FanKarr/compare/v1.11.9...v1.11.10) (2026-03-21)
|
## [1.11.10](https://github.com/Masutayunikon/FanKarr/compare/v1.11.9...v1.11.10) (2026-03-21)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+32
-20
@@ -15,10 +15,16 @@ import fs from 'fs'
|
|||||||
import fsp from 'fs/promises'
|
import fsp from 'fs/promises'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { parentPort } from 'worker_threads'
|
import { parentPort } from 'worker_threads'
|
||||||
import { DATA_DIR } from './config.js'
|
|
||||||
|
|
||||||
const TORRENTS_PATH = path.join(DATA_DIR, 'torrent_final.json')
|
// Base directory : binaire Bun ou cwd (Docker/dev)
|
||||||
const ORGANIZED_PATH = path.join(DATA_DIR, 'organized.json')
|
const _isBunBinary = typeof (globalThis as any).Bun !== 'undefined'
|
||||||
|
&& path.dirname((process as any).execPath) !== process.cwd()
|
||||||
|
const BASE_DIR = _isBunBinary
|
||||||
|
? path.dirname((process as any).execPath)
|
||||||
|
: process.cwd()
|
||||||
|
|
||||||
|
const TORRENTS_PATH = path.join(BASE_DIR, 'data', 'torrent_final.json')
|
||||||
|
const ORGANIZED_PATH = path.join(BASE_DIR, 'data', 'organized.json')
|
||||||
|
|
||||||
// ─── Utils log ────────────────────────────────────────────────
|
// ─── Utils log ────────────────────────────────────────────────
|
||||||
// Le worker tourne dans un thread séparé — il passe les logs au thread principal
|
// Le worker tourne dans un thread séparé — il passe les logs au thread principal
|
||||||
@@ -33,7 +39,7 @@ function debug(msg: string) { parentPort?.postMessage({ type: 'log', level: 'deb
|
|||||||
|
|
||||||
function readSettings(): { mediaPath: string; completePath: string; organizeMode: string; nfoSupport: boolean } {
|
function readSettings(): { mediaPath: string; completePath: string; organizeMode: string; nfoSupport: boolean } {
|
||||||
try {
|
try {
|
||||||
const p = path.join(DATA_DIR, 'settings.json')
|
const p = path.join(process.cwd(), 'data', 'settings.json')
|
||||||
if (!fs.existsSync(p)) return { mediaPath: '', completePath: '', organizeMode: 'hardlink', nfoSupport: false }
|
if (!fs.existsSync(p)) return { mediaPath: '', completePath: '', organizeMode: 'hardlink', nfoSupport: false }
|
||||||
return JSON.parse(fs.readFileSync(p, 'utf-8'))
|
return JSON.parse(fs.readFileSync(p, 'utf-8'))
|
||||||
} catch { return { mediaPath: '', completePath: '', organizeMode: 'hardlink', nfoSupport: false } }
|
} catch { return { mediaPath: '', completePath: '', organizeMode: 'hardlink', nfoSupport: false } }
|
||||||
@@ -283,29 +289,35 @@ async function organizeTorrent(hash: string, name: string, savePath: string) {
|
|||||||
return { ...result, total: 1, done: 1 }
|
return { ...result, total: 1, done: 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Map filename → original_filename (depuis l'API) ────────
|
||||||
|
const filenameToOriginal = new Map<string, string>()
|
||||||
|
for (const ep of torrent.resolved_episodes ?? []) {
|
||||||
|
if (ep.filename && ep.original_filename && ep.filename !== ep.original_filename) {
|
||||||
|
filenameToOriginal.set(ep.filename, ep.original_filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── Map filename → season ─────────────────────────────────
|
// ── Map filename → season ─────────────────────────────────
|
||||||
// Priorité : season_number dans torrent_files (packs multi-saisons)
|
// Priorité : season_number dans torrent_files (packs multi-saisons)
|
||||||
// Fallback : resolved_episodes matchés par episode_number (torrents individuels)
|
// Fallback : resolved_episodes matchés par episode_number (torrents individuels)
|
||||||
const filenameSeasonMap = new Map<string, number>()
|
const filenameSeasonMap = new Map<string, number>()
|
||||||
|
|
||||||
// Index resolved_episodes par episode_number pour lookup rapide
|
// Index resolved_episodes par episode_number pour lookup rapide
|
||||||
const filenameToSeason = new Map<string, number>()
|
const epByNum = new Map<number, number>() // ep_number → season_number
|
||||||
for (const ep of torrent.resolved_episodes ?? []) {
|
for (const ep of torrent.resolved_episodes ?? []) {
|
||||||
if (ep.filename && ep.season_number !== undefined)
|
if (ep.episode_number !== undefined && ep.season_number !== undefined)
|
||||||
filenameToSeason.set(ep.filename, ep.season_number)
|
epByNum.set(Number(ep.episode_number), ep.season_number)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const tf of torrentFiles) {
|
for (const tf of torrentFiles) {
|
||||||
const sn = tf.season_number != null ? Number(tf.season_number) : null
|
const sn: number | null = tf.season_number != null ? Number(tf.season_number) : null
|
||||||
|
const tfNum = tf.num !== undefined ? Number(tf.num) : undefined
|
||||||
if (sn !== null) {
|
if (sn !== null) {
|
||||||
filenameSeasonMap.set(tf.filename, sn)
|
filenameSeasonMap.set(tf.filename, sn)
|
||||||
} else {
|
} else if (tfNum !== undefined && epByNum.has(tfNum)) {
|
||||||
const fromResolved = filenameToSeason.get(tf.filename)
|
filenameSeasonMap.set(tf.filename, epByNum.get(tfNum)!)
|
||||||
if (fromResolved !== undefined) {
|
} else if (torrent.season_number !== undefined) {
|
||||||
filenameSeasonMap.set(tf.filename, fromResolved)
|
filenameSeasonMap.set(tf.filename, torrent.season_number)
|
||||||
} else if (torrent.season_number !== undefined) {
|
|
||||||
filenameSeasonMap.set(tf.filename, torrent.season_number)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,8 +328,7 @@ async function organizeTorrent(hash: string, name: string, savePath: string) {
|
|||||||
const filePath: string[] = tf.path
|
const filePath: string[] = tf.path
|
||||||
|
|
||||||
// Skip les fichiers dans des dossiers bonus/musique/images
|
// Skip les fichiers dans des dossiers bonus/musique/images
|
||||||
const tfMeta = torrentFiles.find((tf: any) => tf.filename === filename)
|
if (isInExcludedFolder(filePath)) {
|
||||||
if (isInExcludedFolder(filePath) && tfMeta?.season_number == null) {
|
|
||||||
log(`[organize] skip bonus: ${filename}`)
|
log(`[organize] skip bonus: ${filename}`)
|
||||||
result.skipped++
|
result.skipped++
|
||||||
continue
|
continue
|
||||||
@@ -347,9 +358,10 @@ async function organizeTorrent(hash: string, name: string, savePath: string) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const seasonNum = filenameSeasonMap.get(filename) ?? 1
|
const seasonNum = filenameSeasonMap.get(filename) ?? 1
|
||||||
const destDir = path.join(mediaPath, serieTitle, seasonFolder(seasonNum))
|
const destFilename = filenameToOriginal.get(filename) ?? filename
|
||||||
const dest = path.join(destDir, filename)
|
const destDir = path.join(mediaPath, serieTitle, seasonFolder(seasonNum))
|
||||||
|
const dest = path.join(destDir, destFilename)
|
||||||
|
|
||||||
if (fs.existsSync(dest)) {
|
if (fs.existsSync(dest)) {
|
||||||
markOrganized(hash, filename)
|
markOrganized(hash, filename)
|
||||||
|
|||||||
Reference in new issue
Block a user