Add ČSFD Anubis bypass, drop legacy preset tags, rename Země → Země původu

This commit is contained in:
2026-06-12 20:30:14 +02:00
parent 22a14b1e41
commit 86c689b9f1
14 changed files with 349 additions and 146 deletions
+35 -4
View File
@@ -16,9 +16,19 @@ from src.core.csfd import (
_extract_genres,
_extract_origin_info,
_check_dependencies,
_solve_anubis_pow,
)
def _mock_session(mock_requests):
"""Wire ``mock_requests`` so ``requests.Session()`` (also as a context
manager) yields a single configurable session mock and return it."""
session = MagicMock()
session.__enter__.return_value = session
mock_requests.Session.return_value = session
return session
# Sample HTML for testing
SAMPLE_JSON_LD = """
{
@@ -219,7 +229,8 @@ class TestFetchMovie:
mock_response = MagicMock()
mock_response.text = SAMPLE_HTML
mock_response.raise_for_status = MagicMock()
mock_requests.get.return_value = mock_response
session = _mock_session(mock_requests)
session.get.return_value = mock_response
movie = fetch_movie("https://www.csfd.cz/film/123-test/")
@@ -227,13 +238,14 @@ class TestFetchMovie:
assert movie.csfd_id == 123
assert movie.rating == 86
assert "Drama" in movie.genres
mock_requests.get.assert_called_once()
session.get.assert_called_once()
@patch("src.core.csfd.requests")
def test_fetch_movie_network_error(self, mock_requests):
"""Test network error handling."""
import requests as real_requests
mock_requests.get.side_effect = real_requests.RequestException("Network error")
session = _mock_session(mock_requests)
session.get.side_effect = real_requests.RequestException("Network error")
with pytest.raises(real_requests.RequestException):
fetch_movie("https://www.csfd.cz/film/123/")
@@ -254,7 +266,8 @@ class TestSearchMovies:
mock_response = MagicMock()
mock_response.text = search_html
mock_response.raise_for_status = MagicMock()
mock_requests.get.return_value = mock_response
session = _mock_session(mock_requests)
session.get.return_value = mock_response
mock_requests.utils.quote = lambda x: x
results = search_movies("test", limit=10)
@@ -277,6 +290,24 @@ class TestFetchMovieById:
assert movie.title == "Test"
class TestAnubisPoW:
"""Tests for the Anubis proof-of-work solver."""
def test_solve_pow_difficulty_one(self):
"""Difficulty 1 requires a single leading zero nibble in the hash."""
import hashlib
random_data = "abc123"
hash_hex, nonce, _ = _solve_anubis_pow(random_data, difficulty=1)
assert hash_hex[0] == "0"
assert hashlib.sha256(f"{random_data}{nonce}".encode()).hexdigest() == hash_hex
def test_solve_pow_difficulty_two(self):
"""Difficulty 2 requires two leading zero nibbles (one zero byte)."""
hash_hex, _, _ = _solve_anubis_pow("seed", difficulty=2)
assert hash_hex[:2] == "00"
class TestDependencyCheck:
"""Tests for dependency checking."""
+5 -7
View File
@@ -40,10 +40,9 @@ class TestFile:
assert file_obj.metadata_filename == expected
def test_file_initial_tags(self, test_file, tag_manager):
"""Test že nový soubor má tag Stav/Nové"""
"""Test že nový soubor nežádné automatické tagy (Stav/Nové odstraněn)"""
file_obj = File(test_file, tag_manager)
assert len(file_obj.tags) == 1
assert file_obj.tags[0].full_path == "Stav/Nové"
assert file_obj.tags == []
def test_file_metadata_saved(self, test_file, tag_manager):
"""Test že metadata jsou uložena při vytvoření"""
@@ -75,13 +74,12 @@ class TestFile:
# Vytvoření nového objektu - měl by načíst metadata
file_obj2 = File(test_file, tag_manager)
assert len(file_obj2.tags) == 2 # Stav/Nové + Video/HD
assert len(file_obj2.tags) == 1 # Video/HD
assert file_obj2.date == "2025-01-15"
# Kontrola že tagy obsahují správné hodnoty
tag_paths = {tag.full_path for tag in file_obj2.tags}
assert "Video/HD" in tag_paths
assert "Stav/Nové" in tag_paths
def test_file_set_date(self, test_file, tag_manager):
"""Test nastavení data"""
@@ -115,7 +113,7 @@ class TestFile:
file_obj.add_tag(tag)
assert tag in file_obj.tags
assert len(file_obj.tags) == 2 # Stav/Nové + Video/4K
assert len(file_obj.tags) == 1 # Video/4K
def test_file_add_tag_string(self, test_file, tag_manager):
"""Test přidání tagu jako string"""
@@ -182,7 +180,7 @@ class TestFile:
"""Test File bez TagManager"""
file_obj = File(test_file, tagmanager=None)
assert file_obj.tagmanager is None
assert len(file_obj.tags) == 0 # Bez TagManager se nepřidá Stav/Nové
assert len(file_obj.tags) == 0 # nový soubor nemá žádné automatické tagy
def test_file_metadata_persistence(self, test_file, tag_manager):
"""Test že metadata přežijí reload"""
+3 -3
View File
@@ -42,7 +42,7 @@ class TestHardlinkManager:
# File 1 with multiple tags
f1 = File(temp_source_dir / "file1.txt", tag_manager)
f1.tags.clear() # Remove default "Stav/Nové" tag
f1.tags.clear() # ensure a clean tag set
f1.add_tag(Tag("žánr", "Komedie"))
f1.add_tag(Tag("žánr", "Akční"))
f1.add_tag(Tag("rok", "1988"))
@@ -50,13 +50,13 @@ class TestHardlinkManager:
# File 2 with one tag
f2 = File(temp_source_dir / "file2.txt", tag_manager)
f2.tags.clear() # Remove default "Stav/Nové" tag
f2.tags.clear() # ensure a clean tag set
f2.add_tag(Tag("žánr", "Drama"))
files.append(f2)
# File 3 with no tags
f3 = File(temp_source_dir / "file3.txt", tag_manager)
f3.tags.clear() # Remove default "Stav/Nové" tag
f3.tags.clear() # ensure a clean tag set
files.append(f3)
return files
+1 -1
View File
@@ -63,7 +63,7 @@ class TestFileWithIndex:
assert not f.metadata_filename.exists() # no sidecar
assert index.get(movie) is not None # record created in index
assert f.tags[0].full_path == "Stav/Nové"
assert f.tags == [] # no automatic tags
def test_index_backed_metadata_persists_across_reload(self, tmp_path):
index = PoolIndex(tmp_path)
+25 -98
View File
@@ -13,24 +13,12 @@ class TestTagManager:
@pytest.fixture
def empty_tag_manager(self):
"""Fixture pro prázdný TagManager (bez default tagů)"""
tm = TagManager()
# Odstranit default tagy pro testy které potřebují prázdný manager
for category in list(tm.tags_by_category.keys()):
tm.remove_category(category)
return tm
"""Fixture pro prázdný TagManager (alias k tag_manager, žádné default tagy)"""
return TagManager()
def test_tag_manager_creation_has_defaults(self, tag_manager):
"""Test vytvoření TagManager obsahuje default tagy"""
assert "Hodnocení" in tag_manager.tags_by_category
assert "Barva" in tag_manager.tags_by_category
def test_tag_manager_default_tags_count(self, tag_manager):
"""Test počtu default tagů"""
# Hodnocení má 5 hvězdiček
assert len(tag_manager.tags_by_category["Hodnocení"]) == 5
# Barva má 6 barev
assert len(tag_manager.tags_by_category["Barva"]) == 6
def test_tag_manager_creation_has_no_defaults(self, tag_manager):
"""Test že nový TagManager nemá žádné předdefinované tagy"""
assert tag_manager.tags_by_category == {}
def test_add_category(self, tag_manager):
"""Test přidání kategorie"""
@@ -141,11 +129,9 @@ class TestTagManager:
assert "Video/4K" in tags
assert "Audio/MP3" in tags
def test_get_all_tags_includes_defaults(self, tag_manager):
"""Test že get_all_tags obsahuje default tagy"""
tags = tag_manager.get_all_tags()
# Minimálně 11 default tagů (5 hodnocení + 6 barev)
assert len(tags) >= 11
def test_get_all_tags_empty_on_fresh_manager(self, tag_manager):
"""Test že čerstvý TagManager nemá žádné tagy (bez defaultů)"""
assert tag_manager.get_all_tags() == []
def test_get_categories_empty(self, empty_tag_manager):
"""Test získání kategorií (prázdný manager)"""
@@ -164,11 +150,9 @@ class TestTagManager:
assert "Audio" in categories
assert "Foto" in categories
def test_get_categories_includes_defaults(self, tag_manager):
"""Test že get_categories obsahuje default kategorie"""
categories = tag_manager.get_categories()
assert "Hodnocení" in categories
assert "Barva" in categories
def test_get_categories_empty_on_fresh_manager(self, tag_manager):
"""Test že čerstvý TagManager nemá žádné kategorie (bez defaultů)"""
assert tag_manager.get_categories() == []
def test_get_tags_in_category_empty(self, tag_manager):
"""Test získání tagů z prázdné kategorie"""
@@ -230,81 +214,33 @@ class TestTagManager:
class TestDefaultTags:
"""Testy pro defaultní tagy"""
"""Testy pro defaultní tagy (legacy Tagger presety byly odstraněny)"""
def test_default_tags_constant_exists(self):
"""Test že DEFAULT_TAGS konstanta existuje"""
assert DEFAULT_TAGS is not None
"""Test že DEFAULT_TAGS konstanta existuje a je prázdná"""
assert isinstance(DEFAULT_TAGS, dict)
assert DEFAULT_TAGS == {}
def test_default_tags_has_hodnoceni(self):
"""Test že DEFAULT_TAGS obsahuje Hodnocení"""
assert "Hodnocení" in DEFAULT_TAGS
assert len(DEFAULT_TAGS["Hodnocení"]) == 5
def test_legacy_presets_removed(self):
"""Test že staré předdefinované kategorie (Hodnocení, Barva) jsou pryč"""
assert "Hodnocení" not in DEFAULT_TAGS
assert "Barva" not in DEFAULT_TAGS
def test_default_tags_has_barva(self):
"""Test že DEFAULT_TAGS obsahuje Barva"""
assert "Barva" in DEFAULT_TAGS
assert len(DEFAULT_TAGS["Barva"]) == 6
def test_hodnoceni_stars_content(self):
"""Test obsahu hvězdiček v Hodnocení"""
stars = DEFAULT_TAGS["Hodnocení"]
assert "" in stars
assert "⭐⭐⭐⭐⭐" in stars
def test_barva_colors_content(self):
"""Test obsahu barev v Barva"""
colors = DEFAULT_TAGS["Barva"]
# Kontrolujeme že obsahuje některé barvy
color_names = " ".join(colors)
assert "Červená" in color_names
assert "Zelená" in color_names
assert "Modrá" in color_names
def test_tag_manager_loads_all_default_tags(self):
"""Test že TagManager načte všechny default tagy"""
def test_tag_manager_starts_empty(self):
"""Test že TagManager bez defaultů startuje prázdný"""
tm = TagManager()
assert tm.get_all_tags() == []
assert tm.get_categories() == []
for category, tag_names in DEFAULT_TAGS.items():
assert category in tm.tags_by_category
tags_in_category = tm.get_tags_in_category(category)
assert len(tags_in_category) == len(tag_names)
def test_can_add_custom_tags_alongside_defaults(self):
"""Test že lze přidat vlastní tagy vedle defaultních"""
def test_can_add_custom_tags(self):
"""Test že lze přidat vlastní tagy do prázdného manageru"""
tm = TagManager()
initial_count = len(tm.get_all_tags())
tm.add_tag("Custom", "MyTag")
assert len(tm.get_all_tags()) == initial_count + 1
assert tm.get_all_tags() == ["Custom/MyTag"]
assert "Custom" in tm.get_categories()
def test_can_remove_default_category(self):
"""Test že lze odstranit default kategorii"""
tm = TagManager()
tm.remove_category("Hodnocení")
assert "Hodnocení" not in tm.tags_by_category
def test_hodnoceni_tags_are_sorted_by_stars(self):
"""Test že tagy v Hodnocení jsou seřazeny od 1 do 5 hvězd"""
tm = TagManager()
tags = tm.get_tags_in_category("Hodnocení")
tag_names = [t.name for t in tags]
assert tag_names == ["", "⭐⭐", "⭐⭐⭐", "⭐⭐⭐⭐", "⭐⭐⭐⭐⭐"]
def test_barva_tags_are_sorted_in_predefined_order(self):
"""Test že tagy v Barva jsou seřazeny v předdefinovaném pořadí"""
tm = TagManager()
tags = tm.get_tags_in_category("Barva")
tag_names = [t.name for t in tags]
expected = ["🔴 Červená", "🟠 Oranžová", "🟡 Žlutá", "🟢 Zelená", "🔵 Modrá", "🟣 Fialová"]
assert tag_names == expected
def test_custom_category_tags_sorted_alphabetically(self):
"""Test že tagy v custom kategorii jsou seřazeny abecedně"""
tm = TagManager()
@@ -316,12 +252,3 @@ class TestDefaultTags:
tag_names = [t.name for t in tags]
assert tag_names == ["4K", "HD", "SD"]
def test_can_add_tag_to_default_category(self):
"""Test že lze přidat tag do default kategorie"""
tm = TagManager()
initial_count = len(tm.get_tags_in_category("Hodnocení"))
tm.add_tag("Hodnocení", "Custom Rating")
assert len(tm.get_tags_in_category("Hodnocení")) == initial_count + 1