1745 wystapien w 291 plikach (backend, scripts, mobile). Dominowal jeden ksztalt, ' — ' laczace zdania, wiec poszedl przecinek; myslnik otwierajacy mysl zdjety; zakresy 0–5 i A–Z na dywiz. Podzial komentarz/kod robil skaner stanow, nie regex, zeby nie ruszyc myslnika stojacego w stringu albo w wyrazeniu regularnym. Potwierdzone maszynowo: po wycieciu komentarzy z wersji HEAD i z dysku obie sa identyczne we wszystkich 291 plikach, czyli poza komentarzami nie zmienilo sie nic. 233 pliki .py parsuja sie bez bledu, tsc ma te same 11 bledow w tych samych 3 plikach co przed zmiana. Dwie rzeczy wymagaly poprawki po automacie: wyrownane listy definicji, gdzie myslnik byl separatorem kolumny (37 miejsc, kolumna przywrocona), i trzy przeniesienia mysli do nowej linii, gdzie zostawal wiszacy przecinek na poczatku (poprawione recznie). Bundla nie republikuje: Hermes i tak nie niesie komentarzy, wiec dla uzytkownika to zero zmiany. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
65 lines
2.6 KiB
Python
65 lines
2.6 KiB
Python
"""Wykrywanie i czyszczenie zdegenerowanych phashy.
|
|
|
|
Phash identyfikuje scenę tylko wtedy, gdy miniaturka pokazuje treść sceny. Gdy tube
|
|
serwuje zaślepkę, czarną klatkę albo wspólne intro studia, ta sama wartość ląduje
|
|
przy setkach niepowiązanych scen i przestaje cokolwiek znaczyć, a `find_by_phash_within`
|
|
bierze najbliższą wartość z CAŁEJ tabeli, więc taki wpis jest czystym szumem.
|
|
|
|
Próg `min_scenes=10` wynika z rozkładu zmierzonego 2026-07-27: 11 000 wartości
|
|
występowało przy dokładnie 2 scenach (to realne duplikaty, chcemy je zachować),
|
|
1346 przy 3-9, a dopiero od 10 w górę zaczynają się grupy, w których liczba różnych
|
|
tytułów równa się liczbie scen, czyli nic ich nie łączy poza obrazkiem.
|
|
|
|
Kolejność ma znaczenie: najpierw `refresh` (zapisz wartości na stałe), potem `purge`
|
|
(skasuj wiersze). Odwrotnie skasowalibyśmy dowody i blacklista wyszłaby pusta.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from sqlalchemy import text
|
|
from sqlalchemy.orm import Session
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
DEFAULT_MIN_SCENES = 10
|
|
|
|
_REFRESH_SQL = """
|
|
INSERT INTO phash_blacklist (value, scene_count)
|
|
SELECT value, count(DISTINCT scene_id)
|
|
FROM scene_fingerprints
|
|
WHERE kind = 'phash'
|
|
GROUP BY value
|
|
HAVING count(DISTINCT scene_id) >= :min_scenes
|
|
ON CONFLICT (value) DO UPDATE SET scene_count = EXCLUDED.scene_count
|
|
"""
|
|
|
|
_PURGE_SQL = """
|
|
DELETE FROM scene_fingerprints f
|
|
USING phash_blacklist b
|
|
WHERE f.kind = 'phash' AND f.value = b.value
|
|
"""
|
|
|
|
|
|
def refresh_phash_blacklist(session: Session, *, min_scenes: int = DEFAULT_MIN_SCENES) -> int:
|
|
"""Dopisz do blacklisty wartości dzielone przez ≥min_scenes scen. Zwraca rozmiar
|
|
blacklisty po odświeżeniu (wpisy raz dodane NIE znikają, o to chodzi)."""
|
|
session.execute(text(_REFRESH_SQL), {"min_scenes": min_scenes})
|
|
return int(session.execute(text("SELECT count(*) FROM phash_blacklist")).scalar_one())
|
|
|
|
|
|
def purge_blacklisted_fingerprints(session: Session) -> int:
|
|
"""Skasuj wiersze `scene_fingerprints` o zablacklistowanej wartości. Zwraca liczbę
|
|
skasowanych. Sceny zostają nietknięte, znika tylko bezużyteczny odcisk."""
|
|
return int(session.execute(text(_PURGE_SQL)).rowcount or 0)
|
|
|
|
|
|
def run_phash_blacklist(*, min_scenes: int = DEFAULT_MIN_SCENES) -> dict[str, int]:
|
|
from app.db import session_scope
|
|
|
|
with session_scope() as session:
|
|
size = refresh_phash_blacklist(session, min_scenes=min_scenes)
|
|
purged = purge_blacklisted_fingerprints(session)
|
|
session.commit()
|
|
log.info("phash blacklist: %d wartości na liście, skasowano %d odcisków", size, purged)
|
|
return {"blacklist_size": size, "purged": purged}
|