goon/app/verticals.py
goon-foss ff898b0783 feat(verticals): animacja odgrodzona od glownego feedu + filmy na ekranie studia
1. WERTYKALY. Hentai i 3D szly do glownego feedu wymieszane z zachodnim
katalogiem, mimo ze argument za odgrodzeniem byl ten sam co przy JAV.
Zamiast drugiej kopii mechanizmu JAV wprowadzam wspolne pojecie wertykalu
(app/verticals.py): mapa nazwa -> originy, jeden predykat, `?vertical=`.

Brama po originie jest DOKLADNA, zmierzone: 9507 scen animowanych, ZERO
z originem spoza listy (nie maja sie z czym zdeduplikowac). Dlatego osobna
baza nie jest potrzebna, rozdzielam logicznie.

Tagi to samodzielny powod: z 3116 tagow przy scenach animowanych tylko 452
wystepuja tez poza animacja, czyli 85% to slownictwo wylacznie animacyjne.
`/tags?vertical=` liczy je NA ZYWO (male zbiory, zero migracji), a
zdenormalizowany Tag.scene_count opisuje juz WYLACZNIE glowny feed.

Przy okazji naprawione zasmiecenie JAV-em istniejace od lipca:
taxonomy_counts wliczal wertykaly do licznikow, ktore opisuja feed ich
nie pokazujacy. Refresh: 1476 tagow, 1402 performerow, 154 studia.

Stary `?jav=true` DZIALA dalej (instalacje sprzed sierpnia go wysylaja).

2. FILMY NA EKRANIE STUDIA. Zgloszenie: polubione studio od filmow nie
pokazuje nowych filmow i nie ma "+1". Backend liczyl je poprawnie
(_merged_new_counts scala sceny i filmy od 2026-07-28). Blad byl w apce:
tap na ulubione studio ZEROWAL licznik (markStudioSeen) i wchodzil na
ekran wylacznie ze scenami, wiec "+N" z nowych filmow znikalo, a filmy
nie mialy sie gdzie pokazac. StudioMoviesScreen istnial, ale wchodzilo
sie do niego tylko z detalu filmu. StudioScenes dostaje zakladki
Scenes/Movies, jak PerformerScenes.

Pasek zakladek w headerze przewija sie w poziomie, bo piata pozycja
(Anime) nie miescila sie na waskich telefonach.
2026-08-13 10:31:54 +02:00

57 lines
2.4 KiB
Python

"""Wertykały: treść, która żyje w osobnej sekcji apki, nie w głównym feedzie.
Wertykał to zbiór originów, których treść **nie miesza się** z zachodnim katalogiem:
osobny namespace tytułów, osobne słownictwo tagów, brak dedupu między wertykałem
a resztą. Dlatego nie chcemy ich w jednym strumieniu, tak samo jak nie chcemy
mieszać JAV z zachodnimi scenami.
**Dlaczego brama po originie jest pewna, a nie heurystyczna.** Scena z wertykału ma
WYŁĄCZNIE originy tego wertykału, bo nie ma się z czym zdeduplikować. Zmierzone
2026-08-13: 9507 scen animowanych, **zero** z originem spoza listy. To znaczy, że
`EXISTS(origin IN ...)` dzieli katalog dokładnie, bez fałszywych trafień w obie strony.
**Dlaczego nie osobna baza.** Rozważane i odrzucone 2026-08-13: skoro rozdzielenie po
originie jest dokładne, osobna baza kosztowałaby rozjazd migracji, backupów i wspólnych
tabel performerów/tagów/dedupu, nie dając nic ponad to, co daje ta lista.
**Tagi to samodzielny powód rozdzielenia.** Z 3116 tagów występujących przy scenach
animowanych tylko 452 pojawiają się też poza animacją, czyli **85% to słownictwo
wyłącznie animacyjne** (nazwy postaci, serie, gatunki rysunkowe). Bez rozdzielenia
lista tagów w głównym feedzie ciągnie 2664 pozycje, których nie da się tam użyć.
"""
from __future__ import annotations
#: JAV: kody typu BKD-368, tytuły po japońsku. Osobna zakładka od 2026-07.
JAV_ORIGINS = (
"tube:javflix",
"tube:javguru",
"tube:vjav",
"tube:supjav",
)
#: Hentai i 3D. Dla animacji nie istnieje kanon (TPDB/StashDB nie mają rysowanych
#: postaci), więc te sceny nie mają obsady i nigdy nie zmatchują się z zachodnimi.
ANIMATION_ORIGINS = (
"tube:hentaimama",
"tube:xanimeporn",
"tube:hentaigasm",
"tube:hentaiplay",
"tube:rule34video",
"tube:naughtymachinima",
)
#: Nazwa wertykału → originy. Klucze są częścią kontraktu API (`?vertical=`).
VERTICALS: dict[str, tuple[str, ...]] = {
"jav": JAV_ORIGINS,
"animation": ANIMATION_ORIGINS,
}
#: Wszystko, co ma NIE wchodzić do głównego feedu.
ALL_VERTICAL_ORIGINS: tuple[str, ...] = JAV_ORIGINS + ANIMATION_ORIGINS
def origins_for(vertical: str | None) -> tuple[str, ...]:
"""Originy wertykału. `None` → wszystkie originy wertykałowe (do wykluczania)."""
if vertical is None:
return ALL_VERTICAL_ORIGINS
return VERTICALS.get(vertical, ())