Commit graph

282 commits

Author SHA1 Message Date
goon-foss
7e48cdee06 fix(clips): wyscig przy pierwszym zapisie afinicznosci urzadzenia
Onboarding Edge i zdarzenia z pierwszych klipow przychodza naraz, oba
widzialy brak wiersza clip_affinity i oba robily INSERT, drugi konczyl sie
UniqueViolation i bledem 500 (GOON-7X). Pusty wiersz przez ON CONFLICT DO
NOTHING, potem odczyt z blokada i dodanie naszych przyrostow do tego, co
zapisalo rownolegle zadanie. Test z dwoma watkami: bez bledow, obie wagi.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:52:54 +02:00
goon-foss
8971d81ef9 fix(clips): skasowany klip uruchamia sprawdzenie reszty klipow tworcy
Tworcy kasuja zwykle cale konto naraz, a przemial przy 1000 klipow na
godzine robi okrazenie katalogu w okolo tydzien. Zgloszenie d343a9b6:
strona tworcy z pustymi kafelkami, 120 "zywych" klipow, kazdy 403.
Po oznaczeniu martwego klipu (przemial albo zgloszenie z apki) od razu
HEAD na pozostalych zywych klipach tego tworcy niesprawdzanych od 6 h,
do 600 na przebieg. Sprawdzone na produkcji: 120 z 120 oznaczone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:38:54 +02:00
goon-foss
edf9e8a39f fix(proxy): okcdn odrzuca obcy Origin, ponowienie bez niego
_build_headers dokleja Origin zawsze, gdy znamy Referer. okcdn (OK.ru,
porndupe) na ten sam adres z Refererem daje 206, a z Refererem i Originem
400, wiec kazdy zapasowy proxy porndupe konczyl sie 502 (120 bledow 502
w tydzien). Przy 400 jedno ponowienie bez Origin; zwykly <video> w
przegladarce i tak go nie wysyla.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 15:04:14 +02:00
goon-foss
ba53f872d2 fix(proxy): hdporn.gg i fullmovies, swiezy adres zamiast 410 w zapasowym proxy
get_file jest przypiety do IP i sesji ladujacej strone i bywa jednorazowy.
Gdy resolver na telefonie zawiodl, proxy dostawalo ten sam zuzyty adres i
oddawalo 410/503: 14 urzadzen w tydzien mialo na tych serwisach same porazki
(inne serwisy graly im bez problemu). Teraz po 403/404/410 albo trwalym 503
proxy pobiera strone na nowo (try_extract) i bierze adres w tej samej jakosci.
Test: adres pobrany z innego IP przez proxy 410 -> z odswiezaniem 206 video/mp4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 14:16:14 +02:00
goon-foss
0f128d2e17 feat(playback): zgloszenie 404/410 z telefonu sprawdzane z serwera
Zrodlo znikalo tylko po dlugim przytrzymaniu przez uzytkownika. Teraz
zgloszenie "Response code: 404/410" uruchamia w tle ponowny resolve z serwera;
martwe dopiero, gdy ekstraktor mowi "usuniete" albo plik z serwera tez daje
404/410 (dwie kontrole). Na sucho na 84 parach z 14 dni: 0 martwych, 83 zywe,
czyli 410 z telefonu prawie zawsze znaczy zly adres, nie skasowany plik.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 14:16:14 +02:00
goon-foss
b0645f625a fix(movies): streamporn.li, nowy uklad mangoporn i yourdailypornmovies
Trzy zrodla filmow od tygodnia nie dawaly nic, a watchdog widzial tylko
"brak nowych":
- streamporn.vip -> 302 streamporn.li; konektor odrzuca linki spoza swojej
  domeny, wiec lista byla pusta. Id filmu to slug, domena nie robi duplikatow.
- mangoporn: /movies/ daje 404, lista z /page/N/; link ma class przed href,
  tytul w golym <h1> (zapas po itemprop i class="data"); limit 75 s, strona
  odpowiada z VPS po 30-60 s.
- yourdailypornmovies: nowe linie miedzy znacznikami karty, wzorzec bez \s*
  nie lapal nic przy dzialajacej stronie.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 13:50:34 +02:00
goon-foss
4666fcb04a feat(edge): nowa punktacja feedu z historii klipu u nas, 25% w grupie kontrolnej
Odtworzenie uczenia na 189 tys. zdarzen (wagi zdarzenie po zdarzeniu, bez
zagladania w przyszlosc, test na 30% najnowszych): stara punktacja porzadkowala
klipy w obrebie urzadzenia z AUC 0,576 (lajk albo >= 10 s vs ucieczka < 2 s).
Tagi RedGifs sa liczne i ogolne, wiec ich suma dominowala, a mowila malo; nisze
prawie nic, popularnosc z RedGifs slabo, tworca i przyjecie klipu u nas najwiecej.

