From f97369a7642635f3e3f87bb09eb5c612ad3ecba4 Mon Sep 17 00:00:00 2001 From: goon-foss Date: Tue, 21 Jul 2026 15:50:49 +0200 Subject: [PATCH] fix(scenes): filter junk 'performers' from similar-scene matching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kategorie/studia podszywające się pod performera (over-attribution z luźnego tube-searcha: 'Big Tits', 'Brazzers', 'Ball Licking') zaśmiecały ranking similar — klastrował po nich zamiast po treści. Odsiew: slug performera pokrywa się z tagiem I brak kanonicznego refa (tpdb/stashdb). Prawdziwi performerzy z tym samym tagiem mają kanoniczny ref → zostają (Jax Slayher/Angela White OK). Scena z samymi śmieciowymi performerami spada na tag-matching (i pusto gdy ma tylko mega-tag). --- app/api/scenes.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/app/api/scenes.py b/app/api/scenes.py index 580c5bb..ee5de79 100644 --- a/app/api/scenes.py +++ b/app/api/scenes.py @@ -26,7 +26,7 @@ from app.api.schemas import ( from app.db import get_session from app.api.device import LEGACY_DEVICE, get_device_id from app.models.favorite_scene import FavoriteScene -from app.models.performer import Performer +from app.models.performer import Performer, PerformerExternalRef from app.models.play_progress import ScenePlayProgress from app.models.playback_source import PlaybackSource from app.models.scene import Scene, SceneExternalRef, ScenePerformer, SceneTag @@ -526,6 +526,31 @@ def similar_scenes( perf_ids = session.execute( select(ScenePerformer.performer_id).where(ScenePerformer.scene_id == scene_id) ).scalars().all() + # Odsiej ŚMIECIOWYCH performerów: kategorie/studia podszywające się pod performera + # (over-attribution z luźnego tube-searcha — np. "Big Tits", "Brazzers", "Ball Licking"). + # Sygnał: slug pokrywa się z tagiem I performer NIE ma kanonicznego refa (tpdb/stashdb). + # Prawdziwi performerzy z tym samym tagiem (tuby tagują sceny nazwiskiem) mają kanoniczny + # ref → zostają. Bez tego similar klastrował się po "Ball Licking" zamiast po treści. + if perf_ids: + junk = set( + session.execute( + select(Performer.id).where( + Performer.id.in_(perf_ids), + exists(select(1).select_from(Tag).where(Tag.slug == Performer.slug)), + ~exists( + select(1) + .select_from(PerformerExternalRef) + .join(Source, Source.id == PerformerExternalRef.source_id) + .where( + PerformerExternalRef.performer_id == Performer.id, + Source.kind.in_([SourceKind.tpdb, SourceKind.stashdb]), + ) + ), + ) + ).scalars().all() + ) + if junk: + perf_ids = [p for p in perf_ids if p not in junk] tag_ids = session.execute( select(SceneTag.tag_id).where(SceneTag.scene_id == scene_id) ).scalars().all()