Preserve completed episodes from failed batches

This commit is contained in:
Dymas
2026-08-18 08:43:30 +02:00
parent 8e95ffc79b
commit d663318f27
6 changed files with 155 additions and 10 deletions
+67
View File
@@ -880,6 +880,36 @@ class QueueApiTests(unittest.TestCase):
)
self.assertTrue(Path(moved[0]).exists())
def test_tv_finalizer_can_move_one_finished_episode_without_removing_staging(self):
with tempfile.TemporaryDirectory() as temp_root:
job = APP.app_support.build_job(
{
"query": "Batch Show",
"title": "Batch Show",
"anime_name": "Batch Show",
"media_type": "tv",
"mode": "sub",
"quality": "best",
"episodes": "1-2",
"download_dir": temp_root,
"season": "1",
},
{"mode": "sub", "quality": "best", "download_dir": temp_root},
)
staging_dir = APP.app_support.job_staging_dir(job)
staging_dir.mkdir(parents=True, exist_ok=True)
first = staging_dir / "Batch Show - S01E01.mp4"
second = staging_dir / "Batch Show - S01E02.mp4"
first.write_bytes(b"ep1")
second.write_bytes(b"ep2")
moved = APP.app_support.finalize_library_files(job, episode=1, cleanup_staging=False)
self.assertEqual(moved, [f"{temp_root}/tv/Batch Show/Season 01/Batch Show - S01E01.mp4"])
self.assertTrue(staging_dir.exists())
self.assertFalse(first.exists())
self.assertTrue(second.exists())
def test_shutdown_wait_cancels_active_process_for_deterministic_teardown(self):
queue = object.__new__(APP.DownloadQueue)
queue.lock = threading.RLock()
@@ -1033,6 +1063,43 @@ class DownloadQueueWorkerFailureTests(unittest.TestCase):
self.assertEqual(send_webhook.call_args.args[2]["category"], "finished")
self.assertEqual(send_webhook.call_args.args[2]["moved_files"], ["/tmp/example/Queue Show - S01E01.mp4"])
def test_failed_batch_preserves_episode_moved_after_progress_done(self):
with tempfile.TemporaryDirectory() as temp_root:
queue = APP.DownloadQueue(
lambda: {
"mode": "sub",
"quality": "best",
"download_dir": temp_root,
},
start_worker=False,
)
job = queue.add({"query": "Batch Show", "title": "Batch Show", "season": "1", "episodes": "1-2"})
staging_dir = queue_jobs.job_staging_dir(job)
staging_dir.mkdir(parents=True, exist_ok=True)
staged_episode = staging_dir / "Batch Show - S01E01.mp4"
staged_episode.write_bytes(b"ep1")
class FakeProc:
pid = 4321
stdout = [
'KAIZOKU_PROGRESS {"episode":1,"episode_index":1,"episode_total":2,"message":"Episode 1 saved.","percent":100,"phase":"done"}\n',
"Episode 2 failed on all providers: boom\n",
]
def wait(self):
return 1
with mock.patch.object(queue_jobs.subprocess, "Popen", return_value=FakeProc()):
queue._run_job(job)
stored = queue._find(job["id"])
final_episode = Path(temp_root) / "tv" / "Batch Show" / "Season 01" / "Batch Show - S01E01.mp4"
self.assertEqual(stored["status"], "failed")
self.assertTrue(final_episode.exists())
self.assertFalse(staged_episode.exists())
self.assertFalse(staging_dir.exists())
self.assertIn(f"Saved: {final_episode}", stored["log"])
def test_successful_detached_download_logs_sync_skipped(self):
queue = APP.DownloadQueue(
lambda: {