Compare commits
13 commits
aa575a17fd
...
7f33195ad3
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f33195ad3 | |||
| b4bb09343d | |||
| cb094beae3 | |||
| 188164c3e5 | |||
| c62a18beff | |||
| f817088de5 | |||
| 506be2234b | |||
| d3488078e1 | |||
| e23374e24b | |||
| 82b14a0732 | |||
| c0913a29ae | |||
| 3c714618e6 | |||
| 81a01d5880 |
6 changed files with 303 additions and 35 deletions
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
31
fileflows/tests/test_flow_import_failure_routing.py
Normal file
31
fileflows/tests/test_flow_import_failure_routing.py
Normal file
|
|
@ -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()
|
||||
|
|
@ -193,6 +193,76 @@ 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)
|
||||
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue