feat(NFO): add TMDB search fallback with alt_titles support
- New _search_with_fallback() method tries multiple strategies: 1. Primary query with year filter (de-DE locale) 2. Alternative titles with ja-JP / en-US locales 3. English search (en-US) 4. Search without year constraint 5. Punctuation-normalized query - create_nfo() accepts new alt_titles param for Japanese/title fallback - Better match rate for anime with non-English titles Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -117,6 +117,8 @@ class TestStart:
|
||||
call_kwargs = mock_sched.add_job.call_args
|
||||
assert call_kwargs[1]["id"] == _JOB_ID
|
||||
assert isinstance(call_kwargs[1]["trigger"], CronTrigger)
|
||||
assert call_kwargs[1]["misfire_grace_time"] == 3600
|
||||
assert call_kwargs[1]["coalesce"] is True
|
||||
mock_sched.start.assert_called_once()
|
||||
assert scheduler_service._is_running is True
|
||||
|
||||
@@ -485,3 +487,75 @@ class TestSingletonHelpers:
|
||||
svc = get_scheduler_service()
|
||||
assert svc is not None # fresh instance
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 12.12 Persistent job store — SQLAlchemyJobStore passed to AsyncIOScheduler
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestPersistentJobStore:
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_creates_scheduler_with_sqlalchemy_jobstore(
|
||||
self, scheduler_service, mock_config_service
|
||||
):
|
||||
with patch(
|
||||
"src.server.services.scheduler_service.AsyncIOScheduler"
|
||||
) as MockScheduler:
|
||||
mock_sched = MagicMock()
|
||||
mock_sched.running = False
|
||||
MockScheduler.return_value = mock_sched
|
||||
|
||||
await scheduler_service.start()
|
||||
|
||||
MockScheduler.assert_called_once()
|
||||
call_kwargs = MockScheduler.call_args
|
||||
jobstores = call_kwargs[1]["jobstores"]
|
||||
assert "default" in jobstores
|
||||
# Verify it's a SQLAlchemyJobStore (class check via module name)
|
||||
assert "sqlalchemy" in type(jobstores["default"]).__module__
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_job_options_include_misfire_grace_and_coalesce(
|
||||
self, scheduler_service, mock_config_service
|
||||
):
|
||||
with patch(
|
||||
"src.server.services.scheduler_service.AsyncIOScheduler"
|
||||
) as MockScheduler:
|
||||
mock_sched = MagicMock()
|
||||
mock_sched.running = False
|
||||
MockScheduler.return_value = mock_sched
|
||||
|
||||
await scheduler_service.start()
|
||||
|
||||
call_kwargs = mock_sched.add_job.call_args
|
||||
assert call_kwargs[1]["misfire_grace_time"] == 3600
|
||||
assert call_kwargs[1]["coalesce"] is True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 12.13 Startup recovery — next run logged after start()
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestStartupRecovery:
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_logs_next_run_time(
|
||||
self, scheduler_service, mock_config_service
|
||||
):
|
||||
with patch(
|
||||
"src.server.services.scheduler_service.AsyncIOScheduler"
|
||||
) as MockScheduler:
|
||||
mock_job = MagicMock()
|
||||
next_run_dt = datetime(2026, 5, 25, 3, 0, tzinfo=timezone.utc)
|
||||
mock_job.next_run_time = next_run_dt
|
||||
mock_sched = MagicMock()
|
||||
mock_sched.running = False
|
||||
mock_sched.get_job.return_value = mock_job
|
||||
MockScheduler.return_value = mock_sched
|
||||
|
||||
with patch(
|
||||
"src.server.services.scheduler_service.logger"
|
||||
) as mock_logger:
|
||||
await scheduler_service.start()
|
||||
# Check that next_run was logged
|
||||
info_calls = [str(c) for c in mock_logger.info.call_args_list]
|
||||
assert any("next_run" in c for c in info_calls)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user