feat: add category-based grouping for Sonarr series with anime and K-drama tag detection
Add tag fetching from Sonarr API and category_for() function to classify series based on normalized tags (anime, kdrama, standard). Parse tag labels/names into normalized strings removing non-alphanumeric characters for matching. Add category and category_label fields to series groups. Update index route to build series_categories list grouping series by category key (anime/Anime, kdrama/K-Dramen, standard/Standard) and pass
This commit is contained in:
@@ -372,7 +372,22 @@ def sonarr_groups():
|
||||
groups = []
|
||||
queue = api_get(SONARR_URL, SONARR_API_KEY, "queue?includeUnknownSeriesItems=true")
|
||||
queued_episodes = {item.get("episodeId") for item in queue.get("records", [])}
|
||||
tags = api_get(SONARR_URL, SONARR_API_KEY, "tag")
|
||||
tag_names = {str(tag.get("id")): str(tag.get("label") or tag.get("name") or "").strip().casefold() for tag in tags}
|
||||
|
||||
def category_for(series):
|
||||
normalized_tags = {
|
||||
re.sub(r"[^a-z0-9]+", "", tag_names.get(str(tag_id), ""))
|
||||
for tag_id in (series.get("tags") or [])
|
||||
}
|
||||
if "anime" in normalized_tags:
|
||||
return "anime", "Anime"
|
||||
if "kdrama" in normalized_tags:
|
||||
return "kdrama", "K-Dramen"
|
||||
return "standard", "Standard"
|
||||
|
||||
for series in api_get(SONARR_URL, SONARR_API_KEY, "series"):
|
||||
category_key, category_label = category_for(series)
|
||||
episodes = api_get(SONARR_URL, SONARR_API_KEY, f"episode?seriesId={series['id']}&includeSeries=false")
|
||||
files = {f["id"]: f for f in api_get(SONARR_URL, SONARR_API_KEY, f"episodefile?seriesId={series['id']}")}
|
||||
items = []
|
||||
@@ -381,7 +396,8 @@ def sonarr_groups():
|
||||
if ef: ef = dict(ef); ef["path"] = str(Path(series.get("path") or "") / ef.get("relativePath", ""))
|
||||
label = f"S{episode.get('seasonNumber', 0):02d}E{episode.get('episodeNumber', 0):02d} · {episode.get('title') or '—'}"
|
||||
items.append(media_row(label, None, ef, SONARR_MEDIA_PATH, LOCAL_SERIES_PATH, {"episode":True, "season":episode.get("seasonNumber", 0), "downloading": episode.get("id") in queued_episodes}))
|
||||
groups.append({"title":series.get("title", "—"), "year":series.get("year"), "episodes":items})
|
||||
groups.append({"title":series.get("title", "—"), "year":series.get("year"), "episodes":items,
|
||||
"category":category_key, "category_label":category_label})
|
||||
return sorted(groups, key=lambda x: x["title"].lower())
|
||||
|
||||
def start_scan(source, force=False):
|
||||
@@ -425,6 +441,10 @@ def index():
|
||||
episodes = [episode for episode in group["episodes"] if is_german_review_candidate(episode) and not has_german_track(episode)]
|
||||
if episodes:
|
||||
missing_german_series.append({**group, "episodes": episodes})
|
||||
series_categories = [
|
||||
{"key": key, "label": label, "series": [group for group in series if group["category"] == key]}
|
||||
for key, label in (("anime", "Anime"), ("kdrama", "K-Dramen"), ("standard", "Standard"))
|
||||
]
|
||||
dashboard_stats = {
|
||||
"movie_total": len(rows),
|
||||
"movie_files": sum(1 for row in rows if not row.get("missing")),
|
||||
@@ -435,7 +455,8 @@ def index():
|
||||
"episode_files": sum(1 for group in series for row in group["episodes"] if not row.get("missing")),
|
||||
"episode_missing": sum(1 for group in series for row in group["episodes"] if row.get("missing") and not row.get("downloading")),
|
||||
}
|
||||
return render_template("index.html", rows=rows, series=series, missing_german_movies=missing_german_movies,
|
||||
return render_template("index.html", rows=rows, series=series, series_categories=series_categories,
|
||||
missing_german_movies=missing_german_movies,
|
||||
missing_german_series=missing_german_series, error=error,
|
||||
dashboard_stats=dashboard_stats,
|
||||
sonarr_enabled=bool(SONARR_URL and SONARR_API_KEY), sab_enabled=bool(SAB_URL and SAB_API_KEY),
|
||||
|
||||
Reference in New Issue
Block a user