Nowa: log(waga tagu x rzadkosc tagu) + 0,25 log(nisze) + 2,5 log(tworca)
+ 0,8 ln(1+lajki RedGifs) + 120 (odsetek lajkow u nas - 3%) - 15 (odsetek
ucieczek - 50%) + 0,3 za swiezosc. Na tescie 0,652, regresja na tych samych
cechach 0,654. Liczniki clips.feed_views/skips/likes (migracja 0052, wypelnione
z historii), bumpowane w POST /clips/events. 25% urzadzen (hash id) zostaje na
starej punktacji do porownania na zywym ruchu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 11:47:02 +02:00
goon-foss
617dda0bbe fix(player): myvidplay/playmogo/doply graja natywnie, bez WebView
Some checks are pending
Backend tests / test (push) Waiting to run
Szablon playera playmogo zawsze zawiera ukryty (d-none) blok "Not Found",
a resolver bral te slowa za usuniety film i poddawal sie od razu, wiec cala
rodzina DoodStream szla do WebView z klikanym Cloudflare. pass_md5 jest w
HTML, a adres gra bez weryfikacji. Teraz usuniety = tytul "not found" albo
widoczny blok. Sprawdzone na emulatorze: ExoPlayer, ttff 4,2 s, postep rosnie.
Bledy cichego resolvera ida do telemetrii (error_kind 'resolver'), poza ocena
zrodel. Wpis changelogu dla OTA d5906704.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 11:30:51 +02:00
goon-foss
8753243e15 fix(edge): skasowany klip nie zostawia czarnego ekranu
Klip skasowany u zrodla daje 403 i na wideo, i na plakacie, a apka nic z tym
nie robila. Teraz odtwarzacz zglasza zdarzenie 'error' (i 'stall' po 12 s bez
obrazu), przy 403/404/410 przewija dalej (max 3 z rzedu, bledy sieci i TLS nie
przewijaja), a serwer od razu sprawdza plik i oznacza klip martwy. Reaper co
godzine po 1000 klipow zamiast 2000 na dobe: ~4% zywych klipow w feedzie
zwracalo juz 403. Zejscie z zepsutego klipu nie psuje wag jako "skip".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 11:30:50 +02:00
goon-foss
92f83b93fe feat(favorites): ulubione z nowosciami na gorze, osobno nowe sceny i filmy
Zgloszenie 5a724cc8: aktorki i studia z "+N" grupowane u gory listy, a znaczek
rozbity na sceny i filmy (new_scene_count, new_movie_count). new_count zostaje
jako suma dla starszych wersji apki, ktore dostaja tez nowa kolejnosc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 11:30:50 +02:00
goon-foss
27309d24f2 fix(movies): kolejka wzbogacania z TPDB pamieta, co juz sprawdzila
Zadanie (co 6 h po 200) bralo zawsze 200 najnowszych kandydatow. Przebieg
o 05:00 wzbogacal 14-19 swiezych filmow, trzy kolejne mielily te same 200
bez trafienia z wynikiem zero, a 12,9 tys. starszych kandydatow nie bylo
sprawdzonych ani razu. Teraz movies.tpdb_checked_at (migracja 0051): najpierw
niesprawdzone, film bez trafienia wraca po 30 dniach, blad nie oznacza.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 20:39:12 +02:00
goon-foss
8f8bb1c448 fix(tags): tag_vertical_counts bez klucza obcego, koniec zakleszczenia o 05:00
Refresh licznikow (co 3 h) i tag_tail_trim (raz dziennie) startuja razem
o 05:00. Kasowanie osieroconych tagow schodzilo kaskada do
tag_vertical_counts i czekalo na refresh, a refresh przy wstawianiu czekal
na blokade tego samego tagu przez sprawdzenie klucza obcego. Od 29.09
Postgres co rano zabijal przycinanie (Sentry GOON-7N). Tabela to kopia
liczona od zera, wiec klucz obcy nie byl potrzebny (migracja 0050).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 20:24:42 +02:00
goon-foss
77679b26bb perf(scenes): lista serwisu od najnowszych prosto z indeksu
Some checks failed
Backend tests / test (push) Has been cancelled
Ekran serwisu (/scenes?origin=tube:X&sort=release_date) dla serwisow,
ktorych scen nie ma wsrod najnowszych w katalogu (perverzija, hdporn.gg,
tubepornclassic, yesporn), sortowal wszystkie ich sceny: 9-19 s na
zimnym cache, 1-4 s na cieplym, 39 wejsc w 3 h.

Wzorem scene_tags.sort_date (GOON-64): data sortu powielona w
playback_sources i pilnowana wyzwalaczami (0048), wypelniona skryptem,
indeks (origin, sort_date DESC, scene_id DESC) WHERE dead_at IS NULL
(0049). API dolacza DISTINCT ON zgodny z indeksem, bo 190 tys. scen ma
dwa zywe zrodla z tego samego serwisu. Po zmianie 0,03-0,24 s, takze
dalsze strony.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:18:59 +02:00
goon-foss
c97af57979 perf(tags): liczniki tagow JAV i animacji liczone w tle
/tags?vertical=jav liczyl agregat po zrodlach i scene_tags na kazde
wejscie, dwa razy: 1 s na rozgrzanym cache, 17-24 s na zimnym. Teraz
czyta tabele tag_vertical_counts (migracja 0047), ktora odswieza
refresh_taxonomy_counts co 3 h. Zakladka JAV: 0,35 s. Gdy tabela jest
pusta dla wertykalu, zostaje stary agregat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 19:37:23 +02:00
goon-foss
494b15aedd fix(siska): kafelki z apostrofem w tytule i kilka osob w jednym nazwisku
Some checks are pending
Backend tests / test (push) Waiting to run
Strona nie escapuje apostrofu w title/alt, wiec "Brenna's Mouths" urywal
dopasowanie i kafelek wypadal (3 z 18 na stronie). Pierwszy czlon alt z
kilkoma osobami ("A, B - Tytul") szedl jako jeden wykonawca.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 19:14:47 +02:00
goon-foss
9225ae95de fix(scrapers): krotka nazwa wykonawcy nie przypina go do wszystkich wynikow
Bramka nazwy w slugu zwracala True, gdy zaden czlon nazwy nie mial 3 znakow ("Wa A",
"Al B", "T P"), a wolajacy pomijali ja przy pustych tokenach. Performer-driven
dopinal wiec takiego wykonawce do kazdego wyniku wyszukiwarki tuba: 108 wykonawcow,
10,5 tys. blednych przypisan w 7,9 tys. scen. Teraz takie nazwy nic nie dopasowuja.
Na produkcji bledne przypisania usuniete (kopia w scene_performers_removed_20260924).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 13:03:11 +02:00
goon-foss
b64ddfd742 fix(hqporner): okladka z kafelka listingu, nie cudza ze strony filmu
Strona filmu hqporner nie ma wlasnej okladki, a pierwszy _main.jpg na niej to kafelek
polecanego filmu. Scraper go bral, wiec ~90% zrodel dostalo cudze miniatury (62 tys.
zrodel, 5,4 tys. roznych miniatur). Okladka jest tylko w kafelku listingu
(cover_<id>): browse zbiera je z listingu, wyszukiwarka z wynikow wyszukiwania.
scripts/hqporner_fix_thumbs.py poprawia zapisane miniatury przechodzac listing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 12:58:41 +02:00
goon-foss
2a2c0d7e9d fix(api): bez planow ogolnych i szybkie listy serwisow, ktore stoja
Some checks failed
Backend tests / test (push) Has been cancelled
- db: prepare_threshold=None. psycopg przygotowywal zapytanie po 5 wykonaniach na
  polaczeniu, a Postgres przechodzil potem na plan ogolny. Lista duzego tagu na takim
  planie: "pov" 44 s zamiast 0,46 s, "masturbation" 46 s zamiast 0,18 s. Stad listy
  ladowaly sie raz szybko, raz minute, zaleznie od polaczenia z puli (tez GOON-73/75).
