Speed up aniworld season and episode loading
This commit is contained in:
@@ -417,15 +417,16 @@ def _extract_latest_episodes(soup: BeautifulSoupT) -> List[LatestEpisode]:
|
||||
return episodes
|
||||
|
||||
|
||||
def scrape_anime_detail(anime_identifier: str, max_seasons: Optional[int] = None) -> List[SeasonInfo]:
|
||||
def scrape_anime_detail(
|
||||
anime_identifier: str,
|
||||
max_seasons: Optional[int] = None,
|
||||
*,
|
||||
load_episodes: bool = True,
|
||||
) -> List[SeasonInfo]:
|
||||
_ensure_requests()
|
||||
anime_url = _series_root_url(_absolute_url(anime_identifier))
|
||||
_log_url(anime_url, kind="ANIME")
|
||||
session = get_requests_session("aniworld", headers=HEADERS)
|
||||
try:
|
||||
_get_soup(_get_base_url(), session=session)
|
||||
except Exception:
|
||||
pass
|
||||
soup = _get_soup(anime_url, session=session)
|
||||
|
||||
base_anime_url = _series_root_url(_extract_canonical_url(soup, anime_url))
|
||||
@@ -445,8 +446,10 @@ def scrape_anime_detail(anime_identifier: str, max_seasons: Optional[int] = None
|
||||
|
||||
seasons: List[SeasonInfo] = []
|
||||
for number, url in season_links:
|
||||
season_soup = _get_soup(url, session=session)
|
||||
episodes = _extract_episodes(season_soup)
|
||||
episodes: List[EpisodeInfo] = []
|
||||
if load_episodes:
|
||||
season_soup = _get_soup(url, session=session)
|
||||
episodes = _extract_episodes(season_soup)
|
||||
seasons.append(SeasonInfo(number=number, url=url, episodes=episodes))
|
||||
seasons.sort(key=lambda s: s.number)
|
||||
return seasons
|
||||
@@ -598,6 +601,7 @@ class AniworldPlugin(BasisPlugin):
|
||||
def __init__(self) -> None:
|
||||
self._anime_results: Dict[str, SeriesResult] = {}
|
||||
self._season_cache: Dict[str, List[SeasonInfo]] = {}
|
||||
self._season_links_cache: Dict[str, List[SeasonInfo]] = {}
|
||||
self._episode_label_cache: Dict[Tuple[str, str], Dict[str, EpisodeInfo]] = {}
|
||||
self._popular_cache: Optional[List[SeriesResult]] = None
|
||||
self._genre_cache: Optional[Dict[str, List[SeriesResult]]] = None
|
||||
@@ -801,19 +805,66 @@ class AniworldPlugin(BasisPlugin):
|
||||
cache_key = (title, season_label)
|
||||
self._episode_label_cache[cache_key] = {self._episode_label(info): info for info in season_info.episodes}
|
||||
|
||||
def remember_series_url(self, title: str, series_url: str) -> None:
|
||||
title = (title or "").strip()
|
||||
series_url = (series_url or "").strip()
|
||||
if not title or not series_url:
|
||||
return
|
||||
self._anime_results[title] = SeriesResult(title=title, description="", url=series_url)
|
||||
|
||||
def series_url_for_title(self, title: str) -> str:
|
||||
title = (title or "").strip()
|
||||
if not title:
|
||||
return ""
|
||||
direct = self._anime_results.get(title)
|
||||
if direct and direct.url:
|
||||
return direct.url
|
||||
wanted = title.casefold().strip()
|
||||
for candidate in self._anime_results.values():
|
||||
if candidate.title and candidate.title.casefold().strip() == wanted and candidate.url:
|
||||
return candidate.url
|
||||
return ""
|
||||
|
||||
def _ensure_season_links(self, title: str) -> List[SeasonInfo]:
|
||||
cached = self._season_links_cache.get(title)
|
||||
if cached is not None:
|
||||
return list(cached)
|
||||
anime = self._find_series_by_title(title)
|
||||
if not anime:
|
||||
return []
|
||||
seasons = scrape_anime_detail(anime.url, load_episodes=False)
|
||||
self._season_links_cache[title] = list(seasons)
|
||||
return list(seasons)
|
||||
|
||||
def _ensure_season_episodes(self, title: str, season_number: int) -> Optional[SeasonInfo]:
|
||||
seasons = self._season_cache.get(title) or []
|
||||
for season in seasons:
|
||||
if season.number == season_number and season.episodes:
|
||||
return season
|
||||
links = self._ensure_season_links(title)
|
||||
target = next((season for season in links if season.number == season_number), None)
|
||||
if not target:
|
||||
return None
|
||||
season_soup = _get_soup(target.url, session=get_requests_session("aniworld", headers=HEADERS))
|
||||
season_info = SeasonInfo(number=target.number, url=target.url, episodes=_extract_episodes(season_soup))
|
||||
updated = [season for season in seasons if season.number != season_number]
|
||||
updated.append(season_info)
|
||||
updated.sort(key=lambda item: item.number)
|
||||
self._season_cache[title] = updated
|
||||
return season_info
|
||||
|
||||
def _lookup_episode(self, title: str, season_label: str, episode_label: str) -> Optional[EpisodeInfo]:
|
||||
cache_key = (title, season_label)
|
||||
cached = self._episode_label_cache.get(cache_key)
|
||||
if cached:
|
||||
return cached.get(episode_label)
|
||||
seasons = self._ensure_seasons(title)
|
||||
number = self._parse_season_number(season_label)
|
||||
if number is None:
|
||||
return None
|
||||
for season_info in seasons:
|
||||
if season_info.number == number:
|
||||
self._cache_episode_labels(title, season_label, season_info)
|
||||
return self._episode_label_cache.get(cache_key, {}).get(episode_label)
|
||||
season_info = self._ensure_season_episodes(title, number)
|
||||
if season_info:
|
||||
self._cache_episode_labels(title, season_label, season_info)
|
||||
return self._episode_label_cache.get(cache_key, {}).get(episode_label)
|
||||
return None
|
||||
|
||||
async def search_titles(self, query: str) -> List[str]:
|
||||
@@ -821,6 +872,7 @@ class AniworldPlugin(BasisPlugin):
|
||||
if not query:
|
||||
self._anime_results.clear()
|
||||
self._season_cache.clear()
|
||||
self._season_links_cache.clear()
|
||||
self._episode_label_cache.clear()
|
||||
self._popular_cache = None
|
||||
return []
|
||||
@@ -835,33 +887,30 @@ class AniworldPlugin(BasisPlugin):
|
||||
raise RuntimeError(f"AniWorld-Suche fehlgeschlagen: {exc}") from exc
|
||||
self._anime_results = {result.title: result for result in results}
|
||||
self._season_cache.clear()
|
||||
self._season_links_cache.clear()
|
||||
self._episode_label_cache.clear()
|
||||
return [result.title for result in results]
|
||||
|
||||
def _ensure_seasons(self, title: str) -> List[SeasonInfo]:
|
||||
if title in self._season_cache:
|
||||
return self._season_cache[title]
|
||||
anime = self._find_series_by_title(title)
|
||||
if not anime:
|
||||
return []
|
||||
seasons = scrape_anime_detail(anime.url)
|
||||
seasons = self._ensure_season_links(title)
|
||||
self._season_cache[title] = list(seasons)
|
||||
return list(seasons)
|
||||
|
||||
def seasons_for(self, title: str) -> List[str]:
|
||||
seasons = self._ensure_seasons(title)
|
||||
return [self._season_label(season.number) for season in seasons if season.episodes]
|
||||
return [self._season_label(season.number) for season in seasons]
|
||||
|
||||
def episodes_for(self, title: str, season: str) -> List[str]:
|
||||
seasons = self._ensure_seasons(title)
|
||||
number = self._parse_season_number(season)
|
||||
if number is None:
|
||||
return []
|
||||
for season_info in seasons:
|
||||
if season_info.number == number:
|
||||
labels = [self._episode_label(info) for info in season_info.episodes]
|
||||
self._cache_episode_labels(title, season, season_info)
|
||||
return labels
|
||||
season_info = self._ensure_season_episodes(title, number)
|
||||
if season_info:
|
||||
labels = [self._episode_label(info) for info in season_info.episodes]
|
||||
self._cache_episode_labels(title, season, season_info)
|
||||
return labels
|
||||
return []
|
||||
|
||||
def stream_link_for(self, title: str, season: str, episode: str) -> Optional[str]:
|
||||
|
||||
Reference in New Issue
Block a user