Nightly: refactor readability, progress callbacks, and resource handling
This commit is contained in:
@@ -19,7 +19,7 @@ import hashlib
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional
|
||||
from urllib.parse import urlencode, urljoin
|
||||
|
||||
try: # pragma: no cover - optional dependency
|
||||
@@ -78,6 +78,16 @@ HEADERS = {
|
||||
"Accept-Language": "de-DE,de;q=0.9,en;q=0.8",
|
||||
"Connection": "keep-alive",
|
||||
}
|
||||
ProgressCallback = Optional[Callable[[str, Optional[int]], Any]]
|
||||
|
||||
|
||||
def _emit_progress(callback: ProgressCallback, message: str, percent: Optional[int] = None) -> None:
|
||||
if not callable(callback):
|
||||
return
|
||||
try:
|
||||
callback(str(message or ""), None if percent is None else int(percent))
|
||||
except Exception:
|
||||
return
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -584,15 +594,25 @@ class TopstreamfilmPlugin(BasisPlugin):
|
||||
session = self._get_session()
|
||||
self._log_url(url, kind="VISIT")
|
||||
self._notify_url(url)
|
||||
response = None
|
||||
try:
|
||||
response = session.get(url, timeout=DEFAULT_TIMEOUT)
|
||||
response.raise_for_status()
|
||||
except Exception as exc:
|
||||
self._log_error(f"GET {url} failed: {exc}")
|
||||
raise
|
||||
self._log_url(response.url, kind="OK")
|
||||
self._log_response_html(response.url, response.text)
|
||||
return BeautifulSoup(response.text, "html.parser")
|
||||
try:
|
||||
final_url = (response.url or url) if response is not None else url
|
||||
body = (response.text or "") if response is not None else ""
|
||||
self._log_url(final_url, kind="OK")
|
||||
self._log_response_html(final_url, body)
|
||||
return BeautifulSoup(body, "html.parser")
|
||||
finally:
|
||||
if response is not None:
|
||||
try:
|
||||
response.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _get_detail_soup(self, title: str) -> Optional[BeautifulSoupT]:
|
||||
title = (title or "").strip()
|
||||
@@ -814,7 +834,7 @@ class TopstreamfilmPlugin(BasisPlugin):
|
||||
# Sonst: Serie via Streams-Accordion parsen (falls vorhanden).
|
||||
self._parse_stream_accordion(soup, title=title)
|
||||
|
||||
async def search_titles(self, query: str) -> List[str]:
|
||||
async def search_titles(self, query: str, progress_callback: ProgressCallback = None) -> List[str]:
|
||||
"""Sucht Titel ueber eine HTML-Suche.
|
||||
|
||||
Erwartetes HTML (Snippet):
|
||||
@@ -827,6 +847,7 @@ class TopstreamfilmPlugin(BasisPlugin):
|
||||
query = (query or "").strip()
|
||||
if not query:
|
||||
return []
|
||||
_emit_progress(progress_callback, "Topstreamfilm Suche", 15)
|
||||
|
||||
session = self._get_session()
|
||||
url = self._get_base_url() + "/"
|
||||
@@ -834,6 +855,7 @@ class TopstreamfilmPlugin(BasisPlugin):
|
||||
request_url = f"{url}?{urlencode(params)}"
|
||||
self._log_url(request_url, kind="GET")
|
||||
self._notify_url(request_url)
|
||||
response = None
|
||||
try:
|
||||
response = session.get(
|
||||
url,
|
||||
@@ -844,15 +866,28 @@ class TopstreamfilmPlugin(BasisPlugin):
|
||||
except Exception as exc:
|
||||
self._log_error(f"GET {request_url} failed: {exc}")
|
||||
raise
|
||||
self._log_url(response.url, kind="OK")
|
||||
self._log_response_html(response.url, response.text)
|
||||
try:
|
||||
final_url = (response.url or request_url) if response is not None else request_url
|
||||
body = (response.text or "") if response is not None else ""
|
||||
self._log_url(final_url, kind="OK")
|
||||
self._log_response_html(final_url, body)
|
||||
|
||||
if BeautifulSoup is None:
|
||||
return []
|
||||
soup = BeautifulSoup(response.text, "html.parser")
|
||||
if BeautifulSoup is None:
|
||||
return []
|
||||
soup = BeautifulSoup(body, "html.parser")
|
||||
finally:
|
||||
if response is not None:
|
||||
try:
|
||||
response.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
hits: List[SearchHit] = []
|
||||
for item in soup.select("li.TPostMv"):
|
||||
items = soup.select("li.TPostMv")
|
||||
total_items = max(1, len(items))
|
||||
for idx, item in enumerate(items, start=1):
|
||||
if idx == 1 or idx % 20 == 0:
|
||||
_emit_progress(progress_callback, f"Treffer pruefen {idx}/{total_items}", 55)
|
||||
anchor = item.select_one("a[href]")
|
||||
if not anchor:
|
||||
continue
|
||||
@@ -885,6 +920,7 @@ class TopstreamfilmPlugin(BasisPlugin):
|
||||
self._title_to_url[hit.title] = hit.url
|
||||
titles.append(hit.title)
|
||||
self._save_title_url_cache()
|
||||
_emit_progress(progress_callback, f"Fertig: {len(titles)} Treffer", 95)
|
||||
return titles
|
||||
|
||||
def genres(self) -> List[str]:
|
||||
|
||||
Reference in New Issue
Block a user