feat: ajout d'une hashmap pour matcher les titres sur synologie et ajouter les hash de torrent manuellement
This commit is contained in:
1 parent
bb6d094383
commit
9b4dc4f782
2 files changed
+38
-8
No files matched your search
+10
-3
@@ -170,6 +170,11 @@ async function readAvailable(): Promise<number[]> {
|
||||
catch { return [] }
|
||||
}
|
||||
|
||||
async function readInfohashMap(): Promise<Record<string, string>> {
|
||||
try { return await githubGet('infohash_map.json') as Record<string, string> }
|
||||
catch { return {} }
|
||||
}
|
||||
|
||||
async function readSerieData(serieId: number): Promise<any | null> {
|
||||
try { return await githubGet(`series/${serieId}.json`) }
|
||||
catch { return null }
|
||||
@@ -277,7 +282,7 @@ app.get('/api/series', requireAuth, async (_req, res) => {
|
||||
let organized: Record<string, Record<string, any>> = {}
|
||||
try { const p = path.join(DATA_DIR, 'organized.json'); if (fs.existsSync(p)) organized = JSON.parse(fs.readFileSync(p, 'utf-8')) } catch {}
|
||||
const activeTorrents = new Set<string>()
|
||||
try { const { category } = readSettings(); const active = await dispatchList(category ?? 'fankai'); for (const t of active) { if (t.hash && t.state === 'downloading') activeTorrents.add(t.hash.toLowerCase()) } } catch {}
|
||||
try { const { category } = readSettings(); const infohashMap = await readInfohashMap(); const active = await dispatchList(category ?? 'fankai', infohashMap); for (const t of active) { if (t.hash && t.state === 'downloading') activeTorrents.add(t.hash.toLowerCase()) } } catch {}
|
||||
const seriesRaw = (Array.isArray(apiData) ? apiData : (apiData.series ?? [])).map(normalizeSerie)
|
||||
const serieDataMap = new Map<number, any>()
|
||||
await Promise.all(seriesRaw.filter((s: any) => availableSet.has(s.id)).map(async (s: any) => { const sd = await readSerieData(s.id); if (sd) serieDataMap.set(s.id, sd) }))
|
||||
@@ -392,7 +397,8 @@ app.post('/api/download', requireAuth, async (req, res) => {
|
||||
app.get('/api/downloads', requireAuth, async (_req, res) => {
|
||||
try {
|
||||
const { category } = readSettings()
|
||||
const torrents = await dispatchList(category ?? 'fankai')
|
||||
const infohashMap = await readInfohashMap()
|
||||
const torrents = await dispatchList(category ?? 'fankai', infohashMap)
|
||||
let organized: Record<string, Record<string, any>> = {}
|
||||
try { const p = path.join(DATA_DIR, 'organized.json'); if (fs.existsSync(p)) organized = JSON.parse(fs.readFileSync(p, 'utf-8')) } catch {}
|
||||
const enriched = await Promise.all(torrents.map(async (t: any) => {
|
||||
@@ -828,9 +834,10 @@ server.listen(PORT, async () => {
|
||||
const autoOrganize = async () => {
|
||||
try {
|
||||
const { category } = readSettings()
|
||||
const infohashMap = await readInfohashMap()
|
||||
const seriesData = await loadEnrichedSeriesData()
|
||||
await autoOrganizeAll(
|
||||
() => dispatchList(category ?? 'fankai'),
|
||||
() => dispatchList(category ?? 'fankai', infohashMap),
|
||||
seriesData,
|
||||
(result) => {
|
||||
if (result.done > 0 || result.errors > 0) {
|
||||
|
||||
@@ -237,15 +237,27 @@ export async function dispatchDownload(url: string): Promise<{ uuid: string; nam
|
||||
|
||||
// ─── Dispatch list ─────────────────────────────────────────────────────────────
|
||||
|
||||
export async function dispatchList(category?: string): Promise<(TorrentInfo & { client_uuid: string; client_name: string })[]> {
|
||||
const clients = loadClients()
|
||||
// Map inversée : titre normalisé → infohash (pour matcher les torrents Synology)
|
||||
function buildTitleIndex(infohashMap: Record<string, string>): Map<string, string> {
|
||||
const index = new Map<string, string>()
|
||||
for (const [hash, title] of Object.entries(infohashMap)) {
|
||||
index.set(title.toLowerCase().trim(), hash.toLowerCase())
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
export async function dispatchList(
|
||||
category? : string,
|
||||
infohashMap? : Record<string, string>,
|
||||
): Promise<(TorrentInfo & { client_uuid: string; client_name: string })[]> {
|
||||
const clients = loadClients()
|
||||
const results: (TorrentInfo & { client_uuid: string; client_name: string })[] = []
|
||||
const titleIndex = infohashMap ? buildTitleIndex(infohashMap) : null
|
||||
|
||||
for (const client of clients) {
|
||||
const driver = getDriver(client.type)
|
||||
if (!driver) continue
|
||||
|
||||
// Skip si le client est en cooldown suite à des échecs d'auth
|
||||
if (isInCooldown(client.uuid)) {
|
||||
const remaining = cooldownRemaining(client.uuid)
|
||||
logger.debug('torrent-clients', `Client "${client.name}" en cooldown — retry dans ${remaining}`)
|
||||
@@ -266,12 +278,23 @@ export async function dispatchList(category?: string): Promise<(TorrentInfo & {
|
||||
const save_path = hasRemap
|
||||
? remapSavePath(t.save_path, remotePath, localPath)
|
||||
: t.save_path
|
||||
results.push({ ...t, save_path, client_uuid: client.uuid, client_name: client.name })
|
||||
|
||||
// Pour Synology (hash = dbid_xxx), on essaie de résoudre le vrai infohash
|
||||
// en matchant le titre du torrent dans la infohashMap
|
||||
let hash = t.hash
|
||||
if (titleIndex && t.hash.startsWith('dbid_')) {
|
||||
const resolved = titleIndex.get(t.name.toLowerCase().trim())
|
||||
if (resolved) {
|
||||
logger.debug('torrent-clients', `Synology hash résolu : "${t.name}" → ${resolved.slice(0, 8)}…`)
|
||||
hash = resolved
|
||||
}
|
||||
}
|
||||
|
||||
results.push({ ...t, hash, save_path, client_uuid: client.uuid, client_name: client.name })
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : 'Erreur inconnue'
|
||||
logger.error('torrent-clients', `Impossible de récupérer la liste depuis "${client.name}" : ${msg}`)
|
||||
// Déclencher le backoff si c'est une erreur d'auth
|
||||
const isAuthError = msg.toLowerCase().includes('login') ||
|
||||
msg.toLowerCase().includes('auth') ||
|
||||
msg.toLowerCase().includes('ban') ||
|
||||
|
||||
Reference in new issue
Block a user