OverviewFilesCommitsIssuesDocsReleasesPeers

stremio-vsembed / test_subsync_reference.py

224 lines · python ref:
"""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