Handle invalid ffprobe JSON during stage1

This commit is contained in:
kim
2026-03-30 18:22:56 +08:00
parent dff1cb07a4
commit 834577dafc
2 changed files with 106 additions and 1 deletions
+23
View File
@@ -435,6 +435,26 @@ def _execute_stage1_scan(config: ScanConfig) -> list[ReportRow]:
payload = _parse_probe_payload(probe_result.stdout_text)
if probe_result.stdout_text and payload is None:
classification = classify_stage1_result(
exit_code=probe_result.exit_code,
stderr_text=probe_result.stderr_text,
probe_payload=None,
extension=stored_file.extension,
high_risk_extensions=config.high_risk_extensions,
)
if classification.reason_code in {"ffprobe_exit_nonzero", "hard_error_keyword"}:
final_status = classification.status
store.record_stage1_status(
stored_file.file_id,
stage1_status=classification.status,
final_status=final_status,
reason_code=classification.reason_code,
)
reasons[stored_file.file_id] = classification.reason_code
if stage1_progress is not None:
stage1_progress.record(classification.status)
continue
stage1_status = "command_error"
store.record_stage1_status(
stored_file.file_id,
@@ -656,7 +676,10 @@ def _reload_probe_payload(path: Path) -> dict[str, object] | None:
def _parse_probe_payload(stdout_text: str) -> dict[str, object] | None:
if not stdout_text.strip():
return None
try:
payload = orjson.loads(stdout_text)
except orjson.JSONDecodeError:
return None
if isinstance(payload, dict):
return payload
return None
+82
View File
@@ -161,6 +161,88 @@ def test_scan_command_processes_stage1_results_and_exports_reports(
assert csv_path.exists()
def test_scan_command_treats_invalid_probe_json_with_nonzero_exit_as_confirmed_broken(
tmp_path: Path, monkeypatch
) -> None:
root = tmp_path / "videos"
root.mkdir()
broken = root / "broken.mp4"
broken.write_bytes(b"broken")
db_path = tmp_path / "scan_state.db"
def fake_run_ffprobe(path, **kwargs):
return ProbeExecutionResult(
status="completed",
command=("ffprobe", str(path)),
exit_code=1,
stdout_text='{\n',
stderr_text="",
elapsed_ms=1,
)
monkeypatch.setattr("tgvideo_check.cli.run_ffprobe", fake_run_ffprobe)
result = runner.invoke(
app,
[
"scan",
str(root),
"--db",
str(db_path),
],
)
assert result.exit_code == 0
assert "Scanned 1 file(s)" in result.stdout
assert "confirmed_broken=1" in result.stdout
store = ScanStore(db_path)
rows = store.list_files(1)
assert rows[0].final_status == "confirmed_broken"
assert rows[0].reason_code == "ffprobe_exit_nonzero"
def test_scan_command_treats_invalid_probe_json_with_zero_exit_as_command_error(
tmp_path: Path, monkeypatch
) -> None:
root = tmp_path / "videos"
root.mkdir()
broken = root / "broken.mp4"
broken.write_bytes(b"broken")
db_path = tmp_path / "scan_state.db"
def fake_run_ffprobe(path, **kwargs):
return ProbeExecutionResult(
status="completed",
command=("ffprobe", str(path)),
exit_code=0,
stdout_text='{\n',
stderr_text="",
elapsed_ms=1,
)
monkeypatch.setattr("tgvideo_check.cli.run_ffprobe", fake_run_ffprobe)
result = runner.invoke(
app,
[
"scan",
str(root),
"--db",
str(db_path),
],
)
assert result.exit_code == 0
assert "Scanned 1 file(s)" in result.stdout
assert "command_error=1" in result.stdout
store = ScanStore(db_path)
rows = store.list_files(1)
assert rows[0].final_status == "command_error"
assert rows[0].reason_code == "invalid_probe_output"
def test_scan_command_leaves_stage2_pending_by_default(tmp_path, monkeypatch) -> None:
root = tmp_path / "videos"
root.mkdir()