manga matching and WebApp
This commit is contained in:
+35
-3
@@ -48,6 +48,7 @@ from MangadexVolumeResolver import MangaDexVolumeResolver
|
||||
from MangaBakaWorksResolver import MangaBakaWorksResolver
|
||||
from MALResolver import MALResolver
|
||||
from AniListResolver import AniListResolver
|
||||
from MatchesCache import MatchesCache
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
@@ -170,7 +171,8 @@ class ComicInfoBuilder:
|
||||
volume_resolver: "MangaDexVolumeResolver | None" = None,
|
||||
works_resolver: "MangaBakaWorksResolver | None" = None,
|
||||
mal_resolver: "MALResolver | None" = None,
|
||||
al_resolver: "AniListResolver | None" = None):
|
||||
al_resolver: "AniListResolver | None" = None,
|
||||
matches_cache: "MatchesCache | None" = None):
|
||||
if not manga_title or not str(manga_title).strip():
|
||||
raise ValueError("manga_title must not be empty.")
|
||||
|
||||
@@ -197,6 +199,7 @@ class ComicInfoBuilder:
|
||||
request_timeout=request_timeout)
|
||||
self._al_resolver = al_resolver or AniListResolver(
|
||||
request_timeout=request_timeout)
|
||||
self._matches_cache = matches_cache
|
||||
|
||||
self._metadata: "dict | None" = None
|
||||
self._pages: list[dict] = []
|
||||
@@ -353,14 +356,43 @@ class ComicInfoBuilder:
|
||||
return series
|
||||
|
||||
def _search_best_series(self, title: str):
|
||||
"""Searches for `title` and returns the best matching series entry."""
|
||||
"""
|
||||
Resolves `title` to a MangaBaka series.
|
||||
|
||||
Lookup order:
|
||||
1. matches.json cache (if attached) — uses the stored series ID
|
||||
to fetch the full series, skipping the search step entirely.
|
||||
2. Fresh MangaBaka search — top hit. The match is persisted to
|
||||
matches.json before being returned so it survives a crash.
|
||||
"""
|
||||
if self._matches_cache is not None:
|
||||
cached = self._matches_cache.get(title)
|
||||
if cached and cached.get("mangabakaId"):
|
||||
try:
|
||||
return self._fetch_series_by_id(cached["mangabakaId"])
|
||||
except Exception as exc:
|
||||
print(f"[ComicInfoBuilder] cached id "
|
||||
f"{cached['mangabakaId']} for {title!r} failed "
|
||||
f"({exc}); falling back to fresh search",
|
||||
flush=True)
|
||||
|
||||
url = f"{self.api_base_url}/series/search"
|
||||
resp = self._session.get(
|
||||
url, params={"q": title, "page": 1, "limit": 1},
|
||||
timeout=self.request_timeout)
|
||||
resp.raise_for_status()
|
||||
data = resp.json().get("data") or []
|
||||
return data[0] if data else None
|
||||
series = data[0] if data else None
|
||||
|
||||
if series and self._matches_cache is not None:
|
||||
self._matches_cache.add(
|
||||
title,
|
||||
mangabaka_id=series.get("id"),
|
||||
mangabaka_name=series.get("title") or "",
|
||||
image_url=_pick_cover_url(series.get("cover")),
|
||||
)
|
||||
|
||||
return series
|
||||
|
||||
def _fetch_series_by_id(self, series_id) -> dict:
|
||||
url = f"{self.api_base_url}/series/{series_id}"
|
||||
|
||||
Reference in New Issue
Block a user