fix: split clients, add surface error and follow redirects on downloads

This commit is contained in:
2025-12-14 09:49:03 +01:00
parent 839394343e
commit cef5e40347

View File

@@ -29,8 +29,11 @@ class DownloadManager:
self.cache_dir = cache_dir self.cache_dir = cache_dir
self.cache_dir.mkdir(parents=True, exist_ok=True) self.cache_dir.mkdir(parents=True, exist_ok=True)
self.chunk_size = chunk_size self.chunk_size = chunk_size
self._http_client = httpx.Client( self._http_client = httpx.Client(auth=auth, timeout=30.0, follow_redirects=True)
auth=auth, timeout=30.0, follow_redirects=False) self._download_client = httpx.Client(
timeout=httpx.Timeout(connect=30.0, read=None, write=30.0, pool=30.0),
follow_redirects=True,
)
def get_or_download(self, asin: str, notify: StatusCallback | None = None) -> Path | None: def get_or_download(self, asin: str, notify: StatusCallback | None = None) -> Path | None:
"""Get local path of AAX file, downloading if missing.""" """Get local path of AAX file, downloading if missing."""
@@ -46,7 +49,7 @@ class DownloadManager:
if notify: if notify:
notify(f"Downloading to {local_path.name}...") notify(f"Downloading to {local_path.name}...")
dl_link = self._get_download_link(asin) dl_link = self._get_download_link(asin, notify=notify)
if not dl_link: if not dl_link:
if notify: if notify:
notify("Failed to get download link") notify("Failed to get download link")
@@ -103,9 +106,13 @@ class DownloadManager:
except Exception: except Exception:
return None return None
def _get_download_link(self, asin: str, codec: str = DEFAULT_CODEC) -> str | None: def _get_download_link(
self, asin: str, codec: str = DEFAULT_CODEC, notify: StatusCallback | None = None
) -> str | None:
"""Get download link for book.""" """Get download link for book."""
if self.auth.adp_token is None: if self.auth.adp_token is None:
if notify:
notify("Missing ADP token (not authenticated?)")
return None return None
try: try:
@@ -123,12 +130,18 @@ class DownloadManager:
link = response.headers.get("Location") link = response.headers.get("Location")
if not link: if not link:
return None link = str(response.url)
tld = self.auth.locale.domain tld = self.auth.locale.domain
return link.replace("cds.audible.com", f"cds.audible.{tld}") return link.replace("cds.audible.com", f"cds.audible.{tld}")
except Exception: except httpx.HTTPError as exc:
if notify:
notify(f"Download-link request failed: {exc!s}")
return None
except Exception as exc:
if notify:
notify(f"Download-link error: {exc!s}")
return None return None
def _download_file( def _download_file(
@@ -136,7 +149,7 @@ class DownloadManager:
) -> Path | None: ) -> Path | None:
"""Download file from URL to destination.""" """Download file from URL to destination."""
try: try:
with self._http_client.stream("GET", url) as response: with self._download_client.stream("GET", url) as response:
response.raise_for_status() response.raise_for_status()
total_size = int(response.headers.get("content-length", 0)) total_size = int(response.headers.get("content-length", 0))
downloaded = 0 downloaded = 0
@@ -152,10 +165,39 @@ class DownloadManager:
) )
return dest_path return dest_path
except Exception: except httpx.HTTPStatusError as exc:
if notify:
notify(
f"Download HTTP error: {exc.response.status_code} {exc.response.reason_phrase}"
)
try:
if dest_path.exists() and dest_path.stat().st_size < MIN_FILE_SIZE:
dest_path.unlink()
except OSError:
pass
return None
except httpx.HTTPError as exc:
if notify:
notify(f"Download network error: {exc!s}")
try:
if dest_path.exists() and dest_path.stat().st_size < MIN_FILE_SIZE:
dest_path.unlink()
except OSError:
pass
return None
except Exception as exc:
if notify:
notify(f"Download error: {exc!s}")
try:
if dest_path.exists() and dest_path.stat().st_size < MIN_FILE_SIZE:
dest_path.unlink()
except OSError:
pass
return None return None
def close(self) -> None: def close(self) -> None:
"""Close the HTTP client and release resources.""" """Close the HTTP clients and release resources."""
if hasattr(self, "_http_client"): if hasattr(self, "_http_client"):
self._http_client.close() self._http_client.close()
if hasattr(self, "_download_client"):
self._download_client.close()