- Lista jednego serwisu bez frazy: przejscie od najnowszych z limitem 1 s, a po nim
  start od scen serwisu (do 150 tys.). Serwis, ktory stoi, mial sceny gleboko:
  superporn 72-92 s -> 1,7 s, yespornvip 15 s -> 1,5 s, hentaiplay 9 s -> 0,06 s.

Porownanie ze starym kodem na 88 listach serwisow: wyniki identyczne przy
zapytaniach puszczonych po sobie.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 09:45:05 +02:00
goon-foss
3349700f72 fix(api): szukanie w serwisie i sortowanie po studiu z rzadka fraza
Some checks are pending
Backend tests / test (push) Waiting to run
- Szukanie w jednym serwisie do 60 tys. scen zaczyna od jego scen (scenes.id = ANY),
  gdy fraza jest popularna albo bez trigramu: "sel" w hqporner 3,4 s -> 0,1 s, "brat"
  w fullmoviesxxx 2,9 s -> 0,15 s. Rzadkie frazy dalej trigramami (GOON-75).
- Poprawka regresji z c08abf6: fraza bez trigramu przy zawezeniu po 3 s oddawala
  pusta liste ("ai" w fullmoviesxxx: 0 wynikow). Teraz od serwisu albo limit 10 s.
- sort=studio z rzadka fraza: JOIN ze studiami i sort samych trafien zamiast
  przejscia po 33 tys. studiow ("sunny leone" 928 s -> 0,26 s, "savanna" 20 s -> 0,17 s).

Porownanie ze starym kodem na 100 wyszukiwaniach w serwisach i 12 z sortem po studiu:
wyniki identyczne poza naprawionymi pustymi listami.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 17:13:39 +02:00
goon-foss
0da36d5c1e perf(tags): warianty pisowni tagow jednym zapytaniem
Some checks are pending
Backend tests / test (push) Waiting to run
enrich-tags wolal resolve_tag dla kazdej nazwy spoza slugow, a ten szukal po
alnum-kluczu i liczbie mnogiej osobnymi zapytaniami (N+1, GOON-5F). Nowe
resolve_tags_by_altkey robi to jednym IN po indeksie ix_tags_name_altkey;
_resolve_by_altkey dla jednej nazwy korzysta z niego (1 zapytanie zamiast 2).
Na 603 nazwach z produkcji wyniki identyczne, 0,77 s -> 0,03 s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 13:24:18 +02:00
goon-foss
cb9e4ab035 fix(siska): przeniesienie na siska.tv po wygasnieciu siska.video
siska.video od 2026-09-22 nie istnieje (NXDOMAIN), ten sam serwis dziala pod
siska.tv z tymi samymi videoID i sciezkami miniatur. Scraper bierze kafelki z obu
domen i z www, zapisuje jeden kanoniczny adres. Lista najnowszych jest pod
best_xvideos.php?page=N, bo /page/N/ na siska.tv zawsze oddaje strone 1.

Na produkcji adresy stron, miniatur i external_id przepisane na siska.tv
(16 007 zrodel, 16 265 powiazan scen); 103 duplikaty www.siska.video oznaczone
jako martwe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 13:18:22 +02:00
goon-foss
ed7c1cd3ed fix(movies): yourdailypornmovies gubil nowe filmy przez nowy format okladki
Od ~15.09 nowe karty maja okladke imgs4cdn.adultempire.com/movie/<id>?w=... (czesc
i.ibb.co albo bez okladki), a regex karty wymagal starego products/NN/<id>h.jpg.
33 z 40 filmow strony 1 odpadalo po cichu, ingest przez tydzien: 0 nowych.
Okladka teraz opcjonalna i w dowolnym formacie, id Adult Empire z obu wariantow.
Nadrobione: 26 nowych filmow, 6 dopietych do istniejacych.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 13:18:22 +02:00
goon-foss
45ee7a81e1 fix(api): szybkie szukanie po tytule dla popularnych i krotkich fraz
Some checks are pending
Backend tests / test (push) Waiting to run
Planer szacowal kazda fraze na 427 trafien (histogram 100 probek, dolny limit), wiec
zawsze szedl indeksem trigramow i sortowal wszystkie trafienia: "vo" 44 s (dwie
litery nie maja trigramu, indeks oddaje 4,3 mln wierszy), "mis" 6,5 s, "free" 1,9 s
(GOON-73/75).

