Split search actions and improve download options
This commit is contained in:
@@ -1302,13 +1302,10 @@ async def action_search(request_id: str, user: Dict[str, str] = Depends(get_curr
|
||||
if client.configured():
|
||||
await _ensure_request_access(client, int(request_id), user)
|
||||
snapshot = await build_snapshot(request_id)
|
||||
arr_item = snapshot.raw.get("arr", {}).get("item")
|
||||
if not isinstance(arr_item, dict):
|
||||
raise HTTPException(status_code=404, detail="Item not found in Sonarr/Radarr")
|
||||
|
||||
prowlarr_results: List[Dict[str, Any]] = []
|
||||
prowlarr = ProwlarrClient(runtime.prowlarr_base_url, runtime.prowlarr_api_key)
|
||||
if prowlarr.configured():
|
||||
if not prowlarr.configured():
|
||||
raise HTTPException(status_code=400, detail="Prowlarr not configured")
|
||||
query = snapshot.title
|
||||
if snapshot.year:
|
||||
query = f"{query} {snapshot.year}"
|
||||
@@ -1318,6 +1315,28 @@ async def action_search(request_id: str, user: Dict[str, str] = Depends(get_curr
|
||||
except httpx.HTTPStatusError:
|
||||
prowlarr_results = []
|
||||
|
||||
await asyncio.to_thread(
|
||||
save_action,
|
||||
request_id,
|
||||
"search_releases",
|
||||
"Search and choose a download",
|
||||
"ok",
|
||||
f"Found {len(prowlarr_results)} releases.",
|
||||
)
|
||||
return {"status": "ok", "releases": prowlarr_results}
|
||||
|
||||
|
||||
@router.post("/{request_id}/actions/search_auto")
|
||||
async def action_search_auto(request_id: str, user: Dict[str, str] = Depends(get_current_user)) -> dict:
|
||||
runtime = get_runtime_settings()
|
||||
client = JellyseerrClient(runtime.jellyseerr_base_url, runtime.jellyseerr_api_key)
|
||||
if client.configured():
|
||||
await _ensure_request_access(client, int(request_id), user)
|
||||
snapshot = await build_snapshot(request_id)
|
||||
arr_item = snapshot.raw.get("arr", {}).get("item")
|
||||
if not isinstance(arr_item, dict):
|
||||
raise HTTPException(status_code=404, detail="Item not found in Sonarr/Radarr")
|
||||
|
||||
if snapshot.request_type.value == "tv":
|
||||
client = SonarrClient(runtime.sonarr_base_url, runtime.sonarr_api_key)
|
||||
if not client.configured():
|
||||
@@ -1325,12 +1344,11 @@ async def action_search(request_id: str, user: Dict[str, str] = Depends(get_curr
|
||||
episodes = await client.get_episodes(int(arr_item["id"]))
|
||||
missing_by_season = _missing_episode_ids_by_season(episodes)
|
||||
if not missing_by_season:
|
||||
return {
|
||||
"status": "ok",
|
||||
"message": "No missing monitored episodes found",
|
||||
"searched": [],
|
||||
"releases": prowlarr_results,
|
||||
}
|
||||
message = "No missing monitored episodes found."
|
||||
await asyncio.to_thread(
|
||||
save_action, request_id, "search_auto", "Search and auto-download", "ok", message
|
||||
)
|
||||
return {"status": "ok", "message": message, "searched": []}
|
||||
responses = []
|
||||
for season_number in sorted(missing_by_season.keys()):
|
||||
episode_ids = missing_by_season[season_number]
|
||||
@@ -1339,32 +1357,22 @@ async def action_search(request_id: str, user: Dict[str, str] = Depends(get_curr
|
||||
responses.append(
|
||||
{"season": season_number, "episodeCount": len(episode_ids), "response": response}
|
||||
)
|
||||
result = {"status": "ok", "searched": responses, "releases": prowlarr_results}
|
||||
message = "Search sent to Sonarr."
|
||||
await asyncio.to_thread(
|
||||
save_action,
|
||||
request_id,
|
||||
"search",
|
||||
"Re-run search in Sonarr/Radarr",
|
||||
"ok",
|
||||
f"Found {len(prowlarr_results)} releases.",
|
||||
save_action, request_id, "search_auto", "Search and auto-download", "ok", message
|
||||
)
|
||||
return result
|
||||
elif snapshot.request_type.value == "movie":
|
||||
return {"status": "ok", "message": message, "searched": responses}
|
||||
if snapshot.request_type.value == "movie":
|
||||
client = RadarrClient(runtime.radarr_base_url, runtime.radarr_api_key)
|
||||
if not client.configured():
|
||||
raise HTTPException(status_code=400, detail="Radarr not configured")
|
||||
response = await client.search(int(arr_item["id"]))
|
||||
result = {"status": "ok", "response": response, "releases": prowlarr_results}
|
||||
message = "Search sent to Radarr."
|
||||
await asyncio.to_thread(
|
||||
save_action,
|
||||
request_id,
|
||||
"search",
|
||||
"Re-run search in Sonarr/Radarr",
|
||||
"ok",
|
||||
f"Found {len(prowlarr_results)} releases.",
|
||||
save_action, request_id, "search_auto", "Search and auto-download", "ok", message
|
||||
)
|
||||
return result
|
||||
else:
|
||||
return {"status": "ok", "message": message, "response": response}
|
||||
|
||||
raise HTTPException(status_code=400, detail="Unknown request type")
|
||||
|
||||
|
||||
|
||||
@@ -550,8 +550,15 @@ async def build_snapshot(request_id: str) -> Snapshot:
|
||||
elif arr_item and arr_state != "available":
|
||||
actions.append(
|
||||
ActionOption(
|
||||
id="search",
|
||||
label="Search again for releases",
|
||||
id="search_auto",
|
||||
label="Search and auto-download",
|
||||
risk="low",
|
||||
)
|
||||
)
|
||||
actions.append(
|
||||
ActionOption(
|
||||
id="search_releases",
|
||||
label="Search and choose a download",
|
||||
risk="low",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -484,7 +484,8 @@ export default function RequestTimelinePage({ params }: { params: { id: string }
|
||||
}
|
||||
const baseUrl = getApiBase()
|
||||
const actionMap: Record<string, string> = {
|
||||
search: 'actions/search',
|
||||
search_releases: 'actions/search',
|
||||
search_auto: 'actions/search_auto',
|
||||
resume_torrent: 'actions/qbit/resume',
|
||||
readd_to_arr: 'actions/readd',
|
||||
}
|
||||
@@ -493,7 +494,7 @@ export default function RequestTimelinePage({ params }: { params: { id: string }
|
||||
setActionMessage('This action is not wired yet.')
|
||||
return
|
||||
}
|
||||
if (action.id === 'search') {
|
||||
if (action.id === 'search_releases') {
|
||||
setActionMessage(null)
|
||||
setReleaseOptions([])
|
||||
setSearchRan(false)
|
||||
@@ -513,7 +514,7 @@ export default function RequestTimelinePage({ params }: { params: { id: string }
|
||||
throw new Error(text || `Request failed: ${response.status}`)
|
||||
}
|
||||
const data = await response.json()
|
||||
if (action.id === 'search') {
|
||||
if (action.id === 'search_releases') {
|
||||
if (Array.isArray(data.releases)) {
|
||||
setReleaseOptions(data.releases)
|
||||
}
|
||||
@@ -526,6 +527,10 @@ export default function RequestTimelinePage({ params }: { params: { id: string }
|
||||
setModalMessage('Search complete. Pick an option below if you want to download.')
|
||||
}
|
||||
setActionMessage(`${action.label} started.`)
|
||||
} else if (action.id === 'search_auto') {
|
||||
const message = data?.message ?? 'Search sent to Sonarr/Radarr.'
|
||||
setActionMessage(message)
|
||||
setModalMessage(message)
|
||||
} else {
|
||||
const message = data?.message ?? `${action.label} started.`
|
||||
setActionMessage(message)
|
||||
@@ -565,6 +570,7 @@ export default function RequestTimelinePage({ params }: { params: { id: string }
|
||||
<span>{release.seeders ?? 0} seeders · {formatBytes(release.size)}</span>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!release.guid || !release.indexerId}
|
||||
onClick={async () => {
|
||||
if (!snapshot || !release.guid || !release.indexerId) {
|
||||
setActionMessage('Missing details to start the download.')
|
||||
|
||||
Reference in New Issue
Block a user