OverviewFilesCommitsIssuesDocsReleasesPeers

stremio-vsembed / test_source_registry.py

160 lines · python ref:
"""The source registry: what a source is, and which ones may feed the library.

Sources were hardcoded -- extract_streams named fmovies and vsembed inline, and
vidcore was bolted on beside them as a special case. There was no shape into
which a fourth could be added, and no place to record what a source can and
cannot do.

Three properties matter, and the third is the one that cost a day to learn:

  container   hls-fmp4 needs a remux to become seekable; progressive-mp4 is
              seekable as-is, so ingesting it is a plain fetch with no ffmpeg.
  browser     resolving needs a real browser (~11s, xvfb+patchright) rather than
              plain HTTP, which decides whether it can sit on a hot path.
  ingestable  whether a plain HTTP client can fetch the BYTES.

`ingestable` is not a detail. vidlink hands over a signed progressive-MP4 URL in
3s with exact sizes -- strictly better than vidcore on every axis that shows up
in an API response -- and is still useless to us, because its proxy rejects curl
AND ffmpeg even with byte-exact browser headers (measured 2026-08-11: 428/403/429
across six combinations). The local-first design rests on ffmpeg pulling bytes
independently of any player, so a browser-only source cannot feed the library at
any quality.

Encoding that here means the next candidate cannot be silently wired into ingest
on the strength of a good-looking API.

Run:  .venv/bin/python3 -m pytest test_source_registry.py -q
"""

import pytest

import addon


@pytest.fixture(autouse=True)
def clean_registry(monkeypatch):
    monkeypatch.setattr(addon, "SOURCES", {})
    yield


def _src(sid, **kw):
    defaults = dict(name=sid, container="hls-fmp4", ingestable=True,
                    browser=False, heights=(1080,), resolve=None, enabled=True)
    defaults.update(kw)
    return addon.Source(id=sid, **defaults)


# --- registration -----------------------------------------------------------

def test_a_source_can_be_registered_and_looked_up():
    addon.register_source(_src("alpha"))
    assert addon.get_source("alpha").name == "alpha"


def test_an_unknown_source_is_none_rather_than_a_crash():
    assert addon.get_source("nope") is None


def test_a_duplicate_id_is_refused():
    """Two sources sharing an id would make row ordering and breaker state
    silently ambiguous."""
    addon.register_source(_src("alpha"))
    with pytest.raises(ValueError):
        addon.register_source(_src("alpha"))


# --- ordering ---------------------------------------------------------------

def test_progressive_sources_are_offered_before_hls():
    """A progressive MP4 seeks natively. HLS on this stack does not -- that is
    the whole subject of #4 -- so it goes second."""
    addon.register_source(_src("hls-one", container="hls-fmp4"))
    addon.register_source(_src("prog-one", container="progressive-mp4"))
    assert [s.id for s in addon.ordered_sources()] == ["prog-one", "hls-one"]


def test_a_disabled_source_is_not_offered():
    addon.register_source(_src("off", enabled=False))
    assert addon.ordered_sources() == []


def test_ordering_is_stable_within_a_container_class():
    for sid in ("a", "b", "c"):
        addon.register_source(_src(sid))
    assert [s.id for s in addon.ordered_sources()] == ["a", "b", "c"]


# --- the ingest guarantee ---------------------------------------------------

def test_a_browser_only_source_is_never_chosen_for_ingest():
    """THE point of this registry. vidlink sorts first on every visible merit --
    progressive MP4, 3s resolve, exact sizes -- and ffmpeg cannot fetch a byte
    of it. Ranking must not be able to override that."""
    addon.register_source(_src("vidlink-like", container="progressive-mp4",
                               ingestable=False))
    addon.register_source(_src("vidcore-like", container="hls-fmp4",
                               ingestable=True))
    assert addon.ingest_source().id == "vidcore-like"


def test_no_ingestable_source_yields_none_rather_than_a_bad_choice():
    addon.register_source(_src("browser-only", ingestable=False))
    assert addon.ingest_source() is None


def test_a_non_ingestable_source_is_still_offered_for_playback():
    """It cannot feed the library, but it can still be watched -- withholding it
    would remove a working way to play something."""
    addon.register_source(_src("browser-only", ingestable=False))
    assert [s.id for s in addon.ordered_sources()] == ["browser-only"]


def test_a_disabled_source_is_never_chosen_for_ingest():
    addon.register_source(_src("off", ingestable=True, enabled=False))
    assert addon.ingest_source() is None


# --- the real registry ------------------------------------------------------
# Not fixture-isolated: these assert what the addon actually ships with.

def test_vidcore_is_registered_as_the_live_source():
    src = addon.SOURCES_DEFAULT["vidcore"]
    assert src.enabled and src.ingestable
    assert src.container == "hls-fmp4"      # why every copy needs a remux
    assert src.browser                      # ~11s, xvfb+patchright


def test_vidlink_is_recorded_as_measured_and_disabled():
    """Recorded rather than omitted: the next person to notice vidlink serves
    progressive MP4 should find the measurement, not repeat it."""
    src = addon.SOURCES_DEFAULT["vidlink"]
    assert src.container == "progressive-mp4"
    assert src.ingestable is False
    assert not src.enabled
    assert "428" in src.note or "proxy" in src.note.lower()


def test_the_dead_scrapers_are_recorded_as_disabled():
    for sid in ("fmovies", "vsembed"):
        assert addon.SOURCES_DEFAULT[sid].enabled is False


def test_the_shipped_registry_chooses_vidcore_for_ingest(monkeypatch):
    monkeypatch.setattr(addon, "SOURCES", dict(addon.SOURCES_DEFAULT))
    assert addon.ingest_source().id == "vidcore"


# --- the registry gates ingest ----------------------------------------------

def test_ingest_refuses_when_no_source_may_feed_the_library(monkeypatch, tmp_path):
    """If every ingestable source were disabled, ingest must decline outright
    rather than resolve, download and then discover it cannot."""
    monkeypatch.setattr(addon, "SOURCES", {})
    called = []
    monkeypatch.setattr(addon, "_library_meta",
                        lambda *a, **k: called.append(a) or None)
    state = addon._run_ingest("series", "tmdb:1", 1, 1, 720)
    assert state == "failed: no ingestable source"
    assert called == [], "it must not even look the title up"