- 0046: histogram title_normalized 1000 probek, szacunki bliskie prawdy.
- list_scenes: przy q i sorcie po dacie najpierw przejscie po indeksie sortu z
  limitem 300 ms (bez bitmap, w SAVEPOINT wycofywanym zawsze), gdy probka tytulow
  z pg_stats mowi, ze wystarczy przejsc do 30 tys. scen; inaczej zwykly plan.
  Frazy bez trigramu zawsze przejsciem (limit 3 s, potem pusto).

115 prawdziwych wyszukiwan z logow: wyniki identyczne, najgorszy 44 s -> 0,8 s,
srednie frazy dotykaja 3-7x mniej stron ("bad" 122 tys. -> 16 tys.).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:11 +02:00
goon-foss
7accd4692f fix(seo): bez prywatnych blacklist i z cache indeksu sitemapy
Blacklisty sa per urzadzenie od 2026-06-10, a SEO dalej wycinalo sume blacklist
wszystkich urzadzen: 465 osob, 4477 tagow, z publicznych stron znikalo ~86% scen.
To samo zapytanie przy liczeniu do /sitemap.xml pisalo 3,7 GB plikow tymczasowych
i przy kilku wejsciach robota naraz zapychalo dysk (GOON-22). Teraz strony SEO
pokazuja to, co katalog nowemu urzadzeniu, a indeks sitemapy liczy sie raz na 6 h
(blokada na rownolegle zadania). Liczenie 135 MB plikow tymczasowych, indeks 13 s,
potem 0,2 s. Wykonawcy 20 tys. -> 81 tys., sceny 3,5 mln.

Na VPS dodatkowo temp_file_limit=2GB dla API w override.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:11 +02:00
goon-foss
d3713d64b9 fix: source-stats z probki scen, nizsze progi autovacuum
source-stats liczyl flagi tag/obsada dla 2,5 mln par serwis-scena, czyli ok. 5 mln
losowych odczytow indeksow; trwal 22-32 min i przekroczyl limit (GOON-V). Teraz
flagi z probki 3000 scen na serwis (stala, po md5), liczba scen, swiezosc i
miniatury dalej dokladnie. 1 min 51 s, gwiazdki bez zmian, procenty +-2 pkt.

Autovacuum na domyslnych 20% nie ruszal duzych tabel od tygodni (scene_performers
11% stron widocznych, statystyki scenes z 25.08). Migracja 0045 daje 2% dla
szesciu najwiekszych tabel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:11 +02:00
goon-foss
55adf8b1cb fix(scheduler): godzina na dedup po tytule i dlugosci
Przebieg nadrabiajacy zaleglosci scalil 67 tys. scen (xnxx/xvideos, ten sam tytul, dlugosc
i obsada) i trwal 90 min, wiec przy limicie 30 min job raportowal sie jako zawieszony
(Sentry GOON-V), mimo ze pracowal. Zaleglosc wzieła sie z restartow workera, ktore ucinaly
wczesniejsze przebiegi.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:11 +02:00
goon-foss
41ad7f1818 feat: automatyczne sprzatanie martwych zrodel sxyprn i eporner
Oba serwisy kasuja filmy po cichu: strona odpowiada 200 z "Post Not Found" albo "Video has
been deleted". Probka 2026-09-19: 57% zywych w bazie zrodel sxyprn w wieku 10-40 dni i 22%
eporner bylo juz usunietych; w apce to puste kafelki i "the tube removed" po kliknieciu.

- eporner: ekstraktor rozpoznaje usunieta strone i rzuca HosterDead, wiec resolve oznacza
  zrodlo zamiast oddawac "blad chwilowy" (82 takie wejscia w 48 h, nic nie oznaczal).
- proxy miniatur: "Post Not Found" na sxyprn oznacza zrodlo od razu, 404 na miniaturze
  eporner uruchamia w tle sprawdzenie strony (28/30 takich miniatur to usuniete filmy).
  Indeks hash po thumbnail_url tylko dla eporner (0044), zeby znalezc zrodlo po obrazku.
- job dead-reap co 6 h: po 1500 zywych zrodel na serwis, polowa z ostatnich 30 dni.
  Oznacza tylko przy pewnym sygnale; siec i timeouty zostawia.

Sprawdzone na produkcji: 10/10 miniatur eporner i 23/23 postow sxyprn oznaczone, 17 zywych
postow nietknietych.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:11 +02:00
goon-foss
0edc85c05f feat(api): glowny feed bez archiwum i z limitem jednego zrodla na strone
"Newest ingest" bez filtrow pomija sceny z dociagania archiwum (backfill): deep-crawl
tubepornclassic dokladal 7,9 tys. scen z lat 2016-2018 dziennie, a xhamster/xnxx/xvideos/
sxyprn kolejne 3,3 tys., wszystkie na szczycie listy. Po odcieciu eporner (2 tys. anonimowych
uploadow dziennie) mial 121 ze 150 pozycji, wiec na pierwszych 8 stronach jedno zrodlo zajmuje
najwyzej 1/3 strony, dopoki sa inne; nadmiar zjezdza nizej, nic nie ginie. Pierwsze 3 strony:
eporner 51, xvideos 24, xnxx 20, youporn 20, pornxpph 15, fullporner 12.

Z filtrami i w sekcjach JAV/Anime bez zmian.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:11 +02:00
goon-foss
ca2a6a1547 fix: dzienny ingest filmow nie przepada o 05:00, apka nie staje na bledzie keystore
- scheduler: misfire_grace_time 1 h zamiast domyslnej 1 s. O 05:00 UTC startuje kilkanascie
  zadan naraz, movie-ingest dostawal watek 1,1 s po czasie i APScheduler go pomijal, wiec
  filmy nie przychodzily od 17.09 (watchdog, Sentry).
- getDeviceId: blad SecureStore ("Could not encrypt the value", Samsung A7, Android 10)
  wywalal kazde zapytanie do API. Teraz id zostaje w pamieci do konca sesji. Wejdzie z
  najblizsza paczka OTA.
