diff --git a/fileflows/scripts/Sonarr_-_Trigger_Manual_Import.js b/fileflows/scripts/Sonarr_-_Trigger_Manual_Import.js index 1adfe02..48dc729 100644 --- a/fileflows/scripts/Sonarr_-_Trigger_Manual_Import.js +++ b/fileflows/scripts/Sonarr_-_Trigger_Manual_Import.js @@ -2,7 +2,7 @@ * @name Sonarr - Trigger Manual Import * @description Safely trigger Sonarr ManualImport for exactly one processed episode file. * @author FileFlows + Sascha - * @revision 11 + * @revision 10 * @output Import erfolgreich * @output Fehler * @param {string} URL Sonarr root URL and port @@ -31,16 +31,13 @@ function Script(URL, ApiKey, ImportPath, UseUnmappedPath, MoveMode, TimeOut) { } // ── SKIP-GUARD: Nur API-Call machen, wenn der aktuelle ImportPath - // mit dem konfigurierten Pfad als vollständiges Pfadsegment - // übereinstimmt. Ein nacktes Prefix würde z. B. /serien4k - // fälschlich dem FHD-Root /serien zuordnen. - const normalizedCurrentPath = normalizeImportPath(exactImportPath); - const normalizedScopeRoot = normalizeImportPath(ImportPath); - const isInScope = normalizedCurrentPath === normalizedScopeRoot - || normalizedCurrentPath.startsWith(normalizedScopeRoot + '/'); - if (!isInScope) { - Logger.ILog(`Skip: current file '${currentFile}' not under ImportPath '${ImportPath}' - not responsible`); - return 1; + // mit dem konfigurierten Pfad uebereinstimmt. Sonst sofort OK. + // Das verhindert 3 unnoetige API-Calls pro Datei (4 Arr-Instanzen). + if (ImportPath && ImportPath.indexOf(URL) === -1) { + if (currentFile && ImportPath && currentFile.indexOf(ImportPath) === -1) { + Logger.ILog(`Skip: current file '${currentFile}' not under ImportPath '${ImportPath}' - not responsible`); + return 1; + } } const sonarr = new Sonarr(URL, ApiKey); @@ -61,18 +58,7 @@ function Script(URL, ApiKey, ImportPath, UseUnmappedPath, MoveMode, TimeOut) { ?? findEpisodeFromGrabHistory(pattern, sonarr); if (trackedEpisode) break; } - if (!trackedEpisode) { - // Ein Staffelpaket-Ordner ist absichtlich mehrdeutig. Zuerst - // den exakten Episoden-Dateinamen parsen, danach erst den - // Ordnernamen als letzten Fallback versuchen. - const parsePatterns = [filePattern, folderPattern] - .filter(Boolean) - .filter((value, index, values) => values.indexOf(value) === index); - for (const pattern of parsePatterns) { - trackedEpisode = parseSeries(pattern, sonarr); - if (trackedEpisode?.id && trackedEpisode?.episodeIds?.length) break; - } - } + if (!trackedEpisode) trackedEpisode = parseSeries(searchPatterns[0] || '', sonarr); seriesId = trackedEpisode?.id ?? null; episodeIds = trackedEpisode?.episodeIds ?? null; } diff --git a/fileflows/tests/test_sonarr_import_safety.py b/fileflows/tests/test_sonarr_import_safety.py index 26f6308..7c45df6 100644 --- a/fileflows/tests/test_sonarr_import_safety.py +++ b/fileflows/tests/test_sonarr_import_safety.py @@ -77,69 +77,6 @@ def run_script(scenario): class SonarrImportSafetyTests(unittest.TestCase): - def test_fhd_scope_does_not_match_uhd_sibling_prefix(self): - exact = ( - "/tdarr/converted/serien4k/Marshals.2026.S01.GERMAN.DUBBED/" - "Marshals.2026.S01E05.GERMAN.DUBBED.mkv" - ) - result = run_script( - { - "releaseTitle": "Marshals.2026.S01E05.GERMAN.DUBBED", - "exactPath": exact, - "scopeRoot": "/tdarr/converted/serien", - } - ) - - self.assertEqual(result["result"], 1) - self.assertEqual(result["calls"], []) - - def test_season_pack_history_uses_exact_episode_filename_for_parse(self): - pack = "Marshals.2026.S01.GERMAN.DUBBED.DL.2160p.WEB.H265-TSCC" - episode = "Marshals.2026.S01E05.GERMAN.DUBBED.DL.2160p.WEB.H265-TSCC" - exact = f"/tdarr/converted/serien4k/{pack}/{episode}.mkv" - queue_records = [ - {"title": pack, "seriesId": 600, "episodeId": 37500 + number} - for number in range(1, 14) - ] - history_records = [ - { - "sourceTitle": pack, - "seriesId": 600, - "episodeId": 37500 + number, - "eventType": "grabbed", - } - for number in range(1, 14) - ] - result = run_script( - { - "releaseTitle": episode, - "exactPath": exact, - "scopeRoot": "/tdarr/converted/serien4k", - "queueResponse": {"records": queue_records}, - "historyResponse": {"records": history_records}, - "parseResponse": { - "series": {"id": 600, "title": "Marshals"}, - "episodes": [{"id": 37505}], - }, - "candidates": [ - { - "path": exact, - "quality": {"quality": {"id": 19, "name": "WEBDL-2160p"}}, - "languages": [{"id": 4, "name": "German"}], - } - ], - } - ) - - self.assertEqual(result["result"], 1) - command = next(call for call in result["calls"] if call["type"] == "command") - self.assertEqual(command["body"]["files"][0]["episodeIds"], [37505]) - parse_call = next( - call for call in result["calls"] - if call["type"] == "fetch" and call["endpoint"] == "parse" - ) - self.assertIn("s01e05", parse_call["query"].lower()) - def test_percent_title_matches_queue_and_imports_exact_episode_file(self): source_title = ( "100%.Wolf.S01E01.Die.Aufnahmeprufung.German.1080p."