Fix ABB magnet parsing (#623)

This commit is contained in:
Alex
2026-02-16 16:58:56 +00:00
committed by GitHub
parent 6c351f4bf3
commit 8ff2d776ae
5 changed files with 70 additions and 1 deletions
+1
View File
@@ -76,6 +76,7 @@ class DownloadTask:
size: Optional[str] = None
preview: Optional[str] = None
content_type: Optional[str] = None # "book (fiction)", "audiobook", "magazine", etc.
source_url: Optional[str] = None # Original release URL used by source-specific handlers
# Series info (for library naming templates)
series_name: Optional[str] = None
+11
View File
@@ -188,6 +188,16 @@ def queue_release(
year = release_data.get('year') or extra.get('year')
preview = release_data.get('preview') or extra.get('preview')
content_type = release_data.get('content_type') or extra.get('content_type')
source_url_raw = (
release_data.get('download_url')
or release_data.get('source_url')
or release_data.get('info_url')
or extra.get('detail_url')
or extra.get('source_url')
)
source_url = source_url_raw.strip() if isinstance(source_url_raw, str) else None
if source_url == "":
source_url = None
# Get series info for library naming templates
series_name = release_data.get('series_name') or extra.get('series_name')
@@ -220,6 +230,7 @@ def queue_release(
size=release_data.get('size'),
preview=preview,
content_type=content_type,
source_url=source_url,
series_name=series_name,
series_position=series_position,
subtitle=subtitle,
@@ -19,6 +19,19 @@ logger = setup_logger(__name__)
class AudiobookBayHandler(ExternalClientHandler):
"""Handler for AudiobookBay downloads via configured torrent client."""
@staticmethod
def _resolve_detail_url(task: DownloadTask) -> Optional[str]:
"""Resolve ABB detail URL from queued task metadata."""
source_url = (task.source_url or "").strip()
if source_url:
return source_url
# Backward-compat: older tests and some legacy flows used task_id as URL.
task_id = (task.task_id or "").strip()
if task_id.startswith(("http://", "https://")):
return task_id
return None
def _get_client(self, protocol: str) -> Optional[DownloadClient]:
"""Compatibility shim so module-level patching still works in tests."""
return get_client(protocol)
@@ -33,7 +46,12 @@ class AudiobookBayHandler(ExternalClientHandler):
status_callback: Callable[[str, Optional[str]], None],
) -> Optional[DownloadRequest]:
"""Resolve ABB detail page into a magnet-link download request."""
detail_url = task.task_id
detail_url = self._resolve_detail_url(task)
if not detail_url:
status_callback("error", "Missing AudiobookBay details URL")
logger.warning(f"Missing details URL for AudiobookBay task: {task.task_id}")
return None
hostname = normalize_hostname(config.get("ABB_HOSTNAME", ""))
if not hostname:
hostname = normalize_hostname(urlparse(detail_url).hostname)
+37
View File
@@ -82,6 +82,43 @@ class TestAudiobookBayHandlerDownload:
mock_poll.assert_called_once()
assert "resolving" in recorder.statuses
@patch('shelfmark.release_sources.audiobookbay.handler.scraper.extract_magnet_link')
@patch('shelfmark.release_sources.audiobookbay.handler.get_client')
def test_download_uses_source_url_for_hashed_task_id(self, mock_get_client, mock_extract_magnet):
"""Test release queue flow where task_id is source hash and source_url has detail URL."""
mock_extract_magnet.return_value = "magnet:?xt=urn:btih:abc123"
mock_client = MagicMock()
mock_client.name = "qbittorrent"
mock_client.find_existing.return_value = None
mock_client.add_download.return_value = "download_id_123"
mock_get_client.return_value = mock_client
handler = AudiobookBayHandler()
task = DownloadTask(
task_id="35f56a3e5734bfa69c3169ee8e605a60",
source="audiobookbay",
title="Test Book",
content_type="audiobook",
source_url="https://audiobookbay.lu/abss/test-book/",
)
cancel_flag = Event()
recorder = ProgressRecorder()
with patch.object(AudiobookBayHandler, "_poll_and_complete", return_value=None):
result = handler.download(
task=task,
cancel_flag=cancel_flag,
progress_callback=recorder.progress_callback,
status_callback=recorder.status_callback,
)
assert result is None
mock_extract_magnet.assert_called_once_with(
"https://audiobookbay.lu/abss/test-book/",
"audiobookbay.lu"
)
assert "resolving" in recorder.statuses
@patch('shelfmark.release_sources.audiobookbay.handler.scraper.extract_magnet_link')
@patch('shelfmark.release_sources.audiobookbay.handler.get_client')
def test_download_existing_complete(self, mock_get_client, mock_extract_magnet):
@@ -74,6 +74,7 @@ def test_queue_release_uses_user_specific_books_output_mode(monkeypatch):
"content_type": "book (fiction)",
"format": "epub",
"size": "1 MB",
"download_url": "https://audiobookbay.lu/abss/release-title/",
}
success, error = orchestrator.queue_release(release_data, user_id=42, username="alice")
@@ -83,6 +84,7 @@ def test_queue_release_uses_user_specific_books_output_mode(monkeypatch):
task = captured["task"]
assert task.output_mode == "email"
assert task.output_args == {"to": "alice@example.com"}
assert task.source_url == "https://audiobookbay.lu/abss/release-title/"
assert ("BOOKS_OUTPUT_MODE", 42) in config_calls