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