fix(performers): zdejmij przypisania kategorii udajacych ludzi
"Natural Tits", "Big Black", "Anal Milf", "Cum Swallow", "Fat Ass" i 94
inne siedzialy w tabeli performers z tagow tubow wciaganych jako obsada.
Ugryzly 2026-08-14 przy rozplataniu zlepkow: regula uznala "Big Black" za
osobe wymieniona w tytule i dala mu 124 sceny.
TRZY OCZYWISTE HEURYSTYKI SPRAWDZONE I ODRZUCONE, kazda z kontrprzykladem:
1. "nazwa jest tez tagiem" -> prawdziwe dla Lauren Phillips, Julii Ann,
Nikki Benz (tuby robia tagi z nazwisk), 7625 z 74150 nazw
2. "nie ma kanonu" -> TPDB SAM MA "Big Black" i "Lesbian Love"
jako performerow, a realna "Mena Mason" refow nie ma
3. "tag >> performer" -> dziala dla "Natural Tits" (2147x) i "Rough
Sex" (1552x), ale "Big Black" ma 0,2x, "Lesbian Love" 0,0x
Kryterium jest wiec STRUKTURALNE i nie zalezy od zadnej z tych baz: cala
nazwa zlozona wylacznie ze slow opisujacych tresc. Kandydatow 101, czyli
na tyle malo, ze lista zostala PRZEJRZANA RECZNIE.
Przeglad wylapal falszywki: "Dick Nasty" ma refy z szesciu zrodel, w tym
StashDB, i jest realnym meskim performerem (obsada "Sugar Daddy 17" obok
Dave'a Cummingsa). "King Cock" wykluczony z ostroznosci. Oba w
_JEDNAK_LUDZIE, z uzasadnieniem w kodzie.
Wynik: 11 793 przypisania zdjete od 99 kategorii, do archiwum. Same rekordy
performerow ZOSTAJA: scene_count spadl do 0, wiec i tak wypadaja z list
z only_with_content, a skasowanie rekordu zerwaloby refy kanoniczne przy
czyms, co TPDB u siebie trzyma jako performera.
Kontrola: Big Black/Natural Tits/Anal Milf/Fat Ass -> 0 scen, Lauren
Phillips 2146 i Dick Nasty 69 nietkniete.
This commit is contained in:
parent
96d16b5488
commit
d9177febf7
1 changed files with 147 additions and 0 deletions
147
scripts/prune_category_performers.py
Normal file
147
scripts/prune_category_performers.py
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
"""Zdejmuje przypisania „performerów", którzy są nazwami KATEGORII, nie ludźmi.
|
||||||
|
|
||||||
|
W tabeli `performers` siedzą pozycje w rodzaju „Natural Tits", „Big Black", „Anal Milf",
|
||||||
|
„Cum Swallow" czy „Fat Ass". Biorą się z tagów tubów wciąganych jako obsada. Ugryzły
|
||||||
|
2026-08-14 przy rozplataniu zlepków: reguła uznała „Big Black" za osobę wymienioną
|
||||||
|
w tytule i dała mu 124 sceny.
|
||||||
|
|
||||||
|
**Trzy oczywiste heurystyki sprawdzone i ODRZUCONE**, każda z konkretnym kontrprzykładem:
|
||||||
|
|
||||||
|
1. „nazwa jest też tagiem" — prawdziwe dla Lauren Phillips, Julii Ann i Nikki Benz,
|
||||||
|
bo tuby robią tagi z nazwisk (7625 z 74150 nazw).
|
||||||
|
2. „nie ma refów kanonicznych" — **TPDB SAM MA** „Big Black" i „Lesbian Love" jako
|
||||||
|
performerów, a realna „Mena Mason" refów nie ma.
|
||||||
|
3. „tag ma dużo więcej scen niż performer" — działa dla „Natural Tits" (2147×) i
|
||||||
|
„Rough Sex" (1552×), ale „Big Black" ma 0,2×, a „Lesbian Love" 0,0×.
|
||||||
|
|
||||||
|
Dlatego kryterium jest STRUKTURALNE i nie zależy od żadnej z tych baz: **cała nazwa
|
||||||
|
składa się wyłącznie ze słów opisujących treść**. „Big Black" to big + black, „Natural
|
||||||
|
Tits" to natural + tits, a „Lauren Phillips" nie ma ani jednego takiego członu.
|
||||||
|
|
||||||
|
Kandydatów wychodzi 101, łącznie ~12 tys. przypisań, i lista jest na tyle krótka, że
|
||||||
|
została **przejrzana ręcznie**. Stąd `_JEDNAK_LUDZIE`: słownik trafia też w prawdziwe
|
||||||
|
osoby o „opisowych" pseudonimach.
|
||||||
|
|
||||||
|
Uruchomienie (kontener worker):
|
||||||
|
python -m scripts.prune_category_performers # dry-run
|
||||||
|
python -m scripts.prune_category_performers --yes # wykonaj
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
|
from sqlalchemy import text
|
||||||
|
|
||||||
|
from app.db import session_scope
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
#: Słowa opisujące TREŚĆ, nie osobę. Świadomie bez imion i nazwisk.
|
||||||
|
_SLOWA_KATEGORII = set(
|
||||||
|
"""
|
||||||
|
anal ass tits boobs cock dick pussy cum cumshot creampie blowjob handjob footjob
|
||||||
|
milf teen mature granny mom stepmom stepsis sister brother wife girlfriend
|
||||||
|
black white asian latina ebony indian arab russian czech japanese korean thai
|
||||||
|
big small huge tiny massive giant thick fat skinny petite busty curvy
|
||||||
|
hardcore softcore rough gentle deep double triple first best hot sexy horny nasty
|
||||||
|
lesbian gay straight bi trans shemale ladyboy
|
||||||
|
fuck fucking fucked sex porn xxx video clip scene movie
|
||||||
|
blonde brunette redhead ginger
|
||||||
|
threesome foursome gangbang orgy bukkake facial swallow
|
||||||
|
squirt squirting shower golden piss pee
|
||||||
|
bdsm bondage domination submission fetish kink
|
||||||
|
natural fake real amateur pro professional
|
||||||
|
queen king lover girl boy babe slut whore bitch
|
||||||
|
pov casting audition massage yoga gym office nurse teacher student
|
||||||
|
young old
|
||||||
|
""".split()
|
||||||
|
)
|
||||||
|
|
||||||
|
#: Wyjątki znalezione przy ręcznym przeglądzie 101 kandydatów. To PRAWDZIWE osoby,
|
||||||
|
#: które mają pecha do pseudonimu:
|
||||||
|
#: „Dick Nasty" — refy z SZEŚCIU źródeł, w tym StashDB; realny męski performer,
|
||||||
|
#: widziany w obsadzie „Sugar Daddy 17" obok Dave'a Cummingsa.
|
||||||
|
#: „King Cock" — cztery źródła i niejednoznaczne sceny; wykluczony z ostrożności,
|
||||||
|
#: bo koszt błędu (skasowanie realnej osoby) jest wyższy niż zysk.
|
||||||
|
_JEDNAK_LUDZIE = frozenset({"dick nasty", "king cock"})
|
||||||
|
|
||||||
|
|
||||||
|
def _norm(s: str | None) -> str:
|
||||||
|
return re.sub(r"[^a-z0-9]+", " ", (s or "").lower()).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def _kandydaci(session) -> list[tuple]:
|
||||||
|
out = []
|
||||||
|
for pid, nm in session.execute(
|
||||||
|
text("SELECT id, canonical_name FROM performers")
|
||||||
|
).all():
|
||||||
|
n = _norm(nm)
|
||||||
|
toks = n.split()
|
||||||
|
if len(toks) < 2 or n in _JEDNAK_LUDZIE:
|
||||||
|
continue
|
||||||
|
if all(t in _SLOWA_KATEGORII for t in toks):
|
||||||
|
out.append((pid, nm))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def run(*, apply: bool) -> dict[str, int]:
|
||||||
|
with session_scope() as session:
|
||||||
|
kand = _kandydaci(session)
|
||||||
|
ids = [k[0] for k in kand]
|
||||||
|
if not ids:
|
||||||
|
print("brak kandydatow")
|
||||||
|
return {"performers": 0, "attributions": 0}
|
||||||
|
|
||||||
|
n = session.execute(
|
||||||
|
text(
|
||||||
|
"SELECT count(*) FROM scene_performers WHERE performer_id = ANY(:ids)"
|
||||||
|
),
|
||||||
|
{"ids": ids},
|
||||||
|
).scalar_one()
|
||||||
|
print(f"kategorii: {len(kand)} | ich przypisan: {n}")
|
||||||
|
|
||||||
|
if not apply:
|
||||||
|
for _pid, nm in sorted(kand, key=lambda x: x[1])[:12]:
|
||||||
|
print(f" {nm}")
|
||||||
|
print(" ... (dry-run)")
|
||||||
|
return {"performers": len(kand), "attributions": int(n)}
|
||||||
|
|
||||||
|
# Archiwum przed kasowaniem, ta sama tabela co reszta sprzatania.
|
||||||
|
session.execute(
|
||||||
|
text(
|
||||||
|
"""
|
||||||
|
INSERT INTO scene_performers_pruned
|
||||||
|
(scene_id, performer_id, source_id, performer_name, scene_title)
|
||||||
|
SELECT sp.scene_id, sp.performer_id, sp.source_id, p.canonical_name, s.title
|
||||||
|
FROM scene_performers sp
|
||||||
|
JOIN performers p ON p.id = sp.performer_id
|
||||||
|
JOIN scenes s ON s.id = sp.scene_id
|
||||||
|
WHERE sp.performer_id = ANY(:ids)
|
||||||
|
ON CONFLICT DO NOTHING
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
{"ids": ids},
|
||||||
|
)
|
||||||
|
deleted = session.execute(
|
||||||
|
text("DELETE FROM scene_performers WHERE performer_id = ANY(:ids)"),
|
||||||
|
{"ids": ids},
|
||||||
|
).rowcount
|
||||||
|
# Same rekordy performerow ZOSTAJA (scene_count spadnie do 0 przy najblizszym
|
||||||
|
# `refresh_taxonomy_counts`, wiec i tak wypadna z list z `only_with_content`).
|
||||||
|
# Kasowanie rekordu zerwaloby refy kanoniczne, a tego nie chcemy przy czyms,
|
||||||
|
# co TPDB u siebie trzyma jako performera.
|
||||||
|
print(f"zdjeto {deleted} przypisan od {len(kand)} kategorii")
|
||||||
|
return {"performers": len(kand), "attributions": int(deleted or 0)}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--yes", action="store_true", help="wykonaj (bez tego dry-run)")
|
||||||
|
run(apply=ap.parse_args().yes)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Add table
Reference in a new issue