- latka expo-modules-core 2.2.3, JNIDeallocator: watek sprzatajacy blokowal sie na sobie,
  nie na deallocatorze, stad ConcurrentModificationException przy przeladowaniu JS
  (Sentry GOON-48). Wejdzie z najblizszym APK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:11 +02:00
goon-foss
73853eb9ed perf(api): kilka tagow od najnowszych idzie po indeksie najrzadszego z nich
Z dwoma tagami (rough-sex + anal) lista szla stara droga po calym katalogu, 7,4 s na zimnym
cache. Teraz dolaczamy najrzadszy tag po ix_scene_tags_tag_sort, a reszta zostaje jako
EXISTS: 0,2 s. Dolaczona tabela ma alias, inaczej EXISTS po scene_tags korelowal sie z nia.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:11 +02:00
goon-foss
7f2fdfaed0 perf(api): lista scen jednego tagu od najnowszych po indeksie na scene_tags (GOON-64)
Ekran tagu (jeden tag, sort=release_date, 200 scen) sortowal po dacie z `scenes`, a filtrowal
po `scene_tags`. Postgres szedl od najnowszej sceny calego katalogu i kazda sprawdzal; przy
tagach rzedu 40-60 tys. scen (`rough-sex`) to 46 tys. scen na strone, 7-15 s na zimnym cache.
Dwie przebudowy samego zapytania nie pomogly (2x albo 30 s na duzych tagach), cache tez nie,
bo wejscia rozkladaja sie na setki tagow.

`scene_tags.sort_date` (0042) trzyma ta sama date co `_effective_date_desc()`, pilnowana przez
wyzwalacze w bazie, indeks (tag_id, sort_date DESC, scene_id DESC) w 0043. Wypelnianie 23 mln
wierszy: scripts/backfill_scene_tags_sort_date.py, partiami z pauza.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:11 +02:00
goon-foss
ed3a7b8f4e fix(merge): tytul z TPDB/StashDB nie przegrywa z dluzszym tytulem z tuba
Zasada "dluzszy tytul wygrywa" podmieniala czysty tytul kanoniczny na tubowy z doklejonym
studiem, obsada i data ("Milfy 26 09 16 Koda Monroe Voluptuous Therapist ..."). Pierwszy
przebieg studio_title_dedup zrobil tak z 491 scenami; tytuly przywrocone z external_records.
Teraz kanon wygrywa z tubem, a dluzszy tytul liczy sie tylko miedzy scenami tego samego rodzaju.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:10 +02:00
goon-foss
7fea132668 feat(dedup): kopie tej samej sceny z tubow o roznym formacie tytulu
Kazdy tube zapisuje tytul po swojemu ("[Milfy] Koda Monroe (...)", "Milfy 26 09 16 ...",
"... 4K"), a miniatury sa z innych klatek, wiec ani phash, ani title_duration_dedup
(identyczny tytul) ich nie lapaly. Jedna scena Milfy wisiala w katalogu 8 razy.

Nowy job porownuje rdzen tytulu w obrebie studia: bez nazwy studia, dat, znacznikow
jakosci i nazwisk obsady. Numery czesci zostaja ("Part 1" to nie "Part 2"). Straznicy:
dlugosc, data premiery, wspolna obsada, dluzszy rdzen gdy brak dlugosci. Kopie bez studia
dolaczaja tylko przy zgodnej co do 3 s dlugosci. Kategorie wpisane przez tube jako obsada
nie skracaja rdzenia. Cyklicznie co 12 h z oknem 30 dni.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:10 +02:00
goon-foss
6b06cc96bf fix(android): 0.4.2 domyka crash expo-video przy zamykaniu apki
Latka z 0.4.1 kopiowala mape sesji przed zwolnieniem playerow, ale sama kopia
tez iteruje mape, a wpisy znikaja z innego watku. Na LinkedHashMap wywalalo sie
wiec dalej, juz w toList() (Sentry GOON-6W, Redmi Note 8 Pro, Android 11).
Mapa jest teraz ConcurrentHashMap, iteracja przezyje rownolegle usuniecie.

versionCode 16 zeby posiadacze 0.4.0/0.4.1 dostali monit: runtime zostaje 1.4,
wiec sam numer kanalu ich nie rozrozni.

Sprawdzone na emulatorze: dwie sesje mediow zywe, zamkniecie z listy ostatnich
zwalnia obie, pusty bufor crashy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:10 +02:00
goon-foss
3c1d2c5907 perf(api): lista stron odswiezana w tle, nikt nie czeka na przeliczenie
Agregat po 4,1 mln zywych zrodel trwa 0,6-2 s, a cache wygasal co 5 minut, wiec co
wygasniecie ktos placil pelnym czasem (Sentry Slow DB Query list_sources, 186 zdarzen,
ostatnie dzisiaj). Teraz po wygasnieciu oddajemy stary wynik i przeliczamy w watku w tle,
a TTL idzie z 5 do 15 minut. Liczby zmieniaja sie o promile na godzine.

Pomiar na prodzie: pierwsze wejscie po restarcie 2,1 s (nieuniknione), potem 11-15 ms,
a wejscie tuz po wygasnieciu 38 ms zamiast pelnego przeliczenia.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:10 +02:00
goon-foss
c8035c68fa fix: losowanie w obrebie wynikow filtra, widoczne pobieranie aktualizacji
Zgloszenia z apki:
- „random filter on and searching titles shows few results": przy sort=random braliśmy
  okno 2000 kolejnych id (0,05% katalogu) i dopiero na nim nakladalismy filtry, wiec
  szukanie w losowej kolejnosci trafialo na garstke scen. Teraz przy aktywnym filtrze
  (szukanie, tag, obsada, studio, strona, jakosc, data, dlugosc) losujemy WYNIKI:
  md5(id + seed) nad pula do 5000 wynikow filtra. Okno po PK zostaje tylko dla listy
  bez filtra, gdzie chronilo przed skanem 2,3 mln wierszy.
- „clicking install does nothing": pobieranie 87 MB szlo bez zadnego sladu w UI. Teraz
  nakladka z kreceleem na czas pobierania, „Download" obok „Install" w monicie i link
  do pliku w komunikacie bledu (na repo git APK nie ma, user szukal go tam).

Sprawdzone: szukanie „massage" z sort=random daje pelne strony (50 + kolejna), ten sam
seed powtarza kolejnosc, strony sie nie nakladaja, inny seed inna kolejnosc; czasy 120-800
ms (tag anal 1,1 s), lista bez filtra bez zmian. Na emulatorze pelna sciezka aktualizacji
z 0.4.0: monit z trzema przyciskami, Install, pobieranie, systemowy dialog, versionCode 15.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:10 +02:00
goon-foss
7bfd194485 fix(mobile): Edge - serduszko nie rusza dzwieku ani nie przewija klipu, jeden przycisk dzwieku, stroik feedu
Zgloszenia Jana 2026-09-16:
1+3. Tapniecie serduszka przelaczalo dzwiek i przewijalo klip na poczatek. Gesty lapala
   cala komorka razem z przyciskami, wiec tap w serduszko byl tez tapem w ekran, a zmiana
   dzwieku restartowala odtwarzanie (efekt aktywacji strony mial soundOn w zaleznosciach).
   Teraz gesty lapie tylko warstwa wideo, a wyciszenie ma osobny efekt.
2. Dwa przyciski dzwieku. Zostaje ten w kolumnie przy kciuku, w gornym pasku wchodzi stroik.
4. Za malo tagow na starcie: bylo 24 z 40, „anal" (27. co do liczby klipow) wypadal.
   Teraz 60 tagow + nisze + szukanie po calym slowniku (1,7 tys. tagow, nowy param q),
   wskazanie wazy 8 zamiast 5, a stroik mozna otworzyc w kazdej chwili i zmiana dziala
   od nastepnego rozdania.
5. Losowe miganie przy przewijaniu: dociagniecie kolejnej strony feedu podmienialo tablice
   klipow i restartowalo biezacy klip. Efekt zalezy teraz od numeru strony i adresow wideo.

Sprawdzone na emulatorze: tap w serduszko zostawia wyciszenie bez zmian i zapisuje like,
przycisk dzwieku odcisza, gorny pasek otwiera stroik, szukanie „anal" daje 8 wariantow,
a po Apply w clip_affinity siedzi anal=8.0. Edge dalej odklada zdarzenia w clip_feed_events.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:10 +02:00
goon-foss
bfa3444de2 feat(mobile): strona tworcy w Edge
Tapniecie nazwy tworcy otwiera jego strone: siatka wszystkich klipow, a tapniecie
kafelka gra je na pelnym ekranie z tym samym przewijaniem w pionie co Edge.
Zgloszenie z apki 2026-09-15: "cannot tap username as it's hidden behind icon tray".

- ClipPager: pionowy pager z dwoma playerami wyjety ze SwipeScreen, wspolny dla Edge
  i strony tworcy; feed, telemetria i autoSwipe zostaly w ekranach
- /clips?creator= oddaje `total` (liczba klipow tworcy) do naglowka
- ze strony tworcy leca tylko like/unlike i "nie interesuje": ogladanie stad nie moze
  zabetonowac feedu na jednym tworcy

Sprawdzone na emulatorze: link z Edge otwiera strone (@lilylovesyou2, 2 clips, verified),
kafelki trzymaja trzecia szerokosci takze w niepelnym rzedzie, pelny ekran gra i zamyka
sie przyciskiem pod paskiem stanu, a Edge dalej odklada zdarzenia w clip_feed_events.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:09 +02:00
goon-foss
7d5dd450f7 fix(mobile): monit o nowe APK takze na tym samym kanale OTA
0.4.0 i 0.4.1 maja ten sam runtime 1.4, a monit porownywal tylko runtime, wiec nikt
z 0.4.0 nie dostal propozycji aktualizacji i crash expo-video przy zamykaniu z ostatnich
wracal do Sentry dzien po poprawce (147164135).

- /version oddaje apk_build (versionCode 15)
- aplikacja czyta versionCode ZAINSTALOWANEGO APK przez natywny modul Sentry
  (expo-constants w SDK 52 nie oddaje go wcale, expo-application wymagalby nowego APK)
- numer builda trafia tez do kontekstu zgloszen z apki: app_version jedzie z paczka OTA,
  wiec nie mowil, ktore wydanie natywne ma zglaszajacy

Sprawdzone na emulatorze: 0.4.1 nie dostaje monitu i raportuje build=15, po instalacji
0.4.0 monit "Update available" pokazuje sie przy starcie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 12:00:09 +02:00
goon-foss
2cdc3d69da perf(api): tanszy odsiew stub-scen i zwarcie sprzecznego filtra playbacku
Some checks failed
Backend tests / test (push) Has been cancelled
Trzy zmiany wokol listy scen z filtrem originu, gdzie kandydatow sa dziesiatki tysiecy.

1. Kolejnosc czlonow OR w stub_exclusion_clause. Postgres liczy OR po kolei i przerywa na
pierwszym trafieniu, a sam czlonow nie przestawia. "Ma kanon" (jedyny czlon z JOIN-em do
sources) stal przed tanszym "ma performera", wiec placilismy za niego takze za sceny,
ktore performera mialy. Po zamianie ten czlon liczy sie 5146 razy zamiast 16 191.

2. Indeks scene_external_refs (scene_id, source_id), migracja 0041. Podzapytanie "ma
kanon" dociagalo source_id z heapu, bo stary indeks zna tylko scene_id. Teraz idzie
Index Only Scanem: Heap Fetches 16 191 -> 1241.

Razem: sort=title + origin=hqporner, strona 5 czyta 251 tys. blokow zamiast 294 tys.,
a na rozgrzanym cache trwa 305 ms zamiast 371 ms (mediana z 3 rund z rotowana
kolejnoscia). Zysk jest skromny. Pierwsze wykonanie na zimnym cache trwa 3-5 s i tak
zostaje, bo trzeba dotknac ~2 GB; sprawdzilem tez wariant z materializacja scen originu
i CTE, czyta wiecej blokow (302 tys.), wiec obecny plan zostaje.

3. has_playback=false RAZEM z filtrem originu to warunek sprzeczny, bo origin wymaga
zrodla z dead_at IS NULL. Wynik jest pusty z definicji, ale Postgres przemielal caly
katalog, zeby to stwierdzic: 148 s. Teraz zwarte na false(), 4,8 ms, dalej zero wynikow.
Przy has_playback=true z originem pomijamy z kolei nadmiarowe EXISTS o zywym playbacku,
bo origin sam go wymaga, a kosztowalo sonde na kazdym kandydacie.

Wyniki bez zmian: strony 1-5 dla origin=hqporner i dla glownego feedu porownane pozycja
po pozycji ze stara wersja daja zero roznic, a sam predykat stub zgadza sie na probce
200 tys. scen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 11:11:17 +02:00
goon-foss
b6a075b28a perf(db): kasuje ix_scenes_title_normalized, zbedny prefiks indeksu z 0039
ix_scenes_title_created_id_desc zaczyna sie od tej samej kolumny, wiec obsluguje wszystko,
co obslugiwal stary indeks: lookupy `title_normalized = X` z resolvera i skan zakresu przy
sortowaniu po tytule. Trzymanie obu to 367 MB na dysku i jeden indeks wiecej do utrzymania
przy kazdym zapisie do scenes, a ingest pisze tam caly czas.

Sprawdzone na produkcji przez BEGIN; DROP INDEX; EXPLAIN ANALYZE; ROLLBACK, zeby zobaczyc
wybor planera bez starego indeksu, a potem jeszcze raz po samym dropie:

  exact title lookup        1,76 ms -> 0,07 ms, Index Scan po nowym indeksie
  OR studio + exact title   ten sam ksztalt planu (BitmapOr), 3,7 ms
  OR data + exact title     Seq Scan przy szerokim oknie dat, ale to decyzja o release_date:
                            z enable_seqscan=off BitmapOr siega po nowy indeks
  trgm ILIKE                bez zmian, swoj indeks GIN

W wariancie z OR planer i tak siegal juz po nowy indeks, jeszcze zanim stary znikl.
Indeksy scenes: 3544 MB -> 3177 MB. Listy scen po dropie bez zmian (tytul 22-54 ms,
studio 38-73 ms na stronach 1-5).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 10:47:24 +02:00
goon-foss
470beb4aa6 perf(api): sortowanie scen po studiu i tytule bez sortowania calego katalogu
Obie listy chodzily na produkcji w dziesiatkach sekund, bo klucz sortu nie mial nic
wspolnego z filtrami widocznosci (zywy playback, odsiew wertykalow, odsiew stubow).

sort=studio: nazwa studia siedzi w dolaczonej tabeli, wiec zaden indeks scen jej nie
zna i planer materializowal caly przefiltrowany katalog (ponad 2 mln wierszy), po czym
sortowal go w calosci. Odwracamy zapytanie: idziemy po studiach w kolejnosci nazwy i dla
kazdego dobieramy jego sceny przez LATERAL po ix_scenes_studio_effective_date_desc.
Zewnetrzny skan jest posortowany, wiec LIMIT urywa go po kilkunastu studiach. Sceny bez
studia dobiera osobny ogon, tak jak wczesniej robilo NULLS LAST. Przy filtrze po studiach
zawezamy tez sam skan studiow, inaczej szedlby przez wszystkie 33 tys.

sort=title: nowy indeks na cale ORDER BY (title_normalized, created_at DESC, id DESC).
Sam title_normalized zostawial Incremental Sort, a ten przed oddaniem pierwszego wiersza
musi zebrac caly kubelek scen o tym samym tytule.

Pomiary na produkcji (2026-09-16, ten sam zestaw filtrow, po rozgrzewce):

  studio strona 1            483 s  ->   41 ms
  studio strona 5            ponad 5 min ->   38 ms
  studio + tag blowjob        71 s  ->  226 ms
  studio + min_duration       48 s  ->   42 ms
  studio + studio_slugs      255 ms ->   44 ms
  tytul strona 1             709 ms ->   12 ms  (81 wpisow indeksu zamiast 3064)
  tytul + tag blowjob        ponad 90 s -> 1,5 s

Wynik jest identyczny co do wiersza: pierwsze 251 pozycji pelnego katalogu porownane
pozycja po pozycji ze starym zapytaniem daje zero roznic, tak samo dwa okna alfabetyczne
studiow (w tym Brazzers, zeby sprawdzic wewnetrzny LIMIT).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 10:37:26 +02:00
goon-foss
cf9741b319 fix(normalize): separator feat/ft w person_named_in naprawde dziala
Some checks are pending
Backend tests / test (push) Waiting to run
W _PERSON_SEPARATOR_RE zamiast \b staly doslowne znaki 0x08 (heredoc przy
commicie b7a8911), wiec tytul nigdy nie byl ciety na feat/ft. Regex uzywa
teraz prawdziwych granic slowa, lapie tez "featuring", a myslniki podaje
jako escape zamiast doslownych znakow.

