goon/app/models/__init__.py
goon-foss a16883d2f3 feat(dedup): backfill phasha z zapisanych miniaturek
Root cause zgloszenia 9d272101 ("5 duplikatow, czemu nie zmergowane?"):
phash mialo tylko 37,8% grywalnych scen. Licza go WYLACZNIE niektore
konektory w momencie ingestu, wiec najwieksze zrodla maja miniaturke dla
~100% scen, a odcisk dla 1-2% (xvideos 1,8%, xnxx 1,4%, eporner 1,0%).
Material jest zapisany, brakowalo tylko obliczenia.

W zglaszanym przypadku 7 wierszy o identycznej dlugosci 2324 s, a dwa
kafelki z IDENTYCZNA okladka nie mialy phasha wcale, wiec jedyny sygnal,
ktory by je sklail, nigdy nie powstal.

Zakres CELOWANY, nie caly katalog: sceny w klastrze (performer, dokladna
dlugosc) o licznosci >1, bez phasha, ale z zapisana miniaturka = 238 704
pozycje (wobec ~1,4 mln scen bez phasha). Reszta nie ma sie z czym skleic.

Kolejka jako TABELA, nie zapytanie w locie: wyznaczenie kandydatow to
ciezki agregat po calym katalogu, ktorego nie chcemy powtarzac przy kazdej
paczce, a kolejka przezywa restart workera i widac z niej postep.

Weryfikacja end-to-end na zglaszanej scenie: ce81a110 dostal phash
85c1bac2f8c60ecf, czyli DOKLADNIE ten sam, ktory mial juz 8373bbb5 (dwa
z kafelkow uzytkownika) -> istniejacy phash_exact je teraz sklei.

Nie zapisujemy wartosci z phash_blacklist (zaslepki dzielone przez setki
scen). Throttling swiadomy: 800 co 15 min, ~3 dni na nadrobienie.

Dwie pulapki SQL zapisane w kodzie: `referer` ma 255 znakow wiec origin
wycinamy w SQL (pelny page_url wywalal planowanie), a rzutowanie musi isc
przez CAST() bo text() SQLAlchemy nie podstawia parametru za ktorym stoi
`::`.
2026-08-13 10:49:12 +02:00

75 lines
2.2 KiB
Python

from app.models.base import Base
from app.models.blacklist import BlacklistedPerformer, BlacklistedStudio, BlacklistedTag
from app.models.bug_report import BugReport
from app.models.external_record import ExternalRecord
from app.models.favorite_movie import FavoriteMovie
from app.models.favorite_performer import FavoritePerformer
from app.models.favorite_scene import FavoriteScene
from app.models.favorite_studio import FavoriteStudio
from app.models.ingest_run import IngestRun
from app.models.merge_candidate import MergeCandidate
from app.models.movie import (
Movie,
MovieChapter,
MovieExternalRef,
MoviePerformer,
MovieTag,
)
from app.models.movie_playback_source import MoviePlaybackSource
from app.models.performer import Performer, PerformerAlias, PerformerExternalRef
from app.models.play_progress import MoviePlayProgress, ScenePlayProgress
from app.models.playback_event import PlaybackEvent
from app.models.playback_source import PlaybackSource
from app.models.phash_backfill_queue import PhashBackfillQueue
from app.models.phash_blacklist import PhashBlacklist
from app.models.saved_search import SavedSearch
from app.models.source_stats import SourceStats
from app.models.scene import (
Scene,
SceneExternalRef,
SceneFingerprint,
ScenePerformer,
SceneTag,
)
from app.models.source import Source
from app.models.studio import Studio, StudioAlias, StudioExternalRef
from app.models.tag import Tag
__all__ = [
"Base",
"BlacklistedPerformer",
"BlacklistedStudio",
"BlacklistedTag",
"BugReport",
"ExternalRecord",
"FavoriteMovie",
"FavoritePerformer",
"FavoriteScene",
"FavoriteStudio",
"IngestRun",
"MergeCandidate",
"Movie",
"MovieChapter",
"MovieExternalRef",
"MoviePerformer",
"MoviePlaybackSource",
"MovieTag",
"Performer",
"PerformerAlias",
"PerformerExternalRef",
"MoviePlayProgress",
"ScenePlayProgress",
"PlaybackSource",
"PhashBlacklist",
"SavedSearch",
"Scene",
"SceneExternalRef",
"SceneFingerprint",
"ScenePerformer",
"SceneTag",
"Source",
"Studio",
"StudioAlias",
"StudioExternalRef",
"Tag",
]