Search Sonarr/Radarr directly on Discover, full top nav, live System links
All checks were successful
Deploy / deploy (push) Successful in 24s
All checks were successful
Deploy / deploy (push) Successful in 24s
- Discover's search now hits Radarr's/Sonarr's own lookup endpoints directly (the same ones /add-to-radarr and /add-to-sonarr already use), instead of Ombi — one fewer round trip, and a result always resolves the same way its own Add button will. The Ombi-based ombi_search/_tmdb_poster helpers are gone. - The top nav on every page but the index now lists all eight destinations (FULL_FASTEXT) instead of the original four; the index keeps the original four-entry row as its own closing line (HOME_FASTEXT), since its body already lists every destination once. - System page's Transmission rows are now links to each service's own reverse-proxied instance (service_urls, already injected into every template but unused until now).
This commit is contained in:
parent
abaccaaacd
commit
cef66e7361
4 changed files with 101 additions and 80 deletions
143
app.py
143
app.py
|
|
@ -726,61 +726,6 @@ def ombi_get(endpoint):
|
|||
return resp.json()
|
||||
|
||||
|
||||
def _tmdb_poster(path):
|
||||
"""Ombi's movie search returns a bare TMDB path ('/abc123.jpg'), not a
|
||||
usable URL; TV search returns a full TVDB banner URL already."""
|
||||
if not path:
|
||||
return ""
|
||||
if path.startswith("http"):
|
||||
return path
|
||||
return f"https://image.tmdb.org/t/p/w300{path}"
|
||||
|
||||
|
||||
def ombi_search(q, limit=12):
|
||||
"""Movies and TV matching q, via Ombi's own search — it already sits in
|
||||
front of TheMovieDB/TVDB, so this is one call instead of two more API
|
||||
keys. Cross-referenced against the cached Sonarr/Radarr title sets so a
|
||||
title already held shows that instead of an Add button.
|
||||
"""
|
||||
term = q.strip()
|
||||
if not term:
|
||||
return {"status": "ok", "results": []}
|
||||
encoded = requests.utils.quote(term)
|
||||
try:
|
||||
radarr_titles = {t.lower() for t in get_radarr_summary().get("radarr_titles", [])}
|
||||
sonarr_titles = {t.lower() for t in get_sonarr_summary().get("sonarr_titles", [])}
|
||||
results = []
|
||||
try:
|
||||
for m in ombi_get(f"Search/movie/{encoded}")[:limit]:
|
||||
title = m.get("title", "")
|
||||
results.append({
|
||||
"title": title,
|
||||
"year": (m.get("releaseDate") or "")[:4],
|
||||
"poster": _tmdb_poster(m.get("posterPath")),
|
||||
"kind": "Film",
|
||||
"target": "radarr",
|
||||
"held": bool(m.get("available")) or title.lower() in radarr_titles,
|
||||
})
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
for s in ombi_get(f"Search/tv/{encoded}")[:limit]:
|
||||
title = s.get("title", "")
|
||||
results.append({
|
||||
"title": title,
|
||||
"year": (s.get("firstAired") or "")[:4],
|
||||
"poster": s.get("banner") or _tmdb_poster(s.get("posterPath")),
|
||||
"kind": "TV",
|
||||
"target": "sonarr",
|
||||
"held": bool(s.get("available")) or title.lower() in sonarr_titles,
|
||||
})
|
||||
except Exception:
|
||||
pass
|
||||
return {"status": "ok", "results": results}
|
||||
except Exception as e:
|
||||
return {"status": "error", "error": str(e), "results": []}
|
||||
|
||||
|
||||
def _ombi_status_label(available, approved, denied):
|
||||
if denied:
|
||||
return "Denied"
|
||||
|
|
@ -1358,6 +1303,30 @@ def service_urls():
|
|||
}
|
||||
|
||||
|
||||
# Every destination, for the top of every page but the index. Order
|
||||
# matches nav_items; the four letter keys keep the destinations they
|
||||
# always had, cycling colour for the rest since only four exist.
|
||||
FULL_FASTEXT = [
|
||||
("k-red", "r", "100", "Index", "/"),
|
||||
("k-cyan", "", "101", "Watch", "/watch"),
|
||||
("k-green", "g", "102", "Library", "/library"),
|
||||
("k-yellow", "y", "103", "Discover", "/discover"),
|
||||
("k-red", "", "104", "Requests", "/requests"),
|
||||
("k-cyan", "c", "105", "System", "/system"),
|
||||
("k-green", "", "106", "Activity", "/activity"),
|
||||
("k-yellow", "", "900", "Settings", "/settings"),
|
||||
]
|
||||
|
||||
# The index's own closing row: just the four letter keys, since the
|
||||
# index's body already lists every one of the above once.
|
||||
HOME_FASTEXT = [
|
||||
("k-red", "r", "100", "Index", "/"),
|
||||
("k-green", "g", "102", "Library", "/library"),
|
||||
("k-yellow", "y", "103", "Discover", "/discover"),
|
||||
("k-cyan", "c", "105", "System", "/system"),
|
||||
]
|
||||
|
||||
|
||||
@app.context_processor
|
||||
def inject_page_chrome():
|
||||
"""Shell-wide context: the nav, the clock's timezone, service links."""
|
||||
|
|
@ -1378,15 +1347,12 @@ def inject_page_chrome():
|
|||
("activity", "106", "Activity", "/activity"),
|
||||
("settings", "900", "Settings", "/settings"),
|
||||
],
|
||||
# The four coloured keys along the bottom of every page. A page
|
||||
# that wants different destinations passes its own `fastext` to
|
||||
# render_template, which wins over this default.
|
||||
"fastext": [
|
||||
("k-red", "r", "100", "Index", "/"),
|
||||
("k-green", "g", "102", "Library", "/library"),
|
||||
("k-yellow", "y", "103", "Discover", "/discover"),
|
||||
("k-cyan", "c", "105", "System", "/system"),
|
||||
],
|
||||
# Every page, at the top of every page but the index — which
|
||||
# overrides this with HOME_FASTEXT, its own short closing row,
|
||||
# since its body already lists all of these once. The four
|
||||
# letter keys (r/g/y/c) keep their original destinations; the
|
||||
# rest have no keyboard shortcut, just a click.
|
||||
"fastext": FULL_FASTEXT,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1494,6 +1460,51 @@ def search_library(q, limit=24):
|
|||
return items[:limit]
|
||||
|
||||
|
||||
def arr_search(q, limit=12):
|
||||
"""Movies and TV matching q, straight from Radarr's and Sonarr's own
|
||||
lookup endpoints — the same ones /add-to-radarr and /add-to-sonarr
|
||||
already use to resolve a title before adding. No Ombi round trip and
|
||||
no second title-matching path to keep in sync with the Add buttons.
|
||||
"""
|
||||
term = q.strip()
|
||||
if not term:
|
||||
return {"status": "ok", "results": []}
|
||||
encoded = requests.utils.quote(term)
|
||||
results = []
|
||||
radarr_ok = sonarr_ok = True
|
||||
try:
|
||||
radarr_titles = {t.lower() for t in get_radarr_summary().get("radarr_titles", [])}
|
||||
for m in radarr_get(f"movie/lookup?term={encoded}")[:limit]:
|
||||
title = m.get("title", "")
|
||||
results.append({
|
||||
"title": title,
|
||||
"year": str(m.get("year", "")),
|
||||
"poster": _poster_url(m.get("images")),
|
||||
"kind": "Film",
|
||||
"target": "radarr",
|
||||
"held": title.lower() in radarr_titles,
|
||||
})
|
||||
except Exception:
|
||||
radarr_ok = False
|
||||
try:
|
||||
sonarr_titles = {t.lower() for t in get_sonarr_summary().get("sonarr_titles", [])}
|
||||
for s in sonarr_get(f"series/lookup?term={encoded}")[:limit]:
|
||||
title = s.get("title", "")
|
||||
results.append({
|
||||
"title": title,
|
||||
"year": str(s.get("year", "")),
|
||||
"poster": _poster_url(s.get("images")),
|
||||
"kind": "TV",
|
||||
"target": "sonarr",
|
||||
"held": title.lower() in sonarr_titles,
|
||||
})
|
||||
except Exception:
|
||||
sonarr_ok = False
|
||||
if not results and not radarr_ok and not sonarr_ok:
|
||||
return {"status": "error", "error": "Sonarr and Radarr both unreachable", "results": []}
|
||||
return {"status": "ok", "results": results}
|
||||
|
||||
|
||||
def get_activity_feed(sabnzbd, ombi, limit=25):
|
||||
"""A single chronological feed assembled from what the fetchers return.
|
||||
|
||||
|
|
@ -1572,7 +1583,7 @@ def home():
|
|||
others = [s for s in sessions if s is not hero]
|
||||
|
||||
return render_template(
|
||||
"home.html", page="home",
|
||||
"home.html", page="home", fastext=HOME_FASTEXT,
|
||||
sonarr=sonarr, radarr=radarr, sabnzbd=r["sabnzbd"], tautulli=tautulli,
|
||||
prowlarr=r["prowlarr"], ombi=r["ombi"], unraid=r["unraid"],
|
||||
hero=hero, other_sessions=others,
|
||||
|
|
@ -1615,7 +1626,7 @@ def discover_page():
|
|||
return render_template("discover.html", page="discover",
|
||||
rt_movies=_filter_rt(r["rt_movies"], radarr_titles),
|
||||
rt_tv=_filter_rt(r["rt_tv"], sonarr_titles),
|
||||
q=q, search=ombi_search(q) if q else None)
|
||||
q=q, search=arr_search(q) if q else None)
|
||||
|
||||
|
||||
@app.route("/requests")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue