goon/tests/test_studio_title_dedup.py
goon-foss 7fea132668 feat(dedup): kopie tej samej sceny z tubow o roznym formacie tytulu
Kazdy tube zapisuje tytul po swojemu ("[Milfy] Koda Monroe (...)", "Milfy 26 09 16 ...",
"... 4K"), a miniatury sa z innych klatek, wiec ani phash, ani title_duration_dedup
(identyczny tytul) ich nie lapaly. Jedna scena Milfy wisiala w katalogu 8 razy.

Nowy job porownuje rdzen tytulu w obrebie studia: bez nazwy studia, dat, znacznikow
jakosci i nazwisk obsady. Numery czesci zostaja ("Part 1" to nie "Part 2"). Straznicy:
dlugosc, data premiery, wspolna obsada, dluzszy rdzen gdy brak dlugosci. Kopie bez studia
dolaczaja tylko przy zgodnej co do 3 s dlugosci. Kategorie wpisane przez tube jako obsada
nie skracaja rdzenia. Cyklicznie co 12 h z oknem 30 dni.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:10 +02:00

93 lines
4.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import date, datetime
from app.scheduler.studio_title_dedup import Cand, plan_merges, same_scene, studio_tokens
_T0 = datetime(2026, 9, 16, 23, 0)
_MILFY = studio_tokens("Milfy", "milfy")
def _c(cid, title, dur=None, rel=None, perfs=(), canon=False, live=1, studio="milfy"):
return Cand(
id=cid, title=title, studio_id=studio, studio_name="Milfy", studio_slug="milfy",
duration_sec=dur, release_date=rel, created_at=_T0, perfs=tuple(perfs), canon=canon, live=live,
)
# Zgloszenie bb1a357d: ta sama scena z osmiu tubow, kazdy z innym formatem tytulu.
_MILFY_COPIES = [
_c("canon", "Voluptuous Therapist Fucks Prisoner", 2218, date(2026, 9, 16),
("Troy Francisco", "Koda Monroe"), canon=True),
_c("a", "MILFY – Koda Monroe – Voluptuous Therapist Fucks Prisoner", 2218, date(2026, 9, 16),
("Troy Francisco", "Koda Monroe"), live=4),
_c("b", "[Milfy] Koda Monroe (Voluptuous Therapist Fucks Prisoner)", None, date(2026, 9, 16)),
_c("c", "[MILFY] Koda Monroe – Voluptuous Therapist Fucks Prisoner", perfs=("Koda Monroe",)),
_c("d", "Koda Monroe - Voluptuous Therapist Fucks Prisoner (17/9/26)", 2218),
_c("e", "Koda Monroe Voluptuous Therapist Fucks Prisoner 4K", 2218),
_c("f", "Milfy 26 09 16 Koda Monroe Voluptuous Therapist Fucks Prisoner", None, date(2026, 9, 16)),
]
def test_milfy_copies_collapse_into_canonical_scene():
plan = plan_merges(_MILFY_COPIES)
assert len(plan) == 1
keep, drops = plan[0]
assert keep.id == "canon"
assert {d.id for d in drops} == {"a", "b", "c", "d", "e", "f"}
def test_part_numbers_are_not_dates():
one = _c("1", "Ariel Swings Her Whip", 600, date(2026, 9, 16))
two = _c("2", "Ariel Swings Her Whip 2", 600, date(2026, 9, 16))
assert not same_scene(one, two, _MILFY)
p1 = _c("p1", "Jewell - Punishment Stool - Part 1", 232, date(2003, 11, 13))
p2 = _c("p2", "Jewell - Punishment Stool - Part 2", 231, date(2003, 11, 13))
assert not same_scene(p1, p2, _MILFY)
def test_guards():
base = _c("x", "Voluptuous Therapist Fucks Prisoner", 2218, date(2026, 9, 16), ("Koda Monroe",))
longer = _c("y", "Voluptuous Therapist Fucks Prisoner", 2600, date(2026, 9, 16), ("Koda Monroe",))
assert not same_scene(base, longer, _MILFY)
later = _c("z", "Voluptuous Therapist Fucks Prisoner", 2218, date(2026, 10, 1), ("Koda Monroe",))
assert not same_scene(base, later, _MILFY)
year_only = _c("j", "Voluptuous Therapist Fucks Prisoner", 2218, date(2026, 1, 1), ("Koda Monroe",))
assert same_scene(base, year_only, _MILFY)
other_cast = _c("o", "Voluptuous Therapist Fucks Prisoner", 2218, date(2026, 9, 16), ("Someone Else",))
assert not same_scene(base, other_cast, _MILFY)
other_studio = _c("s", "Voluptuous Therapist Fucks Prisoner", 2218, date(2026, 9, 16), studio="blacked")
assert not same_scene(base, other_studio, _MILFY)
# Bez dlugosci po obu stronach trzy slowa to za malo.
short_a = _c("sa", "[Milfy] Hot Stepmom Fun")
short_b = _c("sb", "Milfy 26 09 16 Hot Stepmom Fun")
assert not same_scene(short_a, short_b, _MILFY)
def test_chain_does_not_pull_in_incompatible_scene():
keep = _c("k", "Hotel Vixen Season 3 Episode 4 Soft Launch Hard Times", 2608, canon=True)
bridge = _c("m", "[Milfy] Hotel Vixen Season 3 Episode 4 Soft Launch Hard Times")
other = _c("l", "Milfy Hotel Vixen Season 3 Episode 4 Soft Launch Hard Times", 2896)
plan = plan_merges([keep, bridge, other])
assert [(k.id, [d.id for d in ds]) for k, ds in plan] == [("k", ["m"])]
def test_category_named_as_performer_does_not_shorten_core():
# Tube wpisal kategorie jako obsade. Bez listy smieci "big", "ass" i "tits" wypadlyby
# z obu tytulow i dwie rozne sceny mialyby ten sam rdzen "blonde fucks jason luv".
a = _c("a", "Big Ass Blonde Fucks Jason Luv", perfs=("Big Ass", "Big Tits"))
b = _c("b", "Big Tits Blonde Fucks Jason Luv")
assert not same_scene(a, b, _MILFY, junk_names=frozenset({"big ass", "big tits"}))
def test_copies_without_studio_join_only_with_matching_duration():
orphan = _c("o1", "Koda Monroe - Voluptuous Therapist Fucks Prisoner (17/9/26)", 2218, studio="")
orphan_4k = _c("o2", "Koda Monroe Voluptuous Therapist Fucks Prisoner 4K", 2217, studio="")
other_cut = _c("o3", "Koda Monroe Voluptuous Therapist Fucks Prisoner", 2600, studio="")
no_duration = _c("o4", "Koda Monroe Voluptuous Therapist Fucks Prisoner", None, studio="")
plan = plan_merges(_MILFY_COPIES + [orphan, orphan_4k, other_cut, no_duration])
keep, drops = plan[0]
assert keep.id == "canon"
ids = {d.id for d in drops}
assert {"o1", "o2"} <= ids
assert not ids & {"o3", "o4"}
# Dwie sceny bez studia nie maja kotwicy.
assert not same_scene(orphan, orphan_4k, _MILFY)