Rework Curator into a Jellyfin-first library manager

This commit is contained in:
2026-08-31 18:34:03 +02:00
parent 1c78ca9013
commit 6a2baf243f
25 changed files with 2420 additions and 1502 deletions
+24 -53
View File
@@ -207,8 +207,8 @@ class TestFile:
assert file_obj2.date == "2025-01-01"
class TestApplyCsfdTags:
"""Tests for File.apply_csfd_tags tag assignment (CSFD fetch is mocked)."""
class TestApplyNfoTags:
"""Tests for File.apply_nfo tag assignment (NFO parsed from disk)."""
@pytest.fixture
def tag_manager(self):
@@ -222,22 +222,14 @@ class TestApplyCsfdTags:
def movie_file(self, tmp_path, tag_manager, index):
path = tmp_path / "Matrix.mkv"
path.write_text("x")
f = File(path, tag_manager, index=index)
f.set_csfd_link("https://www.csfd.cz/film/9499-matrix/")
return f
return File(path, tag_manager, index=index)
def test_apply_csfd_tags_assigns_expected_categories(self, movie_file):
from unittest.mock import patch
from src.core.csfd import CSFDMovie
def test_apply_nfo_assigns_expected_categories(self, movie_file):
from src.core.nfo import NfoData
movie = CSFDMovie(
title="Matrix", url="u", year=1999, genres=["Akční", "Sci-Fi"],
directors=["Lana Wachowski", "Lilly Wachowski"],
actors=["Keanu Reeves", "Laurence Fishburne"],
rating=90, countries=["USA"],
)
with patch("src.core.csfd.fetch_movie", return_value=movie):
result = movie_file.apply_csfd_tags()
nfo = NfoData(title="Matrix", year="1999", genres=["Akční", "Sci-Fi"],
countries=["USA"], rating=90)
result = movie_file.apply_nfo(nfo)
assert result["success"]
paths = {t.full_path for t in movie_file.tags}
@@ -247,28 +239,14 @@ class TestApplyCsfdTags:
assert "Země původu/USA" in paths
assert "Hodnocení/90" in paths # exact value; folder grouping happens later
def test_apply_csfd_tags_does_not_tag_directors_or_actors(self, movie_file):
"""Režie/herci se jen cachují, netvoří se z nich tagy (bylo by jich moc)."""
from unittest.mock import patch
from src.core.csfd import CSFDMovie
movie = CSFDMovie(
title="Matrix", url="u", directors=["Lana Wachowski"],
actors=["Keanu Reeves", "Laurence Fishburne"], genres=["Drama"],
)
with patch("src.core.csfd.fetch_movie", return_value=movie):
movie_file.apply_csfd_tags()
paths = {t.full_path for t in movie_file.tags}
assert not any(p.startswith("Režie/") for p in paths)
assert not any(p.startswith("Herec/") for p in paths)
cached = movie_file.get_cached_movie()
assert cached.directors == ["Lana Wachowski"]
assert cached.actors == ["Keanu Reeves", "Laurence Fishburne"]
def test_apply_nfo_none_is_noop(self, movie_file):
result = movie_file.apply_nfo(None)
assert not result["success"]
assert movie_file.tags == []
def test_name_context_fields(self, movie_file):
movie_file.title = "Dr. No"
movie_file.csfd_cache = {"year": 1962, "rating": 75}
movie_file.meta = {"year": 1962, "rating": 75}
ctx = movie_file.name_context()
assert ctx["title"] == "Dr. No"
assert ctx["year"] == "1962" # coerced to str for uniform template fields
@@ -278,7 +256,7 @@ class TestApplyCsfdTags:
assert "{year} - {title}{ext}".format(**ctx) == f"1962 - Dr. No{ctx['ext']}"
def test_name_context_year_from_tag_when_no_cache(self, movie_file):
movie_file.csfd_cache = None
movie_file.meta = None
movie_file.add_tag("Rok/1999")
assert movie_file.name_context()["year"] == "1999"
@@ -315,37 +293,30 @@ class TestApplyCsfdTags:
assert "{collection_sort} - {title}{ext}".format(**ctx) == \
f"01 - Dr. No{ctx['ext']}"
def test_apply_csfd_tags_honors_custom_schema(self, movie_file):
def test_apply_nfo_honors_custom_schema(self, movie_file):
"""A schema without the rating entry produces no Hodnocení tags."""
from unittest.mock import patch
from src.core.csfd import CSFDMovie
from src.core.nfo import NfoData
schema = [{"category": "Žánr", "csfd_field": "genres",
"transform": None, "filmoteka_root": ""}]
movie = CSFDMovie(title="Matrix", url="u", rating=90, genres=["Drama"])
with patch("src.core.csfd.fetch_movie", return_value=movie):
movie_file.apply_csfd_tags(schema)
movie_file.apply_nfo(NfoData(genres=["Drama"], rating=90), schema)
paths = {t.full_path for t in movie_file.tags}
assert "Žánr/Drama" in paths
assert not any(p.startswith("Hodnocení/") for p in paths)
def test_apply_csfd_tags_preserves_user_tags_on_refetch(self, movie_file):
"""Re-fetching regenerates only ČSFD tags; user-added tags survive."""
from unittest.mock import patch
from src.core.csfd import CSFDMovie
def test_apply_nfo_preserves_user_tags_on_refresh(self, movie_file):
"""Re-reading regenerates only auto (NFO) tags; user-added tags survive."""
from src.core.nfo import NfoData
movie_file.add_tag("Sbírka/Oblíbené") # user tag
first = CSFDMovie(title="A", url="u", year=1999, genres=["Akční"])
with patch("src.core.csfd.fetch_movie", return_value=first):
movie_file.apply_csfd_tags()
second = CSFDMovie(title="B", url="u", year=2009, genres=["Drama"])
with patch("src.core.csfd.fetch_movie", return_value=second):
movie_file.apply_csfd_tags()
movie_file.apply_nfo(NfoData(year="1999", genres=["Akční"]))
movie_file.apply_nfo(NfoData(year="2009", genres=["Drama"]))
paths = {t.full_path for t in movie_file.tags}
assert "Sbírka/Oblíbené" in paths # user tag kept
assert "Žánr/Drama" in paths # new ČSFD tag
assert "Žánr/Drama" in paths # new NFO tag
assert "Rok/2009" in paths
assert "Žánr/Akční" not in paths # old NFO tag regenerated away
assert "Žánr/Akční" not in paths # stale ČSFD tag dropped
assert "Rok/1999" not in paths