"""The sync reference must be on the PLAYER's timeline (2026-10-18).
ffsubsync extracts speech by piping raw PCM out of ffmpeg, and raw PCM has no
timestamps: a gap in the audio is simply dropped. No Other Choice's audio
stream starts at 9.254 s (video at 0), so the 10-04 reference ran ~9.3 s early
and every measurement inherited it:
- the English "corrected" by -2.25 s actually needed +7.01 s (scale 1.001)
- the "-8.9 s family" of 23 tracks was IN SYNC (fr re-measures +0.33 s) --
the sync moved them 9 s off
Two independent references agree on the right answer: audio padded to its
timestamps (aresample=async=1:first_pts=0) gave +7.01 s, and three 5-minute
windows seeked by timestamp gave +7.03 s.
So the reference is built from gap-padded audio, results carry the reference
version they were measured with, and a result from the old reference is
measured again from the track's ORIGINAL -- the old correction is kept in the
store, never deleted. A track the user kept stays theirs.
Run: .venv/bin/python3 -m pytest test_subsync_reference.py -q
"""
import json
import os
import subprocess
import pytest
import addon
REAL_REFERENCE = addon._subsync_reference
@pytest.fixture
def lib(tmp_path, monkeypatch):
monkeypatch.setattr(addon, "LIBRARY_ROOT", str(tmp_path / "lib"))
monkeypatch.setattr(addon, "SUBS_ORIGINAL_DIR", str(tmp_path / "subs-original"))
monkeypatch.setattr(addon, "SUBTITLE_SYNC_FILE", str(tmp_path / "sync.json"))
monkeypatch.setattr(addon, "_subsync_available", lambda: True)
monkeypatch.setattr(addon, "SUBSYNC_LANGUAGES", ("en",))
monkeypatch.setattr(addon, "_notify_jellyfin", lambda p, t: None)
monkeypatch.setattr(addon, "_subsync_reference",
lambda dest, workdir: os.path.join(workdir, "ref.npz"))
dest = tmp_path / "lib" / "Movies" / "Film (2025) [tmdbid-1]" / "Film (2025).mp4"
dest.parent.mkdir(parents=True)
dest.write_bytes(b"video")
return str(dest)
def _write(path, body):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as f:
f.write(body)
return path
def _sidecar(dest, lang):
return os.path.splitext(dest)[0] + f".{lang}.srt"
def _record(records):
with open(addon.SUBTITLE_SYNC_FILE, "w") as f:
json.dump(records, f)
def _records():
with open(addon.SUBTITLE_SYNC_FILE) as f:
return json.load(f)
def _measure_by_body(table):
"""(offset, scale) chosen by the track's CONTENT, so a test can tell the
original from the old correction; writes the corrected output."""
seen = []
def measure(ref, srt_in, srt_out):
with open(srt_in) as f:
body = f.read()
seen.append(body)
offset, scale = table.get(body, (0.0, 1.0))
if srt_out:
with open(srt_out, "w") as f:
f.write("fixed")
return {"offset": offset, "scale": scale, "score": 1.0}
return measure, seen
# ------------------------------------------------------------ the reference
def test_the_reference_is_built_from_audio_padded_to_its_timestamps(lib, tmp_path,
monkeypatch):
_write(_sidecar(lib, "en"), "x")
monkeypatch.setattr(addon, "_subsync_reference", REAL_REFERENCE)
calls = []
def fake_run(cmd, **kw):
calls.append(cmd)
if os.path.basename(cmd[0]) == "ffsubsync":
np_path = os.path.join(kw["cwd"], "ref.npz")
open(np_path, "wb").close()
return subprocess.CompletedProcess(cmd, 0, "", "")
monkeypatch.setattr(addon.subprocess, "run", fake_run)
work = tmp_path / "work"
work.mkdir()
ref = addon._subsync_reference(lib, str(work))
assert ref == str(work / "ref.npz")
ffmpeg, subsync = calls
assert ffmpeg[0] == "ffmpeg" and lib in ffmpeg
assert "aresample=async=1:first_pts=0" in ffmpeg
wav = ffmpeg[-1]
assert wav.endswith(".wav") and os.path.dirname(wav) == str(work)
assert subsync[1] == wav and "--serialize-speech" in subsync
def test_an_audio_extraction_failure_is_no_reference(lib, tmp_path, monkeypatch):
_write(_sidecar(lib, "en"), "x")
monkeypatch.setattr(addon, "_subsync_reference", REAL_REFERENCE)
def boom(cmd, **kw):
raise subprocess.CalledProcessError(1, cmd)
monkeypatch.setattr(addon.subprocess, "run", boom)
assert addon._subsync_reference(lib, str(tmp_path)) is None
# ------------------------------------------- results from the old reference
def test_new_results_carry_the_reference_version(lib, monkeypatch):
en = _write(_sidecar(lib, "en"), "orig")
measure, _ = _measure_by_body({})
monkeypatch.setattr(addon, "_subsync_measure", measure)
addon._sync_subtitles(lib)
assert _records()[os.path.abspath(en)]["ref"] == addon.SUBSYNC_REF_VERSION
def test_a_correction_from_the_old_reference_is_redone_from_the_original(
lib, tmp_path, monkeypatch):
en = _write(_sidecar(lib, "en"), "old-fix")
orig = _write(str(tmp_path / "subs-original" / "en.srt.2"), "orig")
_record({os.path.abspath(en): {"status": "corrected", "offset": -2.25,
"scale": 1.001, "original": orig,
"identity": addon._file_identity(en)}})
measure, seen = _measure_by_body({"orig": (7.01, 1.001), "fixed": (0.0, 1.0)})
monkeypatch.setattr(addon, "_subsync_measure", measure)
addon._sync_subtitles(lib)
assert seen[0] == "orig", "measured the old correction, not the original"
rec = _records()[os.path.abspath(en)]
assert rec["status"] == "corrected" and rec["offset"] == 7.01
assert rec["ref"] == addon.SUBSYNC_REF_VERSION
with open(en) as f:
assert f.read() == "fixed"
kept = []
for root, _, files in os.walk(addon.SUBS_ORIGINAL_DIR):
for n in files:
with open(os.path.join(root, n)) as f:
kept.append(f.read())
assert "old-fix" in kept, "the superseded correction was not kept"
assert "orig" in kept
def test_a_track_the_old_reference_withdrew_comes_back_and_is_measured(
lib, tmp_path, monkeypatch):
en = _sidecar(lib, "en") # not in the library any more
orig = _write(str(tmp_path / "subs-original" / "en.srt.2"), "orig")
_record({os.path.abspath(en): {"status": "unfixable", "offset": 9.0,
"scale": 1.0, "original": orig,
"identity": None}})
measure, _ = _measure_by_body({"orig": (0.1, 1.0)})
monkeypatch.setattr(addon, "_subsync_measure", measure)
addon._sync_subtitles(lib)
assert os.path.exists(en)
assert _records()[os.path.abspath(en)]["status"] == "in_sync"
def test_an_old_in_sync_verdict_is_measured_again(lib, monkeypatch):
en = _write(_sidecar(lib, "en"), "orig")
_record({os.path.abspath(en): {"status": "in_sync", "offset": 0.1,
"scale": 1.0,
"identity": addon._file_identity(en)}})
measure, seen = _measure_by_body({"orig": (9.25, 1.0), "fixed": (0.0, 1.0)})
monkeypatch.setattr(addon, "_subsync_measure", measure)
addon._sync_subtitles(lib)
assert seen and _records()[os.path.abspath(en)]["status"] == "corrected"
def test_another_language_the_old_reference_touched_is_redone_too(
lib, tmp_path, monkeypatch):
"""English-only scope came AFTER 10-04's all-language pass, which moved
23 good No Other Choice tracks by -8.9 s. Our own damage is repaired
whatever the language."""
fr = _write(_sidecar(lib, "fr"), "old-fix")
orig = _write(str(tmp_path / "subs-original" / "fr.srt.2"), "orig")
_record({os.path.abspath(fr): {"status": "corrected", "offset": -8.93,
"scale": 1.0, "original": orig,
"identity": addon._file_identity(fr)}})
measure, _ = _measure_by_body({"orig": (0.33, 1.0), "fixed": (0.0, 1.0)})
monkeypatch.setattr(addon, "_subsync_measure", measure)
addon._sync_subtitles(lib)
rec = _records()[os.path.abspath(fr)]
assert rec["ref"] == addon.SUBSYNC_REF_VERSION and rec["status"] == "corrected"
def test_an_untouched_other_language_is_still_left_alone(lib, monkeypatch):
_write(_sidecar(lib, "fr"), "orig")
monkeypatch.setattr(addon, "_subsync_measure",
lambda *a: pytest.fail("measured a language out of scope"))
assert addon._sync_subtitles(lib)["tracks"] == 0
def test_a_track_the_user_kept_is_still_theirs(lib, monkeypatch):
en = _write(_sidecar(lib, "en"), "restored")
_record({os.path.abspath(en): {"status": "kept", "offset": 22.18, "scale": 1.0,
"identity": addon._file_identity(en)}})
monkeypatch.setattr(addon, "_subsync_measure",
lambda *a: pytest.fail("re-measured a kept track"))
assert addon._sync_subtitles(lib)["tracks"] == 0
def test_a_current_result_is_not_measured_again(lib, monkeypatch):
en = _write(_sidecar(lib, "en"), "orig")
measure, seen = _measure_by_body({})
monkeypatch.setattr(addon, "_subsync_measure", measure)
addon._sync_subtitles(lib)
addon._sync_subtitles(lib)
assert len(seen) == 1