From 81a01d5880e8e865710ace88e4bdc3a4eca3b0e3 Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:03:07 +0200 Subject: [PATCH 01/12] fix: preserve Arr metadata and fail closed --- .../scripts/Sonarr_-_Trigger_Manual_Import.js | 68 +++++++++++++++---- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/fileflows/scripts/Sonarr_-_Trigger_Manual_Import.js b/fileflows/scripts/Sonarr_-_Trigger_Manual_Import.js index 6e06bcd..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 9 + * @revision 10 * @output Import erfolgreich * @output Fehler * @param {string} URL Sonarr root URL and port @@ -43,14 +43,22 @@ function Script(URL, ApiKey, ImportPath, UseUnmappedPath, MoveMode, TimeOut) { const sonarr = new Sonarr(URL, ApiKey); /*── seriesId / episodeId detection ──────────────────────────────────*/ - const searchPattern = Variables.file.Orig.FileNameNoExtension; + const filePattern = Variables.file.Orig.FileNameNoExtension; + const folderPattern = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(exactImportPath)); + const searchPatterns = [folderPattern, filePattern] + .filter(Boolean) + .filter((value, index, values) => values.indexOf(value) === index); let seriesId = Variables['Sonarr.seriesId'] ?? Variables.TVShowInfo?.id ?? null; let episodeIds = Variables['Sonarr.episodeIds'] ?? Variables.TVShowInfo?.EpisodesInfo ?? null; if (!(seriesId && episodeIds)) { - const trackedEpisode = findEpisodeFromQueue(searchPattern, sonarr) - ?? findEpisodeFromGrabHistory(searchPattern, sonarr) - ?? parseSeries(searchPattern, sonarr); + let trackedEpisode = null; + for (const pattern of searchPatterns) { + trackedEpisode = findEpisodeFromQueue(pattern, sonarr) + ?? findEpisodeFromGrabHistory(pattern, sonarr); + if (trackedEpisode) break; + } + if (!trackedEpisode) trackedEpisode = parseSeries(searchPatterns[0] || '', sonarr); seriesId = trackedEpisode?.id ?? null; episodeIds = trackedEpisode?.episodeIds ?? null; } @@ -60,11 +68,12 @@ function Script(URL, ApiKey, ImportPath, UseUnmappedPath, MoveMode, TimeOut) { Logger.ILog(`Import Mode: ${importMode}`); if (seriesId && episodeIds) { + const releaseMetadata = findGrabMetadata(searchPatterns, sonarr, seriesId, episodeIds); Logger.ILog(`seriesId=${seriesId}, episodeIds=[${episodeIds.join(', ')}] → ManualImport`); - return manualImportWorkflow(sonarr, exactImportPath, importMode, seriesId, episodeIds, TimeOut); + return manualImportWorkflow(sonarr, exactImportPath, importMode, seriesId, episodeIds, releaseMetadata, TimeOut); } - Logger.ELog(`Unable to identify '${searchPattern}' uniquely; file remains for manual recovery.`); + Logger.ELog(`Unable to identify '${searchPatterns.join("' or '")}' uniquely; file remains for manual recovery.`); return -1; } @@ -80,7 +89,7 @@ function Script(URL, ApiKey, ImportPath, UseUnmappedPath, MoveMode, TimeOut) { * @param {number} timeout - Timeout in milliseconds * @returns {number} 1 on success, −1 on failure */ -function manualImportWorkflow(sonarr, path, mode, seriesId, episodeIds, timeout) { +function manualImportWorkflow(sonarr, path, mode, seriesId, episodeIds, releaseMetadata, timeout) { const candidates = getManualImportCandidates(sonarr, path); if (!candidates.length) { Logger.WLog('No candidates returned by fetching ManualImport'); @@ -98,7 +107,7 @@ function manualImportWorkflow(sonarr, path, mode, seriesId, episodeIds, timeout) return -1; } - const fileObj = buildManualImportFile(cand, seriesId, episodeIds, path); + const fileObj = buildManualImportFile(cand, seriesId, episodeIds, path, releaseMetadata); const cmdBody = { name: 'ManualImport', files: [fileObj], importMode: mode }; const cmdId = sendManualImportCommand(sonarr, cmdBody); if (cmdId === null) { @@ -137,23 +146,52 @@ function getManualImportCandidates(sonarr, importPath) { * @param {number} episodeIds – Sonarr episodeIds to which the file is linked * @returns {object} File descriptor for ManualImport */ -function buildManualImportFile(src, seriesId, episodeIds, importPath) { +function buildManualImportFile(src, seriesId, episodeIds, importPath, releaseMetadata) { const path = src.path || importPath; const fallbackFolder = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(path)) ?? Variables.folder.Name; + const metadata = releaseMetadata || {}; + const metadataData = metadata.data || {}; return { path: path, folderName: src.folderName || src.name || fallbackFolder, seriesId: seriesId, episodeIds: episodeIds, - releaseGroup: src.releaseGroup || 'Sonarr', - quality: src.quality, - languages: src.languages || [ { id:0, name:'Unknown' } ], - indexerFlags: src.indexerFlags ?? 0, - releaseType: src.releaseType ?? 'unknown' + releaseGroup: metadataData.releaseGroup || metadata.releaseGroup || src.releaseGroup || 'Sonarr', + quality: metadata.quality || src.quality, + languages: metadata.languages || src.languages || [ { id:0, name:'Unknown' } ], + indexerFlags: Number(metadataData.indexerFlags ?? metadata.indexerFlags ?? src.indexerFlags ?? 0), + releaseType: metadataData.releaseType || metadata.releaseType || src.releaseType || 'unknown' }; } +function findGrabMetadata(searchPatterns, sonarr, seriesId, episodeIds) { + try { + const query = buildQueryParams({ + page: 1, pageSize: 250, eventType: 1, + sortKey: 'date', sortDirection: 'descending' + }); + const response = sonarr.fetchJson('history', query) || {}; + const records = Array.isArray(response) ? response : (response.records || []); + const wanted = searchPatterns.map(normalizeReleaseTitle); + const matching = records.filter(item => + item?.seriesId === seriesId + && episodeIds.includes(item?.episodeId) + && wanted.includes(normalizeReleaseTitle(item.sourceTitle || '')) + ); + if (!matching.length) return null; + const targetKeys = matching + .map(item => `${item.seriesId}:${item.episodeId}`) + .filter((key, index, values) => values.indexOf(key) === index); + if (targetKeys.some(key => !episodeIds.includes(Number(key.split(':')[1])))) return null; + Logger.ILog(`Using metadata from exact Sonarr grab history match (${matching[0].sourceTitle}).`); + return matching[0]; + } catch (e) { + Logger.WLog(`Unable to recover Sonarr grab metadata: ${e.message}`); + return null; + } +} + /** * @description Send the **ManualImport** command to Sonarr and return command-id * @param {Sonarr} sonarr – Sonarr API instance From 3c714618e6a649989fe3c289f426d873994dcdf7 Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:03:08 +0200 Subject: [PATCH 02/12] fix: preserve Arr metadata and fail closed --- .../scripts/Radarr_-_Trigger_Manual_Import.js | 69 ++++++++++++++----- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/fileflows/scripts/Radarr_-_Trigger_Manual_Import.js b/fileflows/scripts/Radarr_-_Trigger_Manual_Import.js index 5ebc556..b4c4844 100644 --- a/fileflows/scripts/Radarr_-_Trigger_Manual_Import.js +++ b/fileflows/scripts/Radarr_-_Trigger_Manual_Import.js @@ -2,7 +2,7 @@ * @name Radarr - Trigger Manual Import * @description Safely trigger Radarr ManualImport for exactly one processed file. * @author FileFlows + Sascha - * @revision 10 + * @revision 11 * @output Import erfolgreich * @output Fehler * @param {string} URL Radarr root URL and port @@ -48,12 +48,20 @@ function Script(URL, ApiKey, ImportPath, UseUnmappedPath, MoveMode, TimeOut) { const radarr = new Radarr(URL, ApiKey); /*── movieId detection ──────────────────────────────────*/ - const searchPattern = Variables.file.Orig.FileNameNoExtension; - let movieId = Variables['Radarr.movieId'] - ?? findMovieIdFromQueue(searchPattern, radarr) - ?? findMovieIdFromGrabHistory(searchPattern, radarr) - ?? parseMovie(searchPattern, radarr) - ?? null; + const filePattern = Variables.file.Orig.FileNameNoExtension; + const folderPattern = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(exactImportPath)); + const searchPatterns = [folderPattern, filePattern] + .filter(Boolean) + .filter((value, index, values) => values.indexOf(value) === index); + let movieId = Variables['Radarr.movieId'] ?? null; + for (const pattern of searchPatterns) { + if (!movieId) { + movieId = findMovieIdFromQueue(pattern, radarr) + ?? findMovieIdFromGrabHistory(pattern, radarr); + } + if (movieId) break; + } + if (!movieId) movieId = parseMovie(searchPatterns[0] || '', radarr); Logger.ILog(`Radarr URL: ${URL}`); Logger.ILog(`Triggering Path: ${exactImportPath}`); @@ -61,11 +69,12 @@ function Script(URL, ApiKey, ImportPath, UseUnmappedPath, MoveMode, TimeOut) { Logger.ILog(movieId ? `movieId: ${movieId} → ManualImport` : 'No unambiguous movieId → fail closed'); if (!movieId) { - Logger.ELog(`Unable to identify '${searchPattern}' uniquely; file remains for manual recovery.`); + Logger.ELog(`Unable to identify '${searchPatterns.join("' or '")}' uniquely; file remains for manual recovery.`); return -1; } - return manualImportWorkflow(radarr, exactImportPath, importMode, movieId, TimeOut); + const releaseMetadata = findGrabMetadata(searchPatterns, radarr, movieId); + return manualImportWorkflow(radarr, exactImportPath, importMode, movieId, releaseMetadata, TimeOut); } @@ -80,7 +89,7 @@ function Script(URL, ApiKey, ImportPath, UseUnmappedPath, MoveMode, TimeOut) { * @param {number} timeout - Timeout in milliseconds * @returns {number} 1 on success, −1 on failure */ -function manualImportWorkflow(radarr, importPath, mode, movieId, timeout) { +function manualImportWorkflow(radarr, importPath, mode, movieId, releaseMetadata, timeout) { const candidates = getManualImportCandidates(radarr, importPath); if (!candidates.length) { Logger.WLog('No candidates returned by fetching ManualImport'); @@ -98,7 +107,7 @@ function manualImportWorkflow(radarr, importPath, mode, movieId, timeout) { return -1; } - const fileObj = buildManualImportFile(cand, movieId, importPath); + const fileObj = buildManualImportFile(cand, movieId, importPath, releaseMetadata); const cmdBody = { name: 'ManualImport', files: [fileObj], importMode: mode }; const cmdId = sendManualImportCommand(radarr, cmdBody); if (cmdId === null) { @@ -133,21 +142,49 @@ function getManualImportCandidates(radarr, importPath) { * @param {number} movieId – Radarr movieId to which the file is linked * @returns {object} File descriptor for ManualImport */ -function buildManualImportFile(src, movieId, importPath) { +function buildManualImportFile(src, movieId, importPath, releaseMetadata) { const path = src.path || importPath const fallbackFolder = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(path)) ?? Variables.folder.Name; + const metadata = releaseMetadata || {}; + const metadataData = metadata.data || {}; return { path: path, folderName: src.folderName || src.name || fallbackFolder, movieId: movieId, - releaseGroup: src.releaseGroup || 'Radarr', - quality: src.quality, - languages: src.languages || [ { id:0, name:'Unknown' } ], - indexerFlags: src.indexerFlags ?? 0 + releaseGroup: metadataData.releaseGroup || metadata.releaseGroup || src.releaseGroup || 'Radarr', + quality: metadata.quality || src.quality, + languages: metadata.languages || src.languages || [ { id:0, name:'Unknown' } ], + indexerFlags: Number(metadataData.indexerFlags ?? metadata.indexerFlags ?? src.indexerFlags ?? 0) }; } +function findGrabMetadata(searchPatterns, radarr, movieId) { + try { + const query = buildQueryParams({ + page: 1, pageSize: 250, eventType: 1, + sortKey: 'date', sortDirection: 'descending' + }); + const response = radarr.fetchJson('history', query) || {}; + const records = Array.isArray(response) ? response : (response.records || []); + const wanted = searchPatterns.map(normalizeReleaseTitle); + const matching = records.filter(item => + item?.movieId === movieId + && wanted.includes(normalizeReleaseTitle(item.sourceTitle || '')) + ); + if (!matching.length) return null; + const movieIds = matching + .map(item => item.movieId) + .filter((id, index, values) => values.indexOf(id) === index); + if (movieIds.length !== 1) return null; + Logger.ILog(`Using metadata from exact Radarr grab history match (${matching[0].sourceTitle}).`); + return matching[0]; + } catch (e) { + Logger.WLog(`Unable to recover Radarr grab metadata: ${e.message}`); + return null; + } +} + /** * @description Send the **ManualImport** command to Radarr and return command-id * @param {Radarr} radarr – Radarr API instance From c0913a29ae3448a3724a23968ed712a03e3ca7dd Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:03:09 +0200 Subject: [PATCH 03/12] fix: preserve Arr metadata and fail closed --- fileflows/tests/test_sonarr_import_safety.py | 92 ++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/fileflows/tests/test_sonarr_import_safety.py b/fileflows/tests/test_sonarr_import_safety.py index b05ee18..7c45df6 100644 --- a/fileflows/tests/test_sonarr_import_safety.py +++ b/fileflows/tests/test_sonarr_import_safety.py @@ -119,6 +119,98 @@ class SonarrImportSafetyTests(unittest.TestCase): [call.get("name") for call in commands], ) + def test_release_folder_matches_when_episode_filename_is_scene_shortened(self): + release = ( + "Angie.Tribeca.S01E06.Frettchen.Royale.GERMAN.DL." + "1080p.HDTV.x264-SYNCTV" + ) + exact = f"/tdarr/converted/serien/{release}/synctv-angie.s01e06.1080p.mkv" + result = run_script( + { + "releaseTitle": "synctv-angie.s01e06.1080p", + "exactPath": exact, + "scopeRoot": "/tdarr/converted/serien", + "queueResponse": { + "records": [ + {"title": release, "seriesId": 853, "episodeId": 63336} + ] + }, + "historyResponse": {"records": []}, + "parseResponse": {}, + "candidates": [ + { + "path": exact, + "quality": {"quality": {"id": 4, "name": "HDTV-1080p"}}, + "languages": [{"id": 4, "name": "German"}], + } + ], + } + ) + + self.assertEqual(result["result"], 1) + command = next(call for call in result["calls"] if call["type"] == "command") + imported = command["body"]["files"][0] + self.assertEqual(imported["seriesId"], 853) + self.assertEqual(imported["episodeIds"], [63336]) + + def test_grab_metadata_overrides_unknown_manualimport_metadata(self): + release = ( + "The.Night.Agent.2025.S02E04.Desperate.Measures.2160p.NF." + "WEB-DL.MULTi.DDP5.1.Atmos.H.265-FUZEER" + ) + exact = f"/tdarr/converted/serien4k/{release}/{release}.mkv" + grabbed_quality = {"quality": {"id": 18, "name": "WEBDL-2160p"}} + grabbed_languages = [ + {"id": 1, "name": "English"}, + {"id": 4, "name": "German"}, + ] + result = run_script( + { + "releaseTitle": release, + "exactPath": exact, + "scopeRoot": "/tdarr/converted/serien4k", + "queueResponse": { + "records": [ + {"title": release, "seriesId": 602, "episodeId": 37528} + ] + }, + "historyResponse": { + "records": [ + { + "sourceTitle": release, + "seriesId": 602, + "episodeId": 37528, + "eventType": "grabbed", + "quality": grabbed_quality, + "languages": grabbed_languages, + "data": { + "releaseGroup": "FUZEER", + "indexerFlags": "8", + "releaseType": "SingleEpisode", + }, + } + ] + }, + "candidates": [ + { + "path": exact, + "releaseGroup": "Sonarr", + "quality": {"quality": {"id": 0, "name": "Unknown"}}, + "languages": [{"id": 0, "name": "Unknown"}], + } + ], + } + ) + + self.assertEqual(result["result"], 1) + command = next(call for call in result["calls"] if call["type"] == "command") + imported = command["body"]["files"][0] + self.assertEqual(imported["quality"], grabbed_quality) + self.assertEqual(imported["languages"], grabbed_languages) + self.assertEqual(imported["releaseGroup"], "FUZEER") + self.assertEqual(imported["indexerFlags"], 8) + self.assertEqual(imported["releaseType"], "SingleEpisode") + if __name__ == "__main__": unittest.main() From 82b14a07320fadcc0ff4e3b4cf8afe8afa6a4c2d Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:03:09 +0200 Subject: [PATCH 04/12] fix: preserve Arr metadata and fail closed --- fileflows/tests/test_radarr_import_safety.py | 45 ++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/fileflows/tests/test_radarr_import_safety.py b/fileflows/tests/test_radarr_import_safety.py index a895783..d8f9864 100644 --- a/fileflows/tests/test_radarr_import_safety.py +++ b/fileflows/tests/test_radarr_import_safety.py @@ -193,6 +193,51 @@ class RadarrImportSafetyTests(unittest.TestCase): ) self.assertIn("eventType=1", history_fetch["query"]) + def test_grab_metadata_overrides_unknown_manualimport_metadata(self): + release = "American.Sweatshop.2025.German.DTSHD.DL.1080p.BluRay.AVC.Remux-MAMA" + exact = f"/tdarr/converted/video/{release}/{release}.mkv" + grabbed_quality = {"quality": {"id": 30, "name": "Remux-1080p"}} + grabbed_languages = [ + {"id": 1, "name": "English"}, + {"id": 4, "name": "German"}, + ] + result = run_script( + { + "releaseTitle": release, + "exactPath": exact, + "scopeRoot": "/tdarr/converted/video/", + "queueResponse": {"records": [{"title": release, "movieId": 6425}]}, + "historyResponse": { + "records": [ + { + "sourceTitle": release, + "movieId": 6425, + "eventType": "grabbed", + "quality": grabbed_quality, + "languages": grabbed_languages, + "data": {"releaseGroup": "MAMA", "indexerFlags": "4"}, + } + ] + }, + "candidates": [ + { + "path": exact, + "releaseGroup": "Radarr", + "quality": {"quality": {"id": 0, "name": "Unknown"}}, + "languages": [{"id": 0, "name": "Unknown"}], + } + ], + } + ) + + self.assertEqual(result["result"], 1) + command = next(call for call in result["calls"] if call["type"] == "command") + imported = command["body"]["files"][0] + self.assertEqual(imported["quality"], grabbed_quality) + self.assertEqual(imported["languages"], grabbed_languages) + self.assertEqual(imported["releaseGroup"], "MAMA") + self.assertEqual(imported["indexerFlags"], 4) + if __name__ == "__main__": unittest.main() From e23374e24b62daa8dfd62dbb00a738dda3b0bb31 Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:03:10 +0200 Subject: [PATCH 05/12] fix: preserve Arr metadata and fail closed --- .../tests/test_flow_import_failure_routing.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 fileflows/tests/test_flow_import_failure_routing.py diff --git a/fileflows/tests/test_flow_import_failure_routing.py b/fileflows/tests/test_flow_import_failure_routing.py new file mode 100644 index 0000000..bdb370c --- /dev/null +++ b/fileflows/tests/test_flow_import_failure_routing.py @@ -0,0 +1,31 @@ +import json +import unittest +from pathlib import Path + + +FLOW = Path(__file__).parents[1] / "flow" / "flow_auto_movie_pipeline.json" + + +class FlowImportFailureRoutingTests(unittest.TestCase): + def test_arr_import_failures_route_to_fail_flow(self): + flow = json.loads(FLOW.read_text()) + fail_node = next( + part + for part in flow["Parts"] + if part.get("FlowElementUid") == "FileFlows.BasicNodes.Functions.FailFlow" + ) + import_nodes = [ + part + for part in flow["Parts"] + if part.get("Name") + in {"Sonarr - Trigger Manual Import", "Radarr - Trigger Manual Import"} + ] + + self.assertEqual(len(import_nodes), 4) + for node in import_nodes: + with self.subTest(node=node["Uid"]): + self.assertEqual(node["ErrorConnection"]["InputNode"], fail_node["Uid"]) + + +if __name__ == "__main__": + unittest.main() From d3488078e1de04f5e19129fb2d30d897ec640612 Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:03:11 +0200 Subject: [PATCH 06/12] fix: preserve Arr metadata and fail closed --- fileflows/flow/flow_auto_movie_pipeline.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fileflows/flow/flow_auto_movie_pipeline.json b/fileflows/flow/flow_auto_movie_pipeline.json index 35498dc..91cffd0 100644 --- a/fileflows/flow/flow_auto_movie_pipeline.json +++ b/fileflows/flow/flow_auto_movie_pipeline.json @@ -310,7 +310,7 @@ "ErrorConnection": { "Input": 1, "Output": -1, - "InputNode": "64a5eb5c-13d3-47d7-b67a-a013fad58145" + "InputNode": "6bf4e65f-5376-4b52-a754-bc0972620be4" }, "Type": 9, "Model": { @@ -343,7 +343,7 @@ "ErrorConnection": { "Input": 1, "Output": -1, - "InputNode": "64a5eb5c-13d3-47d7-b67a-a013fad58145" + "InputNode": "6bf4e65f-5376-4b52-a754-bc0972620be4" }, "Type": 9, "Model": { @@ -377,7 +377,7 @@ "ErrorConnection": { "Input": 1, "Output": -1, - "InputNode": "64a5eb5c-13d3-47d7-b67a-a013fad58145" + "InputNode": "6bf4e65f-5376-4b52-a754-bc0972620be4" }, "Type": 9, "Model": { @@ -411,7 +411,7 @@ "ErrorConnection": { "Input": 1, "Output": -1, - "InputNode": "64a5eb5c-13d3-47d7-b67a-a013fad58145" + "InputNode": "6bf4e65f-5376-4b52-a754-bc0972620be4" }, "Type": 9, "Model": { From 506be2234bdbe14e64fa7693870ed9d15dd81a73 Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:08:00 +0200 Subject: [PATCH 07/12] test: cover shortened Radarr filenames From f817088de5909d1ac224dc38a929bc3e113f4c12 Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:08:00 +0200 Subject: [PATCH 08/12] test: cover shortened Radarr filenames From c62a18beff3ca18cbf6c771ebaff9eeb4572cea0 Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:08:01 +0200 Subject: [PATCH 09/12] test: cover shortened Radarr filenames From 188164c3e582d00acdeaa8abcb0571d7d6b24b2e Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:08:02 +0200 Subject: [PATCH 10/12] test: cover shortened Radarr filenames --- fileflows/tests/test_radarr_import_safety.py | 25 ++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/fileflows/tests/test_radarr_import_safety.py b/fileflows/tests/test_radarr_import_safety.py index d8f9864..b281ec2 100644 --- a/fileflows/tests/test_radarr_import_safety.py +++ b/fileflows/tests/test_radarr_import_safety.py @@ -238,6 +238,31 @@ class RadarrImportSafetyTests(unittest.TestCase): self.assertEqual(imported["releaseGroup"], "MAMA") self.assertEqual(imported["indexerFlags"], 4) + def test_release_folder_matches_when_movie_filename_is_shortened(self): + release = "Example.Movie.2026.German.DL.1080p.WEB.H264-GROUP" + exact = f"/tdarr/converted/video/{release}/movie-final.mkv" + result = run_script( + { + "releaseTitle": "movie-final", + "exactPath": exact, + "scopeRoot": "/tdarr/converted/video/", + "queueResponse": {"records": [{"title": release, "movieId": 7331}]}, + "historyResponse": {"records": []}, + "parseResponse": {}, + "candidates": [ + { + "path": exact, + "quality": {"quality": {"id": 3, "name": "WEBDL-1080p"}}, + "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]["movieId"], 7331) + if __name__ == "__main__": unittest.main() From cb094beae3f6b235498fb1f24e7789c677421b33 Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:08:02 +0200 Subject: [PATCH 11/12] test: cover shortened Radarr filenames From b4bb09343d8265ef8187a999b4264b2d82d59710 Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 12 Sep 2026 12:08:03 +0200 Subject: [PATCH 12/12] test: cover shortened Radarr filenames