Skutek w danych sprawdzony na prodzie: 255 701 przypisan na scenach z
sxyprn, 6530 tytulow z feat/ft, stara i nowa regula roznia sie w 0
przypadkach, bo sam czlon feat/ft i tak przerywal sasiedztwo nazwiska.
Poprawka zamyka przypadki brzegowe (smieciowy performer "Feat").

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 15:59:39 +02:00
goon-foss
d2b3378d93 fix(ingest): czysc opisy z encji i znacznikow HTML, title_normalized zawsze przez normalize
Opisy scen szly do bazy z `&#34;`, `&lt;br&gt;` i surowymi `<br />`, a apka i strona
SEO pokazuja opis jako tekst, wiec bylo to widac doslownie. clean_description
dekoduje encje, `<br>` i koniec akapitu zamienia na nowa linie, a znane znaczniki
wycina (`<3` zostaje tekstem). Wpiete w normalize_scene i normalize_movie.

bulk_rescrape_hqporner.py i repair_truncated_titles.py liczyly title_normalized
jako lower(title), przez co 6005 scen mialo interpunkcje w kluczu dopasowania.
Oba licza teraz normalize() i dekoduja encje w tytule.

Skrypty: fix_html_entity_titles.py przemianowany na fix_html_entities.py z
przebiegiem po opisach; nowy fix_title_normalized.py przelicza klucz tam, gdzie
rozjechal sie z normalize(title).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 15:59:39 +02:00
goon-foss
d471bb3293 fix(ingest): dekoduj encje HTML w tytulach scen i filmow
xvideos (JSON-LD) i kilka innych tubow oddaje tytuly z encjami HTML5
(`we&apos;re`, `&lpar;AI&rpar;`), czasem podwojnie zakodowane. normalize
robil z nich slowa `apos`, `lpar`, wiec tytul nie trafial w wyszukiwarke
ani w kanon.

unescape_html w app/normalize/text.py dekoduje encje zakonczone srednikiem
po slowniku HTML5, do skutku (max 3 przebiegi). Wpiete w normalize_scene i
normalize_movie oraz w parsery xvideos_browse i pornxp. Skrypt
fix_html_entity_titles.py poprawia istniejace wiersze (title,
title_normalized, slug gdy byl wyliczony z tytulu).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 15:59:39 +02:00
goon-foss
37e6b7f03c perf(api): liczniki +N ulubionych z cache i indeksem, podobne sceny z najrzadszych tagow
- /favorites i /favorites/studios: liczniki w cache procesu (swiezy 5 min, potem
  odswiezanie w tle), mark_seen zeruje od razu; parametr counts=false dla ekranow,
  ktore chca tylko stan gwiazdki
- licznik studiow idzie indeksem ix_scenes_studio_effective_date_desc (migracja 0038)
  i konczy po 200 scenach na studio: 10-25 s -> kilkanascie ms
- okno licznika sortuje tak jak lista (data premiery albo dzien dodania), wczesniej
  rozjechane od 0033
- similar_scenes: pula z 4 najrzadszych tagow zamiast grupowania po wszystkich
  (do 5 s -> ponizej 0,4 s)
- enrich-tags: tagi jednym zapytaniem po slugach i jeden INSERT
- /scene-favorites: serializer wsadowy

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 15:05:43 +02:00
goon-foss
080fc4b70e fix(apk 0.4.1): puste ikony na paczce wbudowanej, crash expo-video przy zamykaniu z ostatnich
- expo-file-system jako jawna zaleznosc: zagniezdzony pod expo nie byl autolinkowany,
  ExpoAsset.downloadAsync padal na AppDirectories not found (Sentry 143555436)
- app/build.gradle: create*UpdatesResources zawsze generowane; zadanie mialo same napisy
  jako wejscia i od 2026-05-31 osadzalo stary app.manifest (23 assety, bez fontu ikon)
- patch-package + patches/expo-video+2.0.6.patch: cleanup() iteruje po kopii mediaSessions
  (ConcurrentModificationException w onTaskRemoved, Sentry 147164135)
- versionCode 15 / 0.4.1, runtime bez zmian (1.4), /version 0.4.1, linki na stronie

Test: czysta instalacja offline na emulatorze, 0.4.0 = 0 glifow ikon + blad w Sentry,
0.4.1 = 11 glifow i brak bledu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 14:33:13 +02:00
goon-foss
747d0cec3b perf(api): historia ogladania wsadowo, wyszukiwanie w obrebie strony po rownosci originu
- /watch/recent: _build_scenes_out_batch(light) zamiast 5-7 zapytan na scene (N+1 w Sentry)
- /scenes?origin=tube❌ rownosc zamiast ILIKE '%...%', 4,6 s -> 1,1 s na hdporngg z q

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 14:06:01 +02:00
goon-foss
8462ab50df feat(mobile): zakladka nazywa sie Edge; /version 0.4.0 runtime 1.4
Nazwa od edgingu: feed krotkich klipow bez konca (wybor Jana). W kodzie zostaje
Swipe (SwipeScreen, swipeTelemetry), etykieta i teksty user-facing to Edge.
Backend /version podaje 0.4.0 / 1.4, wiec starsze APK dostaja monit o nowej
wersji; plik app-release.apk podmieniany razem z publikacja.
2026-09-15 09:29:40 +02:00
goon-foss
538a72107e perf(clips): explore po podzapytaniu okna, kandydaci bez ORM i bez tagow, max(uuid) przez tekst
Strona feedu spadla z 310-470 ms do 50-130 ms (srednio 85 ms na 30 stronach,
0 powtorek). Postgres nie ma max(uuid): koniec okna liczony po rzutowaniu na
tekst (ten sam porzadek dla malych hex w stalym formacie).
2026-09-14 20:34:19 +02:00