feat: add NFO scan after rescan and year caching

- Add nfo_scan_after_rescan config option (default: true)
- Implement year caching in AniworldLoader and EnhancedAniWorldLoader
- Make get_year abstract method in base provider
- Run NFO validation/creation after scheduled rescan completes
- Add _YearDict cache to avoid re-extracting year from HTML
This commit is contained in:
2026-06-05 18:15:41 +02:00
parent 8b21f1243f
commit e74b04c1ee
10 changed files with 839 additions and 35 deletions

View File

@@ -103,6 +103,9 @@ class ConcreteLoader(Loader):
def get_title(self, key: str) -> str:
return f"Title for {key}"
def get_year(self, key: str) -> int | None:
return 2024
def get_season_episode_count(self, slug: str) -> Dict[int, int]:
return {1: 12, 2: 24}

View File

@@ -45,6 +45,9 @@ class ConcreteEnhancedLoader(EnhancedAniWorldLoader):
def get_title(self, key: str) -> str:
return self.GetTitle(key)
def get_year(self, key: str) -> int | None:
return self.GetYear(key)
@pytest.fixture
def enhanced_loader():
@@ -969,6 +972,7 @@ class TestHlsUrlDetection:
def test_voe_hls_pattern_extracts_hls_url(self):
"""HLS_PATTERN should extract HLS URL from VOE embedded player HTML."""
import re
from src.server.providers.streaming.voe import HLS_PATTERN
html_with_hls = """
@@ -984,6 +988,7 @@ class TestHlsUrlDetection:
def test_voe_hls_pattern_returns_none_when_no_hls(self):
"""HLS_PATTERN should return None when no HLS URL in HTML."""
import re
from src.server.providers.streaming.voe import HLS_PATTERN
html_no_hls = """
@@ -997,6 +1002,7 @@ class TestHlsUrlDetection:
def test_hls_url_detection_in_provider_flow(self, enhanced_loader, tmp_path):
"""Provider should detect and handle HLS URLs from VOE extractor."""
import re
from src.server.providers.streaming.voe import HLS_PATTERN
# Simulate VOE returning an HLS URL (base64 encoded .m3u8)

View File

@@ -53,6 +53,9 @@ class MockProvider(Loader):
def get_title(self, key):
return self._title
def get_year(self, key) -> int | None:
return 2024
def get_season_episode_count(self, slug):
return self._season_episodes
@@ -66,6 +69,9 @@ class ConcreteMonitoredWrapper(MonitoredProviderWrapper):
def unsubscribe_download_progress(self, handler):
pass
def get_year(self, key: str) -> int | None:
return None
@pytest.fixture
def mock_provider():

View File

@@ -25,6 +25,7 @@ def _loader() -> AniworldLoader:
loader = AniworldLoader.__new__(AniworldLoader)
loader._KeyHTMLDict = {}
loader._EpisodeHTMLDict = {}
loader._YearDict = {}
loader.ANIWORLD_TO = "https://aniworld.to"
loader.DEFAULT_REQUEST_TIMEOUT = 10
loader.session = MagicMock()