From 45d259bab2449815e53586ff3e5220e03e2f5d1d Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 5 Jun 2026 20:24:24 +0200 Subject: [PATCH] fix(setup): resolve series key from search link field - Fix _resolve_key_via_search to use 'title' instead of 'name' - Extract key from 'link' field URL (e.g., /anime/stream/naruto -> naruto) - Skip folders with unresolved keys instead of crashing with 'Series key cannot be empty' - Update tests to use correct field names (title/link) --- src/server/services/setup_service.py | 13 +++++++++++-- tests/unit/test_setup_service.py | 10 +++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/server/services/setup_service.py b/src/server/services/setup_service.py index bbd1a4c..c0796d5 100644 --- a/src/server/services/setup_service.py +++ b/src/server/services/setup_service.py @@ -93,9 +93,11 @@ class SetupService: results = await series_app.search(title) if len(results) == 1: - result_name = results[0].get('name', '').lower() + result_name = results[0].get('title', '').lower() if result_name == title.lower(): - return results[0].get('key', '') + link = results[0].get('link', '') + if link and '/anime/stream/' in link: + return link.split('/anime/stream/')[-1].split('/')[0] except Exception as e: logger.warning( "Provider search failed for folder", @@ -236,6 +238,13 @@ class SetupService: # Resolve key via provider search resolved_key = await cls._resolve_key_via_search(title) + if not resolved_key: + logger.warning( + "Could not resolve series key for folder, skipping: %s", + folder_name + ) + continue + # Check filesystem properties props = cls._get_series_properties(folder) diff --git a/tests/unit/test_setup_service.py b/tests/unit/test_setup_service.py index 40850fe..9a81488 100644 --- a/tests/unit/test_setup_service.py +++ b/tests/unit/test_setup_service.py @@ -67,7 +67,7 @@ class TestResolveKeyViaSearch: """Search returns 1 result with same name → returns key.""" mock_series_app = AsyncMock() mock_series_app.search.return_value = [ - {'key': 'attack-on-titan', 'name': 'Attack on Titan'} + {'title': 'Attack on Titan', 'link': '/anime/stream/attack-on-titan'} ] with patch( @@ -97,8 +97,8 @@ class TestResolveKeyViaSearch: """Search returns >1 results → returns empty string.""" mock_series_app = AsyncMock() mock_series_app.search.return_value = [ - {'key': 'attack-on-titan', 'name': 'Attack on Titan'}, - {'key': 'attack-on-titan-ova', 'name': 'Attack on Titan OVA'} + {'title': 'Attack on Titan', 'link': '/anime/stream/attack-on-titan'}, + {'title': 'Attack on Titan OVA', 'link': '/anime/stream/attack-on-titan-ova'} ] with patch( @@ -114,7 +114,7 @@ class TestResolveKeyViaSearch: """Search returns 1 result but name differs (case-insensitive) → returns empty string.""" mock_series_app = AsyncMock() mock_series_app.search.return_value = [ - {'key': 'attack-on-titan', 'name': 'Attack on Titan'} + {'title': 'Attack on Titan', 'link': '/anime/stream/attack-on-titan'} ] with patch( @@ -243,7 +243,7 @@ class TestSetupServiceRun: mock_series_app = AsyncMock() mock_series_app.search.return_value = [ - {'key': 'attack-on-titan', 'name': 'Attack on Titan'} + {'title': 'Attack on Titan', 'link': '/anime/stream/attack-on-titan'} ] mock_db = AsyncMock()