Add quality-aware release picker modal
This commit is contained in:
@@ -1686,7 +1686,24 @@ def _filter_arr_release_results(results: Any) -> List[Dict[str, Any]]:
|
||||
key = (item.get("indexerId"), item.get("guid"))
|
||||
if not key[0] or not key[1] or key in seen:
|
||||
continue
|
||||
rejections = item.get("rejections")
|
||||
if (
|
||||
item.get("approved") is not True
|
||||
or item.get("rejected") is True
|
||||
or item.get("temporarilyRejected") is True
|
||||
or item.get("downloadAllowed") is False
|
||||
or isinstance(rejections, list) and bool(rejections)
|
||||
):
|
||||
continue
|
||||
seen.add(key)
|
||||
quality_payload = item.get("quality")
|
||||
quality_name = None
|
||||
if isinstance(quality_payload, dict):
|
||||
quality_value = quality_payload.get("quality")
|
||||
if isinstance(quality_value, dict):
|
||||
quality_name = str(quality_value.get("name") or "").strip() or None
|
||||
elif isinstance(quality_payload.get("name"), str):
|
||||
quality_name = quality_payload["name"].strip() or None
|
||||
keep.append(
|
||||
{
|
||||
"title": item.get("title"),
|
||||
@@ -1708,9 +1725,14 @@ def _filter_arr_release_results(results: Any) -> List[Dict[str, Any]]:
|
||||
"downloadAllowed": item.get("downloadAllowed"),
|
||||
"fullSeason": item.get("fullSeason"),
|
||||
"seasonNumber": item.get("seasonNumber"),
|
||||
"quality": quality_name,
|
||||
"customFormatScore": item.get("customFormatScore"),
|
||||
}
|
||||
)
|
||||
return keep[:30]
|
||||
releases = keep[:30]
|
||||
for index, release in enumerate(releases):
|
||||
release["bestPick"] = index == 0
|
||||
return releases
|
||||
|
||||
|
||||
def _build_release_push_payload(payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
@@ -3210,9 +3232,18 @@ async def action_search(request_id: str, user: Dict[str, str] = Depends(get_curr
|
||||
"search_releases",
|
||||
"Search and choose a download",
|
||||
"ok",
|
||||
f"{collector} found {len(releases)} releases.",
|
||||
f"{collector} approved {len(releases)} releases against its assigned quality profile.",
|
||||
)
|
||||
return {"status": "ok", "collector": collector, "releases": releases}
|
||||
return {
|
||||
"status": "ok",
|
||||
"collector": collector,
|
||||
"qualityFiltered": True,
|
||||
"message": (
|
||||
f"{collector} approved {len(releases)} release{'s' if len(releases) != 1 else ''} "
|
||||
"against its assigned quality profile."
|
||||
),
|
||||
"releases": releases,
|
||||
}
|
||||
|
||||
|
||||
@router.post("/{request_id}/actions/search_auto")
|
||||
|
||||
@@ -1124,6 +1124,18 @@ class CollectorManualDownloadTests(unittest.IsolatedAsyncioTestCase):
|
||||
"protocol": "torrent",
|
||||
"fullSeason": True,
|
||||
"seasonNumber": 1,
|
||||
"approved": True,
|
||||
"rejected": False,
|
||||
"downloadAllowed": True,
|
||||
"quality": {"quality": {"name": "WEBDL-1080p"}},
|
||||
},
|
||||
{
|
||||
"title": "Example.Show.S01.2160p",
|
||||
"guid": "outside-profile",
|
||||
"indexerId": 7,
|
||||
"approved": False,
|
||||
"rejected": True,
|
||||
"rejections": ["Quality is not wanted in profile"],
|
||||
}
|
||||
],
|
||||
[],
|
||||
@@ -1143,8 +1155,12 @@ class CollectorManualDownloadTests(unittest.IsolatedAsyncioTestCase):
|
||||
sonarr.search_releases.assert_any_await(42, 1)
|
||||
sonarr.search_releases.assert_any_await(42, 2)
|
||||
self.assertEqual(result["collector"], "Sonarr")
|
||||
self.assertEqual(len(result["releases"]), 1)
|
||||
self.assertTrue(result["releases"][0]["fullSeason"])
|
||||
self.assertEqual(result["releases"][0]["seasonNumber"], 1)
|
||||
self.assertEqual(result["releases"][0]["quality"], "WEBDL-1080p")
|
||||
self.assertTrue(result["releases"][0]["bestPick"])
|
||||
self.assertTrue(result["qualityFiltered"])
|
||||
|
||||
async def test_movie_manual_search_uses_radarr(self) -> None:
|
||||
snapshot = Snapshot(
|
||||
@@ -1163,6 +1179,9 @@ class CollectorManualDownloadTests(unittest.IsolatedAsyncioTestCase):
|
||||
"indexerId": 9,
|
||||
"indexer": "Prowlarr",
|
||||
"protocol": "torrent",
|
||||
"approved": True,
|
||||
"rejected": False,
|
||||
"downloadAllowed": True,
|
||||
}
|
||||
]
|
||||
),
|
||||
@@ -1180,6 +1199,32 @@ class CollectorManualDownloadTests(unittest.IsolatedAsyncioTestCase):
|
||||
radarr.search_releases.assert_awaited_once_with(84)
|
||||
self.assertEqual(result["collector"], "Radarr")
|
||||
self.assertEqual(result["releases"][0]["guid"], "movie-release")
|
||||
self.assertTrue(result["releases"][0]["bestPick"])
|
||||
|
||||
def test_manual_release_filter_requires_explicit_arr_approval(self) -> None:
|
||||
releases = requests_router._filter_arr_release_results(
|
||||
[
|
||||
{"title": "Missing decision", "guid": "missing", "indexerId": 1},
|
||||
{
|
||||
"title": "Temporarily rejected",
|
||||
"guid": "temporary",
|
||||
"indexerId": 1,
|
||||
"approved": True,
|
||||
"temporarilyRejected": True,
|
||||
},
|
||||
{
|
||||
"title": "Approved release",
|
||||
"guid": "approved",
|
||||
"indexerId": 1,
|
||||
"approved": True,
|
||||
"rejected": False,
|
||||
"downloadAllowed": True,
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual([release["guid"] for release in releases], ["approved"])
|
||||
self.assertTrue(releases[0]["bestPick"])
|
||||
|
||||
async def test_tv_manual_grab_is_sent_to_sonarr_not_qbittorrent(self) -> None:
|
||||
snapshot = Snapshot(
|
||||
|
||||
Reference in New Issue
Block a user