Commit graph

166 commits

Author SHA1 Message Date
goon-foss
4fd94de72d fix: cofnij obietnice keep-awake (modul nie jest w APK) + martwe miniatury fastpic
Some checks are pending
Backend tests / test (push) Waiting to run
1) Changelog obiecywal 'screen no longer turns off', ale to NIE dziala. Audyt APK
v0.2.1: nazwa 'ExpoKeepAwake' NIE wystepuje w zadnym classes*.dex - jest tylko
KeepAwakeManager z expo-modules-core (wewnetrzny interfejs). Czyli expo-keep-awake
nie zostal wkompilowany, requireNativeModule rzuca, a moj try/catch cicho polyka
blad. Blad w moim wczesniejszym rozumowaniu: obecnosc w node_modules/expo/
node_modules NIE oznacza, ze autolinking wciagnal modul do konkretnego builda.
Keep-awake WYMAGA nowego APK (OTA dowozi tylko JS), wiec wpis usuniety zamiast
obiecywac cos, czego nie ma. Zgloszenie 9d5618dd.

2) fastpic.org (galaxyporn) zrywa polaczenie zamiast oddac obraz -> dopisany do
_is_rotting_thumb. Bonus: scena bez miniatury odpala w apce auto-enrich, ktory
sciaga swieza ze strony tube'a. Zgloszenie c2f1dd41, 240 z 20213 zrodel.
2026-08-05 21:58:06 +02:00
goon-foss
81f0074d34 fix(vjav): bramka jakosci tytulu + wlasna iteracja stron
Po naprawie dostepu vjav ruszyl, ale zaczal sypac smieciem: pomiar na 295 scenach z
doby po fixie dal 78,6 proc. tytulow slug-concat i ZERO przypisanej obsady. Takie
sceny sa w apce nieodnajdywalne - nie maja ani tytulu, ani performera.

Bramka odrzuca cztery wzorce: prefiks id_JAV, hash x1x..., kod typu
QCT062-KPUDYLMLBL913295279 oraz ciagi bez samoglosek/spacji (walniecie w klawiature).
Zmierzone na probce 6000 tytulow: odrzuca 80 proc. swiezych i 27 proc. starych, przy
39 przepuszczonych na 200 obejrzanych - zrodlo nie jest wyzerowane.

WAZNE, znalezione przy pomiarze pierwszej wersji: str.isalpha() jest prawdziwe dla
kana i kanji, a japonski nie stawia spacji, wiec reguly "za malo samoglosek" i "brak
spacji" odrzucalyby PRAWDZIWE tytuly na serwisie JAV - 708 z 708 tytulow CJK z probki.
Stad jawny wyjatek _has_cjk. Kontrola jednostkowa: 8/8 przypadkow, w tym dwa CJK.

Drugi blad, wprowadzony przez sama bramke i zlapany dopiero pilotem: strona 1 jest w
100 proc. smieciowa, wiec po odsianiu zwracala [], a bazowe latest_scenes traktuje
pusta strone jako koniec katalogu i konczylo caly run. Zrodlo dawalo seen: 0 mimo 39
dobrych scen na stronach 2-5. Wlasna iteracja rozstrzyga wyczerpanie po dlugosci listy
id, nie po liczbie scen po filtrze. To ta sama pulapka co w _load_ids.

Pilot po obu poprawkach: seen 39 (wszystkie skipped - weszly przed bramka).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 14:25:00 +02:00
goon-foss
6199577ae7 revert(watchdog): usuniecie integracji ze Slackiem
Na zyczenie uzytkownika. Alerty zostaja wylacznie w Sentry - z eskalacja poziomu i
kubelkami wieku w fingerprincie z poprzedniego commita, wiec sama poprawa
powiadamiania zostaje nienaruszona.

Usuniete: app/notify/ (caly pakiet), job watchdog-digest, parametr to_slack w
run_ingest_freshness_watchdog oraz klucze konfiguracji sched_watchdog_digest_hours,
slack_bot_token i slack_channel. Zadna wartosc SLACK nigdy nie trafila do .env ani do
compose, wiec nic nie bylo wysylane.

Po usunieciu watchdog dalej sprawdza 41 zrodel (sceny + filmy), scheduler rejestruje
juz tylko ingest-watchdog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 15:12:17 +02:00
goon-foss
6e056b81c2 feat(watchdog): pokrycie filmow, eskalacja poziomu i dobowy digest na Slacka
Watchdog dzialal poprawnie - vjav i superporn wypisywal co 6h przez caly czas ich
ciszy. Zawiodlo POWIADOMIENIE, w trzech miejscach naraz.

1. Filmy nie byly pokryte w ogole. Watchdog skanowal tylko origins tube:<sitetag> ze
scen, wiec streamporn.vip stal 23 dni i zaden automat nie mial jak tego zauwazyc.
Doszlo 6 konektorow filmowych (35 -> 41 sprawdzanych zrodel), prog 72h. Zweryfikowane
przez celowe obnizenie progu do 1h: wszystkie 6 matchuje realne liczby pozycji, a nie
zwraca cicho zera - bo to dokladnie ta klasa bledu, ktora naprawiamy.

2. Stabilny fingerprint per origin tworzyl JEDNO issue przy pierwszym wystapieniu i
potem tylko licznik. Sentry powiadamia o nowych i regresjach, nie o kolejnych
wystapieniach otwartego issue. Teraz fingerprint zawiera kubelek wieku (2d+/7d+/30d+),
wiec przekroczenie kazdego progu zaklada nowe issue, ale w obrebie kubelka nadal nie
ma spamu co 6h.

3. Poziom byl zawsze warning, a reguly alertow celuja w error. Od 7 dni ciszy idzie
error. Sprawdzone: vjav i superporn eskaluja teraz do error, pornbusy/youperv/porndish
zostaja na warning.

Plus kanal, ktory czlowiek realnie czyta: dobowy digest na Slacka (osobny job, zeby
nie wysylac tej samej listy 4x dziennie). Domyslnie NO-OP - bez GOON_SLACK_BOT_TOKEN
i GOON_SLACK_CHANNEL nic nie probuje wysylac, kanalu nie zgadujemy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 15:03:27 +02:00
goon-foss
532c7e2bb4 fix(vjav): 429 parsowany jako XML, zrodlo stalo 12 dni bez zadnego bledu
Audyt po fixie streamporn.vip. vjav (77 tys. zrodel) nie dodal nic od 2026-07-22 i
NIE zglaszal bledu - crawl_page oddawal 0 scen, licznik pokazywal errors: 0.

Przyczyna: vjav odcial IP VPS-a. Sprawdzone 2026-08-03 - sitemap, strona glowna i
/latest-updates/ daja 429 przy trzech probach z rzedu, a przez Bright Data 200 od
pierwszej. Kod tego nie widzial, bo browser_get NIE rzuca na 4xx, wiec 343-bajtowa
tresc bledu byla parsowana jako XML: zero sitemap, zero id.

Drugi blad, ktory to ukryl: przy niepowodzeniu _load_ids ustawialo _sorted_ids = [],
a crawl_page tlumaczy [] na "koniec katalogu" (poprawny stan), nie na awarie. Teraz
przy bledzie zostaje None, ktore crawl_page zwraca jako transient-fail.

Fix: proxy Bright Data na sitemap i API metadanych (ten sam host, ten sam 429), jawne
sprawdzanie statusu, [] tylko dla realnie pustego katalogu.

Po fixie crawl_page oddaje 120 scen zamiast 0. Nowej podazy to jeszcze nie dalo
(wszystkie 120 to pozycje sprzed blokady, skipped na niezmienionym hashu) - sitemap
vjav nie przesunal sie od czasu odciecia. Do obserwacji. Uwaga na jakosc: w tej
partii 58 proc. tytulow to slug-concat typu 0008363_JAV_..., przy 2,9 proc. w calym
katalogu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 14:36:25 +02:00
goon-foss
3f8f38202a fix(movies): streamporn.vip czytal zly listing, stal od 23 dni
Zrodlo nie dodalo nic nowego od 2026-07-11. Strona jednak ZYLA, a konektor parsowal
poprawnie - problem byl w tym, ze `/movies/` na tym motywie NIE jest sortowane po
dacie i oddaje stary katalog. Zmierzone na tych samych 8 pozycjach: `/movies/` dalo
roczniki 2012-2015, strona glowna wylacznie 2026, po 10-11 zrodel playbacku kazda.
`?orderby=date` motyw ignoruje (odpowiedz identyczna z domyslna).

To ta sama klasa bledu co przy freshporno: wlasciwa strona, zly endpoint listingu.
Diagnoza po licznikach per zrodlo (ostatni nowy film + nowe w 30d/7d), nie po tym,
czy konektor rzuca wyjatkiem - bo nie rzucal.

Fix: `_listing_path` na `/` + `/page/N/`. Strony 1 i 2 wspoldziela ~44 linki
(sidebar/widgety), ale dedup po URL w fetch_movies je odsiewa.

Pilot po zmianie: seen 40, new 18, updated 10, skipped 12, errors 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 10:56:13 +02:00
goon-foss
c586a8ad32 feat(movies): konektor yourdailypornmovies.ws
Sprawdzony NA DUPLIKAT przed budowa, bo poprzedni kandydat (speedporn.net) okazal sie
kolejna nakladka na pandanetwork.club - 49/49 miniaturek z tego samego hosta co nasze
pandamovies, 0 nowych filmow. Tutaj z 40 pozycji ze strony glownej 13 mielismy po
tytule, 9 po id produktu Adult Empire, a 18 bylo nowych. Inna pula tresci: okladki DVD
z imgs1cdn.adultempire.com, nie re-hosty.

Pilot na 40: seen 40, new 22, updated 18, errors 0. W bazie 36 filmow, z tego 34 z
obsada, 36 ze studiem, 14 dopielo sie do pozycji, ktore juz mielismy.

WordPress z wlasnym motywem, wiec nie da sie podpiac pod DooplayConnector.

Pulapka, ktora trzeba bylo obejsc: /tag/ w calym HTML to 2177 linkow, czyli chmura
tagow w sidebarze (ten sam wzorzec co przy sexu). Obsada, tagi i studio czytane
WYLACZNIE z blokow div.xmll - efekt to 5-14 tagow na film zamiast 2177.

Druga rzecz: /director/ trzyma w praktyce STUDIO (New Sensations, VIXEN, Zero
Tolerance Films), nie rezysera. Bierzemy to jako studio, bo tak jest uzyte.

Playback: voe i mixdrop maja gotowe moduly hosterow i zweryfikowalem, ze resolwuja
(voe m3u8, mixdrop mp4). vidara.to nieznana, leci jako zwykly embed do WebView.
Katalog min. 8000 pozycji, siega 2003. Brak dlugosci filmu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 10:38:18 +02:00
goon-foss
4417ae0ff0 feat(tags): scal duplikaty liczby mnogiej + prewencja + skrocone liczniki
Some checks failed
Backend tests / test (push) Has been cancelled
1) Duplikaty tagow wrocily, ale INNYM wzorcem niz w lipcu: alnum-klucz z natury nie
lapie liczby mnogiej ('blowjob' != 'blowjobs'). Audyt: 1944 pary, m.in.
Blowjob/Blowjobs (390728 vs 791), Teen/Teens (53096 vs 41294), Cumshot/Cumshots.
Scalone oba kierunki (kanoniczny = wiekszy scene_count): 1938 + 2063 tagow,
przeniesione 251251 + 26142 przypisan scen i 118522 + 392 filmow. Zostaje 581 par
(lancuchy i remisy) - celowo pominiete, wymagaja recznej decyzji.

2) Prewencja w _resolve_by_altkey: gdy alnum-klucz nie trafi, probujemy obu form
(+s / -s). Tylko proste 's' - form nieregularnych (panty/panties) NIE ruszamy, bo
zbyt latwo o falszywy zlew (glass/glasses, bra/bras). Zweryfikowane na prodzie:
Blowjobs->Blowjob, Teens->Teen, Cumshots->Cumshot, Lesbians->Lesbian.

3) UI: formatCount() skraca duze liczniki (181764 -> 181k, 1200 -> 1,2k) w tagach,
performerach, ulubionych i filtrach filmow - user-request, chipy przestaja puchnac.
2026-08-03 09:19:50 +02:00
goon-foss
21d51ca691 chore(hqfap): zdjete zrodlo - Cloudflare JS-challenge nie do przejscia
Some checks are pending
Backend tests / test (push) Waiting to run
Druga i ostateczna deaktywacja (pierwsza 2026-06-25, wtedy stub-pliki). Strona
wdrozyla Cloudflare z JS-challenge na /watch/. Sprawdzone TRZY drogi, wszystkie 403:
VPS (Hetzner), residential IP z pelnym kompletem naglowkow przegladarki, oraz
Bright Data ISP proxy. Czyli blokada NIE jest po IP - wymaga wykonania JS.
Przelaczenie na WebView (commit 140764b) tez nie wystarczylo: challenge pokazuje sie
userowi zamiast przechodzic samoczynnie (zgloszenia 92e9133e / 60576a84 / 244131ba).
Telemetria: ZERO prob odtworzenia od 27.07, czyli realnie martwe od tygodnia.

Utrzymanie wymagaloby headless-przegladarki na VPS - nieproporcjonalne do zysku,
decyzja uzytkownika: usunac. Wyrejestrowany scraper (browse) i extractor;
61238 playback_sources oznaczone dead_at. Uwaga: hqporner to INNE zrodlo o mylnie
podobnej nazwie - nietkniete, dziala.
2026-08-02 18:01:19 +02:00
goon-foss
c1e6c7ad49 fix(thumbs): odsiej zrodla oddajace atrapy zamiast miniatur (znikaly po merge)
Some checks are pending
Backend tests / test (push) Waiting to run
Zgloszenia a01dc891 / 2fbba822 / b437d5f7 ('3 zrodla live, a miniaturki nie ma',
'jakby przy merge scen cos ginelo'). Diagnoza: WSZYSTKIE zrodla mialy
thumbnail_url w bazie, wiec problem byl w wyborze. Apka bierze PIERWSZE zrodlo z
ustawionym URL-em, a po scaleniu na czolo listy wchodzilo zrodlo ktore formalnie
'ma miniature', ale realnie oddaje smiec - dzialajaca lezala nizej i nigdy nie
byla uzyta. Przy jednym zrodle bralo sie to dobre, stad objaw dopiero po merge.

Dwa hosty dopisane do _is_rotting_thumb (istniejacy mechanizm zerowania martwych):
- imgs.xiaoshenke.net (fullporner): HTTP 200 z ~153-bajtowa ATRAPA zamiast obrazu,
- tn.sextu.com (fullvideosporn): 429 dla IP datacenter, wiec nasze image-proxy tej
  miniatury NIGDY nie pobierze (znany problem tego zrodla).

Zweryfikowane na wszystkich trzech zgloszonych scenach: bylo 153B/404/429,
teraz 200 i realne obrazy (22287 / 21633 / 32820 B).
2026-08-02 16:30:21 +02:00
goon-foss
580e4db535 feat(perverzija): natywny HLS zamiast WebView z reklamami
Some checks failed
Backend tests / test (push) Has been cancelled
Bug-reports 40ec88cc / 92e9133e ('zacina sie na pierwszych sekundach i robi loop').
Trace CDP wykazal: iframe pervl4.xtremestream.xyz/player/index.php?data=<md5> ma w
HTML WYLACZNIE preroll/midroll (opencdn.b-cdn.net) - to one lecialy w petli. Wideo
player dociaga dopiero w runtime:
  GET /player/xs1.php?data=<md5>&q=<480|720>  ->  GOTOWY manifest HLS (#EXTM3U, VOD,
  segmenty ~4,17s z PELNYMI URL-ami do pervl4.xspcdn{01..10}.sa.com/cdn/down/...).
Segmenty maja rozszerzenie .html (kamuflaz), ale to zwykly HLS - nic nie trzeba
deszyfrowac ani skladac.

Nowy extractor zwraca oba warianty jako type='m3u8' z referer=index.php?data=<md5>
(taki Referer wysyla przegladarka; bez niego ryzyko 403). Zweryfikowane na prodzie:
2 zrodla, oba HTTP 200 i #EXTM3U (44245 / 41142 B).

Uwaga: sciezka manifestu nie konczy sie na .m3u8, wiec musi isc przez /proxy/hls
passthrough (casus pornhat) - segmenty i tak leca direct z CDN.
2026-07-28 12:16:18 +02:00
goon-foss
7a40ff70ba fix(performers): czlon <3 znaki degenerowal filtr slug-matchu (over-attribution)
Some checks are pending
Backend tests / test (push) Waiting to run
Bug-report 986d3018 ('O co chodzi z tym Lady Vi? To wcale nie jest aktorka z tych
filmow'). Search-scrapery filtruja wyniki po tokenach nazwy >=3 znaki, wiec czlon
2-znakowy wypada: 'Lady Vi' -> {lady}, i  degeneruje sie do 'slug zawiera
lady' = KAZDA scena z tym slowem. Dla nazw gdzie WSZYSTKIE czlony sa krotkie
('Jj Jj', 'Mi Su') zbior tokenow jest PUSTY, a
przepuszcza wtedy absolutnie wszystko.

Audyt: Lady Vi miala 116 przypisan z tube, z czego 115 pasowalo tylko przez 'lady'
a realnie o niej byla 1. Wyczyszczone (zostaly kanoniczne stashdb + 1 trafione).

Fix: gdy nazwa ma czlon <3 znaki, wymagamy dodatkowo CALEJ nazwy sklejonej bez
separatorow ('lady-vi-...' -> 'ladyvi'). Zweryfikowane: lady-vi-hot-scene przyjmie,
lady-sonia-milf i busty-lady-next-door odrzuci.
2026-07-28 09:52:41 +02:00
goon-foss
140764bfc5 fix(hqfap): Cloudflare JS-challenge -> tryb WebView zamiast phone-fetch
Some checks are pending
Backend tests / test (push) Waiting to run
hqfap wdrozyl Cloudflare na strony /watch/ (2026-07-28): 403 z VPS ORAZ z
residential IP, takze przy pelnym komplecie naglowkow przegladarki (strona glowna
dalej 200, wiec blokada celuje w strony wideo). Phone-side resolveHqfapPage to
zwykly fetch, wiec nie ma jak wykonac JS-challenge -> resolve padal i user
ladowal na stronie hostera (bug-report 92e9133e 'Hqfap przekierowuje na strone').

Telemetria tego NIE pokazala: hqfap ma 99-100% do 26.07 i ZERO eventow od 27.07,
bo blad wystepuje PRZED playerem, wiec event nie powstaje. Ten sam wzorzec co przy
freshporno - przy takich zgloszeniach nie ufac samemu success-rate.

Fix: hqfapcom -> _vps_blocked_fallback (WebView, Chrome engine + JS + cookie
przechodzi challenge; INJECTED_JS i tak wylusknie mp4 i wroci na native player).
Zdjety z PHONE_RESOLVE_ORIGINS i z lancucha phone-resolve w SceneDetail/Player.
2026-07-28 09:42:05 +02:00
goon-foss
90a63b1e77 feat: wylaczalny auto-rotate w playerze + '+N' liczy takze filmy
Some checks are pending
Backend tests / test (push) Waiting to run
1) Auto-rotate (bug-report 55da1c3f: 'I can't turn off auto rotate. Which is a
problem when I put the phone on a flat surface'). Player robil bezwarunkowy
unlockAsync, wiec telefon lezacy plasko skakal miedzy orientacjami. Nowa
preferencja goon.player_auto_rotate (default true = dotychczasowe zachowanie),
przelacznik w Settings. Off = player zostaje w pionie, ale przycisk pelnego
ekranu dalej wchodzi w poziom recznie, wiec nic nie ginie.

2) '+N nowych' na ulubionym performerze/studiu liczylo TYLKO sceny (user-request
2026-07-28). Dochodzi _new_movie_counts: filmy z zywym playbackiem, created_at >
last_seen_at, po MoviePerformer / Movie.studio_id. Filmow jest o rzedy wielkosci
mniej niz scen (brak tube-spamu), wiec bez okna top-N i odsiewu stub/backfill -
te pojecia dotycza scen. Zweryfikowane: performer 1633 scen + 436 filmow = 2069,
studio 648 + 95 = 743, /favorites 200 OK.
2026-07-28 09:34:37 +02:00
goon-foss
9af5fd4eb4 fix(performers): zbedne przypisania jednotokenowe obok osoby pelnoimiennej
Ranking z poprzedniego commita ujawnil klase, ktorej zaden wczesniejszy sygnal nie
widzial: wpisy bedace SAMYM NAZWISKIEM albo samym imieniem, powstale z rozbicia peleno
nazwy przez tube-search. "Devine" obok "Shalina Devine", "Kitana" obok "Kitana A",
"Rayne" obok "Tiffany Rayne". Taki wpis lapie potem kazda scene z tym slowem,
nalezaca do zupelnie innej osoby.

Regula jest DOWODLIWIE BEZSTRATNA: kasujemy przypisanie jednotokenowe tylko wtedy, gdy
ta sama scena ma juz przypisana osobe pelnoimienna zawierajaca to slowo. Informacja o
obsadzie zostaje, znika tylko niejednoznaczny duplikat. Kontrola potwierdzila, ze zadna
scena nie zostala przez to bez obsady (0).

Prowenancja z migracji 0026 dala zabezpieczenie: z 62 783 zbednych przypisan 62 120 to
scraper (skasowane), 73 kanon (chronione), 590 nieznane (zostawione). Bez niej nie dalo
by sie tego rozdzielic.

Wynik: 62 120 przypisan zdjetych, 2156 wpisow odchudzonych (Devine 170 na 60), 1740
pustych rekordow usunietych. Regula dopieta do joba junk_performers, drugi przebieg
daje zera.

Zostaje residuum: sceny, na ktorych osoba pelnoimienna NIE byla przypisana, wiec
regula nie miala sie o co oprzec (James, Blue, Moon, Crystal, Cruz, Starr, Knight po
60-160 przypisan). Tam trzeba by DOPISAC wlasciwa osobe, a nie kasowac - to osobne,
bardziej ryzykowne zadanie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 09:23:14 +02:00
goon-foss
8d92ecc51b fix(performers): zdjecie scraperowych przypisan z nazw 1-2 znakowych
"A", "L", "Ro", "Be", "Js" mialy po 250-290 scen kazdy. To artefakty parsowania
tytulow przez tube-search, ale NIE wszystkie: "Cj", "PD" i "JD" to realne krotkie
pseudonimy z obsada potwierdzona w TPDB i StashDB, z prawdziwymi partnerami
scenicznymi (Cj z Lucy Belle i Denisem Martim, PD z Victoria Love).

Dlatego nie kasujemy tu performera, tylko przypisania, o ktorych WIEMY ze dokleil je
scraper. Reszta rozstrzyga sie sama: komu nic nie zostanie, ten znika. To pierwsze
uzycie provenance z migracji 0026 - bez niej nie dalo sie odroznic "Cj" z obsady
TPDB od "Cj" wylusknietego z tytulu.

Rozklad byl jednoznaczny: z 9404 przypisan 9232 (98,2 proc.) ze scrapera, 141 z
kanonu, 31 nieznanych. Wiersze z NULL-em zostawiamy, nie zgadujemy.

Wynik: 9232 przypisan zdjetych, 20 performerow zniknelo calkiem, 31 zostalo z sama
prawdziwa obsada (Cj 41, PD 38, JD 20, reszta <=10). Dopiete do joba junk_performers,
zeby nie odroslo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 15:18:38 +02:00
goon-foss
034ddd644c feat(dedup): provenance przypisan performerow do scen (scene_performers.source_id)
scene_performers nie zapisywalo, KTO przypisal performera do sceny. Przez to nie dalo
sie odroznic obsady z kanonu od performera doklejonego przez tube-search, ktory
dopasowuje wynik po JEDNYM tokenie zapytania. Stad przypadek "Rapture": 30 z 72 jej
przypisan bylo falszywych (film "The Rapture" z Mimi Rogers, literowka "hymen
raptured", tytuly scen) i trzeba bylo je przegladac recznie, bo nie bylo sygnalu.

Kolumna trzyma NAJBARDZIEJ wiarygodne zrodlo, jakie przypisalo. Regula idzie tylko w
gore: NULL wypelnia cokolwiek, kanon nadpisuje scraper, scraper NIGDY nie zamazuje
kanonu. Inaczej dowolny pozniejszy tube-search zatarlby informacje, ze obsade
potwierdzilo TPDB. To samo przy merge_scenes: przy kolizji przenosimy lepsza
provenance na keepera, zeby scalanie nie degradowalo potwierdzonej obsady.

Backfill wypelnil 4 147 128 wierszy (96,3 procent) wnioskowaniem, ktore jest pewne:
scena z refami z DOKLADNIE jednego zrodla ma cala obsade stamtad. Sceny wielozrodlowe
(67 tys.) zostaja z NULL-em, bo tam zgadywanie zepsuloby sens kolumny. Wsadowo, z
commitem na paczke: pojedynczy UPDATE na 4 mln wierszy trzymalby locki na
scene_performers i zablokowal ingest.

Rozklad: tube-scraper 3 219 677, tpdb 747 540, stashdb 180 355.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 15:04:10 +02:00
goon-foss
7ad94448a4 fix(performers): drugie kryterium smieciowych performerow (tag przytlacza osobe)
Klasa "prawdziwy performer o pospolitej nazwie" okazala sie zawierac 211 rekordow,
ktore w ogole nie sa osobami, tylko kategoriami z refem kanonicznym: "Big Tits"
(931 scen), "Big Ass" (640), "Hardcore" (222), "Blonde" (238), "Masturbation".
TPDB i StashDB SAME zawieraja takie wpisy, wiec ref kanoniczny ich nie oczyszcza.

Kryterium promiskuitycznosci z poprzedniego commita tu NIE dziala i sprawdzenie tego
bylo kluczowe: w tej populacji obcy mierzy popularnosc, nie smieciowosc. Przy
wartosciach 50-59 stoja Adriana Chechik (4201 scen), Lauren Phillips, Jane Wilde i
Jordi El Nino Polla. Moja wczesniejsza walidacja progu 50 byla obciazona, bo grupa
bez refa to sami malo znani.

Rozstrzyga stosunek scen-z-tagiem do scen-performera, i to z uzasadnienia, nie z
probki: nazwisko uzyte jako wlasny tag daje stosunek ~1 Z DEFINICJI, bo tag siedzi
dokladnie na jej scenach. Potwierdzone na markach osobistych: Hotwifevictoria 1,02,
Rossmexicana 0,99, Sexwithmilfstella 0,87. Wielkie gwiazdy jeszcze nizej, maksimum
0,35 wsrod 921 pewnych osob. Kategorie: Hardcore 1720, Masturbation 1570, Blonde 770.
Prog 2 + wymog >=50 scen (ponizej stosunek jest szumem).

Skasowane 211 rekordow / ~32 tys. przypisan w dwoch przebiegach. Job idempotentny.
Ogon klasy jest zdrowy: z 8116 pozostalych 92% miesci sie ponizej 0,35.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 14:23:03 +02:00
goon-foss
02ff9c7ff1 fix(performers): skasowanie 277 smieciowych performerow + job zapobiegajacy odrastaniu
Kategorie i studia podszywajace sie pod osoby: "Creampie" (269 scen), "Natural tits"
(670), "reverse cowgirl" (315), "69", "Brazzers", "Blacked", "Twistys". Razem 277
rekordow i 33 784 przypisan do scen.

Zrodlo: _search_base filtruje wyniki tube-searcha warunkiem "slug zawiera >=1 token
z zapytania", a resolve_performer tworzy performera z dowolnej nazwy podanej przez
tube. Zadnej bramki po drodze.

KRYTERIUM JEST WASKIE CELOWO. To uzywane w app/api/scenes.py do de-rankingu (slug
pokrywa sie z tagiem I brak refa tpdb/stashdb) daje 3111 trafien, ale probka pokazala
~60% falszywek dla nazw wielowyrazowych: wpadaja w nie Hatano Yui, Davina Raines,
Michelle Ferrari, Clanddi, SolaZola, Kate Kuray. Zalozenie "prawdziwy performer ma ref
kanoniczny" nie dziala dla JAV, amatorek i debiutantek. Do de-rankingu wystarcza, do
kasowania nie.

Rozstrzyga promiskuitycznosc taga: ile ROZNYCH innych performerow pojawia sie na
scenach z tym samym slugiem. Zmierzone: prawdziwe osoby maksimum 20 (Julia Reaves),
wiekszosc 0-4, Hatano Yui 0. Kategorie: Deepthroat 39541, Creampie 33661, riding
16284. Prog 50 lezy ponad 2x powyzej najwyzszej prawdziwej osoby. Odrzucilem tez
sygnal "slug rowny studiu", bo wciagal marki osobiste (Katekuray, Julia Reaves).

Tresc nie ginie: te slugi dalej istnieja jako tagi (creampie przy 176 tys. scen),
przestaja tylko udawac osoby. 16 968 scen zostalo bez obsady, co dokłada 1,8 procent
do istniejacych 943 tys. scen bez obsady.

Job co 24h zamiast bramki w resolve_performer: nie dotyka goracej sciezki ingestu,
a smieci odrastaja wolno. Ta sama logika co przy blackliscie phashy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 13:44:11 +02:00
goon-foss
3de8489ffa fix(dedup): blacklista zdegenerowanych phashy + scalenie 4647 duplikatow
Audyt duplikatow po phashu miniatur wykazal dwa rozne zjawiska, ktore wygladaly
jak jedno.

1. Zdegenerowane phashe. 73 wartosci wystepowaly przy >=10 scenach kazda, lacznie
przy 4375 scenach; rekordzistka byla dzielona przez 892 sceny o 892 roznych
tytulach i 1886 roznych performerach. To zaslepki i czarne klatki, nie odciski
scen. find_by_phash_within bierze najblizsza wartosc z calej tabeli, wiec taka
zaslepka zawsze wygrywala z prawdziwym duplikatem (dist 0). Do tej pory bronila
nas bramka dur_prox i nic sie nie skleilo, ale to zabezpieczenie drugiej linii.

Blacklista jest tabela, nie jednorazowym DELETE, bo sam DELETE nic nie daje:
zaslepka wraca przy kolejnym ingescie. Trzeba pamietac, ze wartosc jest
bezuzyteczna. Job co 24h dopisuje nowe i czysci odciski. Po czyszczeniu zero
grup >=10, najwieksza pozostala ma 9.

2. Realne duplikaty. 4647 scalonych. Przyczyna byla jedna: 97 procent par ma
perverzije po dokladnie jednej stronie, bo pisze tytuly z prefiksem studia i
performera, a reszta tubow daje goly tytul. Wbrew mojej pierwszej diagnozie NIE
trzeba tu ruszac scoringu tytulu (token_set_ratio i tak radzi sobie z prefiksem,
a sciezka phash idzie przed composite): 80 procent par to dlug sprzed 60+ dni, a
biezacy wyciek to okolo 1 dziennie. Nadmiarowe wiersze: 18452 na 9449.

merge_phash_exact_dupes.py dostal wykluczenie blacklisty. Bez tego byl grozny:
sam klaster 892 scen dawal ~397 tys. par do rozwazenia.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 12:47:20 +02:00
goon-foss
b485511f3f feat(fullporner): browse scraper pelnych scen + extractor bez tokenu
Pelne sceny, nie klipy: mediana ~33 min, zero ponizej 10 min, ~140-240 dziennie,
listing chronologiczny mimo naglowka Featured.

Extractor sklada URL sam, bez tokenu i bez wygasania: id w iframe jest zapisane
wspak, a koncowka to maska bitowa jakosci (1/2/4/8 = 360/480/720/1080). Id bywa
numeryczne albo szesnastkowe, a to drugie to ~25% katalogu. Blokada CDN jest na
naglowku (bez UA 403, bez Referera 404), NIE na fingerprincie TLS, wiec telefon
przechodzi -> mobile_direct_ok. Zweryfikowane 206 + faststart do 1080p.

Metadane cienkie: brak studia, mediana 3 tagi, tytuly przepisane pod SEO. Za to
data jako unix timestamp i dlugosc co do sekundy. Bramka na obsade, bo sceny bez
performera scalily sie 0/23 w dry-runie.

Phash miniatury liczony celowo i to on robi robote: dry-run resolvera bez niego
dawal 31% scalen, pilot z nim dal 65% (seen 62, new 22, updated 40, errors 0).
85 z 89 performerow ma ref tpdb/stashdb.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 12:04:34 +02:00
goon-foss
ea489454c0 feat(sexu): scraper + extractor HLS, ale bez rejestracji w ingescie
Metadane ma najlepsze z tej serii: kanal = realne studio na 97% scen, 96%
performerow z refem tpdb/stashdb, dokladna dlugosc w sekundach, swiezosc w
godzinach, 120 scen na stronie listingu.

Nie wlaczamy go jednak do ALL_BROWSE_SCRAPERS, bo jednostka tresci jest zla:
to klipy 5-10 minut, nie sceny. Mediana 571 s na stronie 30 i 459 s na 200,
zero filmow >=20 min w calym katalogu. Pilot na 240 scenach dal 1 canonical
match, bo dlugosc i tytul, czyli sygnaly resolvera, sa przepisane pod tube.
Przy ~340 uploadach dziennie to ~10k nierozwiazywalnych wierszy miesiecznie.

Kod zostaje kompletny i zweryfikowany: POST /api/video-info przez Bright Data
(CF blokuje sam POST z VPS), HLS playerData.src zamiast mp4 sources (te maja
ip= requestera w tokenie), master konczy sie .mp4 wiec lapie go istniejacy
hls_needs_passthrough. Gdyby serwis zaczal wrzucac pelne sceny, wystarczy
dopisac klase z powrotem do rejestru.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 11:42:05 +02:00
goon-foss
f5b7a45ac0 feat(8kporner): browse scraper za obejściem CF + extractor JWPlayer sources
Sitemapa i /watch/*.html są za Cloudflare, paginacja zwraca stronę 1, a load-more
chce logowania, więc katalog buduje się z homepage (~115 scen), a detale lecą przez
?link1=watch&id=. Bramka na obsadę przepuszcza 62/115; z tego 97% performerów ma
ref tpdb/stashdb, a 60% scen dopina się do tego, co już mamy.

Extractor czyta tablicę sources JWPlayera, nie JSON-LD contentUrl (ten jest zawsze
144p). Cap 720p, bo okcdn dławi połączenie do ~2,1 Mbps. Stream przenośny cross-IP
(206 bez Referera, faststart) → mobile_direct_ok.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 11:15:32 +02:00
goon-foss
b3e1092175 feat(pornmike): browse scraper behind a cast gate + direct-mp4 extractor
pornmike.com puts everything in JSON-LD @graph -> ItemPage.mainEntity
(name, duration, uploadDate, actor[], genre[], keywords, description,
thumbnail), so the parser reads one JSON blob instead of scraping markup.
Cast is clean: the whole scene page carries exactly as many /pornstar/
links as there are actors, none of the sidebar pollution that got xxxfiles
rejected. 82% of sampled performers already carry a tpdb/stashdb ref and
19-20 of 20 channels are studios we already know.

Ingest is gated on a non-empty actor[]: 23% of the catalog has no cast and
those scenes could neither be attributed nor deduped. Tags and categories
come only from JSON-LD (keywords + genre), never from the HTML, which
carries 38 /category/ and 22 /tag/ nav and sidebar links per page.
Pagination is ?p=N only: the /N/ form 404s and ?page=N is silently ignored,
returning page 1.

Playback is the simplest in the portfolio: a plain <source> mp4 on twincdn
with no token, no query string and no expiry. Verified 206 on a Range
request from the VPS and from another machine in another country, both
without a Referer, so it is neither hotlink-guarded nor IP-bound and the
phone streams it directly.

Two honest caveats recorded in the module docstring: these are 5-12 minute
clips (median ~487s against 1800-2400s for the tubes we accepted), so for
the ~20% of the catalog from Tushy/Blacked Raw/Milfy/Anilos they will sit
as a short shadow next to full canonical scenes; and uploadDate is the
tube's import date, not the studio release, so pages past the second are
marked backfill.

Pilot ingest of 3 pages: 127 seen, 49 merged into existing scenes, 66 new,
0 errors; on page one the gate passed 42 of 62 links with zero scenes
missing cast, duration or studio.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-07-27 10:42:39 +02:00
goon-foss
d7442187c9 feat(fullvideosporn): browse scraper behind a cast gate + TXXX extractor
fullvideosporn.com is sextu.com rebranded, not a clone of fullmovies.xxx
(different engine, different catalog, 0/140 title overlap with our
fullmoviesxxx corpus).

The site is only worth ingesting behind a gate: 65-75% of its catalog has
no performer at all, and those scenes also carry SEO-spun titles, so they
would never match canonical and would land as empty orphans. So we ingest
only scenes with at least one performer. That keeps ~25-35% of the catalog
(verified: 19 of 60 on page one) where the signal is good, since 88-89% of
the performer names in the research sample already resolve to a canonical
performer in our DB.

Three site-specific traps, all handled:
- Titles come from the player's vit:"..." field, not og:title/h1, which are
  sometimes an AI SEO rewrite rather than the real scene title.
- Cast is read only from the <h3>Porn-stars:</h3> section; the page carries
  ~22 videos.php?q= links overall but only 1-2 real performers, the same
  pollution that got xxxfiles rejected. Porn Site / Porn Categories are
  separate h3 blocks and are parsed per-section so they don't bleed.
- Every fetch passes a cookie gate: a fresh session gets HTTP 429 plus a
  small JS challenge, so we read the cookie out of it and retry on the same
  session. Hence the custom crawl_page instead of the base browser_get.

The TXXX video_url decoder moved out of vjav into _txxx.py since both tubes
share the engine; vjav keeps an alias and was re-verified after the move.
Playback resolves videofile.php -> decode -> get_file -> 302 -> znvcdn, and
the final CDN URL is portable cross-IP so the phone streams it directly.
Note for future debugging: the VPS itself gets 429 from that CDN because of
datacenter IP reputation, so playback health-checks run from the VPS will
be falsely negative.

Pilot ingest of 2 pages: 39 seen, 11 merged into existing scenes, 28 new,
0 errors; 0/19 without cast or duration on the sampled page.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-07-27 08:56:23 +02:00
goon-foss
d716b0c75d feat(pornbusy): browse scraper + loadvid POST-manifest producer
pornbusy.com exposes every field as a discrete itemprop node (title,
duration, uploadDate, thumbnail, description) plus a dedicated
<div id="video-actors"> cast block with no sidebar pollution. Measured
orphan risk is low: 80% of a 100-scene sample have a performer that
already carries a tpdb/stashdb ref, and 21% of titles strongly match
scenes we already hold. No studio field exists on the site.

Homepage pagination is broken (pages 1/2/3 return an identical set), so
the listing is driven off sitemap_index.xml -> 10 post-sitemaps sorted by
lastmod, chunked in crawl_page the same way the PlayTube base does it.

Playback dispatches on embedURL and covers ~69% of the catalog: the
seekplayer family (already handled by the engine after the earlier host
regex widening) and zpi.cx (the embedURL is the file itself), plus loadvid
at ~41%, which needed new plumbing.

loadvid hands back the CONTENT of an m3u8 over POST /videos/resolve-token
(CSRF + videoToken from the embed page) and has no manifest URL at all:
GET on that endpoint is 405 and the guessable .m3u8 paths are 404. So
make_token grew an optional `producer` marker and /proxy/hls calls the
producer instead of GETting a URL. Segments in the returned manifest are
absolute and fully portable (verified: 206 on a Range request with no
headers, no referer, no token), so the phone still pulls them straight
from the CDN and only the manifest travels through the VPS.

upload18 (~12%) and the tail are deliberately left unresolved: their token
embeds the fetcher's /24, so resolving server-side would force the whole
video through the VPS.

Verified: 19 scenes/page, 19/19 with duration, 17/19 with cast, 19/19 with
tags (names read from the title attribute since an icon element precedes
the anchor text), playback 8/8 via loadvid, and /proxy/hls returning a
116KB manifest with 869 absolute segments. Pilot ingest of 3 pages: 59
seen, 35 merged into existing scenes, 24 new, 0 errors.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-07-27 08:45:00 +02:00
goon-foss
2bf9179467 feat(galaxyporn): browse scraper + extractor; widen seekplayer host regex
galaxyporn.net carries paysite rips with a dedicated <div id="video-actors">
cast block (no sidebar pollution), studio + date in the title prefix, healthy
/page/N/ pagination. Measured orphan risk is low: 92% of a 75-performer
sample already have a tpdb/stashdb ref in our DB and 79% of titles match
scenes we already hold.

seekplayer_engine host regex widened to cover seekplays|4meplayer|ezplayer|
seeks|upn and the pro|cloud|one TLDs. This is the same engine (identical
AES key/IV and /api/v1/video endpoint), just newer domains; the whitelist is
additive so existing hosts keep matching (verified, including that
upns.evil.com is still rejected). Unlocks all four galaxyporn player hosts
and the same family on other sites.

Two things the extractor had to get right:
- Call seekplayer_engine directly rather than via extract_stream_from_hoster:
  the wrapper verifies the resulting URL and the hotlink-guarded HLS 403s, so
  it discarded correctly decoded streams.
- Referer must be the PLAYER origin, not galaxyporn.net. With the site referer
  the manifest 403s; with the player origin it returns 200. Verified end to
  end: manifest 200 -> variant 200 (570 segments) -> segment 206.

Duration is absent from the HTML, JSON-LD and player payload, and a NULL
duration would silently hide scenes behind the min_duration_sec filter (the
porntrex incident), so it is computed from the player's thumbnail.vtt last
cue. The player API throttles bursts, hence the retry/backoff: that took
missing durations from 9/21 down to 3/21. The value runs ~2% short of the
true length (one thumbnail interval), which beats having none.

Pilot: 21 scenes/page with studio 21/21 and clean cast (max 3), ingest of
2 pages = 42 seen, 34 new, 8 merged, 0 errors.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-07-26 18:23:13 +02:00
goon-foss
5a0b62c3e4 feat(youperv): browse scraper + direct-mp4 extractor
youperv.com (DataLife Engine) carries paysite rips titled
"Studio - Performer - Title" (71% of a 132-title sample), ~60-70 new
scenes/day. Browse the homepage + /page/N/ (19 scenes/page, no overlap);
scene URL is /<category>/<id>-<slug>.html.

Cast is scoped to the fmeta block (up to the Related section): the whole
page carries 19-26 /xfsearch/pornstar/ links but only 1-2 are the actual
cast, so without scoping this would repeat the page-wide pollution that
got xxxfiles rejected. Studio comes from the title prefix, guarded so a
performer name is never mistaken for a studio. Duration, ISO release date,
per-scene tags and thumbnail all come from the same block.

Playback is a plain <source> mp4 (files.klubnichka-hd.com) with no token
or expiry, but the CDN hotlink-guards on Referer: bare Range gets 403,
Range + Referer + browser UA gets 206 cross-IP from the VPS. So the
extractor returns it with referer + mobile_direct_ok and the phone streams
straight from the CDN, no WebView and no proxy. Path is percent-encoded
because the filenames contain spaces.

Deep-crawl capped at 2000 pages: beyond that (<=09.2023) the catalog turns
into generic amateur uploads with no performers and dead CDN files.

Verified: 19 scenes/page with studio+cast+duration+date, max 2 performers
per scene (pollution guard holds), 0/19 missing duration, playback 206
video/mp4. Pilot ingest 3 pages: 57 seen, 39 attached to existing canonical
scenes, 18 new, 0 errors.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-07-26 17:57:24 +02:00
goon-foss
55da508f9c fix: keep-screen-on podczas odtwarzania + on-demand miniaturki youporn
Some checks failed
Backend tests / test (push) Has been cancelled
1) Ekran gasl w trakcie ogladania (bug-reports fcbaa933 2026-07-18, c40fb79f
2026-07-23, dwoch userow). Android wygasza po timeoucie, bo dotyk nie pada, a samo
granie wideo nie trzyma wake-locka. expo-keep-awake NIE jest w top-level
node_modules (siedzi w node_modules/expo/node_modules), wiec metro nie rozwiaze
importu, ale natywny modul ExpoKeepAwake JEST w APK (expo go autolinkuje) -
siegamy po niego przez requireNativeModule z expo-modules-core (top-level).
Dzieki temu leci OTA, bez nowego APK. Wake-lock tylko gdy realnie gra (przy pauzie
ekran gasnie normalnie); WebView-player trzyma przez caly czas zycia ekranu, bo
tam nie ma sygnalu play/pause.

2) Miniaturki youporn (bug-report bebf8c92): youporn przeszedl dla czesci katalogu
na imgproxy z PODPISANYM URL-em (?hash=...&validto=<ts>), ktory WYGASA - zapisany
w bazie po czasie zwraca 410 (8666 z 62930 zrodel). Statyczne .../original/N.jpg
dzialaja bezterminowo. Nowy endpoint /proxy/youporn-thumb/<video_id> resolwuje
swiezy poster przy serwowaniu (jak sxyprn-thumb), z html.unescape bo og:image ma
&amp; i psulo to podpis (403). Podmiana TYLKO dla podpisanych - statycznych nie
ruszamy, zero dodatkowych fetchy.

Zweryfikowane: 8/8 wczesniej-410 teraz 200 (57-142KB), statyczne bez regresji.
2026-07-26 17:00:31 +02:00
goon-foss
0c5148b6e8 feat(ingest): browse-latest scraper dla hqporner
Some checks are pending
Backend tests / test (push) Waiting to run
hqporner byl TYLKO w ALL_DIRECT_SCRAPERS (search po nazwisku performera), wiec
swieze sceny wchodzily wylacznie gdy worker trafil na pasujacego performera →
0 nowych scen w 7 dni (audit 2026-07-26, user: 'nie widze nowych scen z hqporner'),
mimo ze tube publikuje codziennie.

HQPornerBrowseScraper: listing / + ?p=N (~50 scen/strone), detail /hdporn/<id>-<slug>.
Metadane z detail page: tytul z <title> (Title Case; <h1> jest lowercase), dlugosc z
meta description ('Video duration is 46min 58sec'), performerki z /actress/ (display
name, nie slug), tagi z /category/, miniaturka fastporndelivery + phash (z Refererem,
bo CDN bez niego 403).

external_id identyczny jak w HQPornerScraper.search (hqpornercom:<url>) → obie sciezki
trafiaja w te sama scene zamiast robic duplikat. Tagi jakosciowe (1080p-porn, 4k-porn)
odfiltrowane, bo to atrybut pliku a nie tag tresci.

Zweryfikowane na zywo: 50 scen z page 1, dur 2818s/1138s/1805s, performerzy+tagi+phash.
2026-07-26 16:41:47 +02:00
goon-foss
7afb332fc8 fix(playback+ingest): realny proxy fallback gdy CDN nieosiagalny + porntrex duration
Some checks are pending
Backend tests / test (push) Waiting to run
1) eporner/phone-resolve: gdy strona parsuje sie OK, ale CDN jest nieosiagalny z
sieci usera (audit: siec zglaszajacego nulluje vid-*.eporner.com -> 0.0.0.0, a
www.eporner.com dziala), phone re-resolve zwracal TEN SAM URL, a lancuch fallback
nie ratowal: dla phone-resolved linkow fallbackProxyUrl === url (resolver ustawia
stream_url = direct_url), wiec krok proxy byl no-opem i szlo prosto do WebView =
strona hostera z reklamami ('zaladowala sie reklama zamiast wideo'). Teraz po
nieudanym phone-resolve bierzemy PRAWDZIWE proxy z backendu (VPS pobiera swoim
DNS-em). Tylko na sciezce bledu. Eporner globalnie zdrowy (89-100%, ~100 urzadzen
dziennie), wiec to fix dla userow z blokowanym CDN, nie regresja globalna.

2) porntrex zmienil markup kafelka: class="duration">MM:SS< ->
<div class="durations"><i class="fa fa-clock-o"></i> MM:SS</div>. Stary wzorzec
przestal matchowac -> duration_sec=NULL dla ~95% swiezych scen (6479/6815 w 7 dni),
a mobile domyslnie filtruje min_duration_sec=60, wiec te sceny byly NIEWIDOCZNE
('nie widze nowych scen z porntrex'). Wzorzec obsluguje oba warianty + H:MM:SS.
Zweryfikowane na zywym listingu: 84/85 kafelkow, 20:45 -> 1245s.
2026-07-26 16:34:24 +02:00
goon-foss
2d1800a461 fix(scenes): sxyprn detail thumbnail + stronger WebView pre-play mute
Some checks are pending
Backend tests / test (push) Waiting to run
1) _build_scene_out (detal) nie stosował _sxyprn_thumb_url jak lista → detal
pokazywał martwy trafficdeposit URL, refresh nie pomagał (sxyprn IP-bound). Teraz
detal też podmienia na żywy /proxy/sxyprn-thumb/<id>. Backend-only.

2) Mute WebView-scrape: attribute-autoplay (<video autoplay>) omijał override play()
i grał unmuted. Dokładam proaktywne ciszenie na play/loadeddata/volumechange +
poll 40ms do gestu (property-lock trzyma między tickami). Web Audio i tak gated
autoplay-policy. Raport usera: dalej głos przed ExoPlayerem.
2026-07-22 11:16:44 +02:00
goon-foss
80ac621344 fix(tags): collapse spelling-variant duplicate tags + prevent regrowth
Ten sam tag z różnych tubów tworzył osobne wpisy (Blowjob/Blow Job, Big Tits/
Bigtits, deep-throat/deepthroat, creampie-1/creampie, mojibake CJK 'Japanese'…)
bo resolve_tag brał slug/slugify(name) verbatim. ~11k nadmiarowych tagów.

- resolve_tag: przed utworzeniem nowego tagu szuka istniejącego kanonicznego po
  alnum-kluczu nazwy (_resolve_by_altkey) i reużywa go → warianty nie regenerują.
- Indeks funkcyjny ix_tags_name_altkey (migracja 0028) pod ten lookup.
- scripts/merge_altkey_tags.py: jednorazowy backfill istniejących duplikatów
  (kanoniczny = max scene_count, scene_tags/movie_tags/blacklisted_tags przepięte
  z dedupem na PK, dropy skasowane, taxonomy_counts odświeżone).
2026-07-21 15:59:33 +02:00
goon-foss
f97369a764 fix(scenes): filter junk 'performers' from similar-scene matching
Some checks are pending
Backend tests / test (push) Waiting to run
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).
2026-07-21 15:50:49 +02:00
goon-foss
45459b414b feat(scenes): similar-scenes rail on detail (shared performers/tags)
Some checks are pending
Backend tests / test (push) Waiting to run
Backend GET /scenes/{id}/similar: ranking po WSPÓLNYCH performerach (waga 3) i
tagach (waga 1). Performerzy selektywni → mała pula kandydatów (cap 1500); tagi
liczone tylko w tej puli. Fill z tagów (bounded 400, HAVING>=2 wspólne) tylko gdy
performerów mało/brak (anonimowe tube sceny) — inaczej szeroki tag skanowałby
setki tysięcy scen. Filtr widoczności jak lista: grywalne + brama JAV + blacklist
+ nie-stub + nie-self. Ranking/sort w Pythonie nad ograniczonymi zbiorami.
Zmierzone: 210-944ms wg liczby performerów seeda.

Mobile: SimilarRail (poziomy) na dole SceneDetail, lazy przez react-query, znika
gdy brak dopasowań, tap → nav.push kolejnego SceneDetail.
2026-07-21 15:26:55 +02:00
goon-foss
aa11fb022a fix(stars): fresh+rich source not marked offline on telemetry gap
Some checks are pending
Backend tests / test (push) Waiting to run
freshporno gra natywnie (zweryfikowane na realnym telefonie, PlaybackState=
PLAYING) ale udane odtworzenia nie raportują się jako success event → sam błąd
w telemetrii → 0% success → health=0 → fałszywe 'offline' i demote.

_overall_stars: gdy health==0 ale źródło jest ewidentnie żywe (freshness>=4 i
richness>=4), floor 2★ 'flaky' zamiast 0★ 'offline'. Martwe źródła mają niski
freshness więc gate dalej działa.
2026-07-20 20:58:02 +02:00
goon-foss
db1bd2a3d4 fix(scenes): JAV sites showed "No videos" when browsed directly
Some checks are pending
Backend tests / test (push) Waiting to run
The JAV vertical gate excluded JAV origins whenever jav=false, including when the user
browsed a specific JAV site (Sites -> javflix/vjav/supjav -> SiteScenes passes
origin=... without jav=true), so those pages showed "No videos" (3 reports 07-19).

Only apply the exclusion to the main feed (origin is None). Browsing a specific origin
shows it regardless; the JAV tab (jav=true) still shows only JAV. Verified: javflix/vjav/
supjav now return scenes via origin filter, main feed still gates JAV out.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:18:01 +02:00
goon-foss
2cfb0bc12d feat(sync): device-to-device backup of favorites & state
Some checks are pending
Backend tests / test (push) Waiting to run
No-accounts app, so favorites/saved-searches/hidden-list/watch-progress live
per-device (keyed by X-Device-Id). Users asked how to move them to a new phone.

Backend: POST /me/import/{source_device} copies all device-scoped tables from a
source device to the caller (dedup via NOT EXISTS, new UUIDs for id-PK tables like
saved_searches). Copy not move, so the old phone keeps everything; idempotent. The
device_id is a random UUID so knowing it is the authorization (fine for a keyless app).

Mobile: Settings -> "Backup & sync" shows this device's sync code (copy button) and a
Restore field to paste the other device's code; invalidates favorites queries after.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:41:35 +03:00
goon-foss
7e2807b42e feat(supjav): resolve voe hoster to direct stream instead of WebView
Some checks failed
Backend tests / test (push) Has been cancelled
supjav is an embed-aggregator (voe/streamtape/turbovid/fc2stream). It was playing
through the WebView fallback because none of its hosters had a native phone-side
resolver wired into the scene player. voe.sx does have one (voeResolver.ts, already
used for movies) — it just was not wired for scenes.

- PlayerScreen: wire isVoeUrl/resolveVoePage into the hoster routing (like
  dood/filemoon), so a voe embed resolves on the phone to a direct m3u8
  (token bound to the phone /16, plays direct, no WebView, no proxy).
- supjav extractor: return voe first (sorted by URL), and stop putting the raw
  hostname in `quality` (the digit in "fc2stream" was parsed as quality 2 and won
  _pick_best) — use a clean digit-free server label instead.
- SceneDetailScreen: for hoster-only scenes, open the first embed (the extractor
  puts the natively-resolvable one first) rather than _pick_best's choice.

Verified: supjav's voe embed resolves to a real HLS manifest (200,
application/vnd.apple.mpegurl, #EXTM3U). WebView stays only as last-resort fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 19:52:26 +02:00
goon-foss
8c3ad2b09a feat(jav): supjav.com scraper + extractor (embed-aggregator, 4th JAV source)
Fourth JAV vertical source (origin tube:supjav, gated to JAV tab via JAV_ORIGINS).

Browse: CF-blocks datacenter IPs, so listing goes through the Bright Data ISP proxy
with retry (the proxy rotates IPs and CF only lets some through). Homepage-latest only
(~66 newest); deeper /page/N/ stays CF-403 even via proxy. Metadata parsed from the
listing cards (title, thumbnail, JAV code, year/month) rather than per-post details,
which are flaky and slow through the proxy.

Stream: supjav hides the real hoster behind a per-server data-link (hex). base.js loads
lk1.supremejav.com/supjav.php?l=<data-link>, which reverses the hex string and fetches
?c=<reversed>, 302-ing to the hoster (TV->turbovid, FST->fc2stream, ST->streamtape,
VOE->voe). The extractor reproduces that: fetch detail via proxy, reverse each data-link,
resolve through lk1 (reachable direct from the server), return the hosters as type=hoster
so the phone resolves them (dood/filemoon native, the rest via the WebView fallback on the
residential IP). lk1 needs no proxy; only the detail fetch does.

Backend-only, no mobile change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 14:10:43 +02:00
goon-foss
5b31459a26 feat(jav): vjav.com scraper + extractor (TXXX-network JAV source)
Second JAV vertical source (origin tube:vjav, gated to JAV tab via JAV_ORIGINS).

Browse: SPA has no server-rendered listing, so id-walk over sitemap_vids
(newest = highest video id) feeding the rich JSON metadata API
(/api/json/video/1/<floor>/<id>/<id>.json): title, duration, post_date,
channel->studio, models->performers, categories+tags.

Stream: videofile.php returns video_url in two obfuscation layers, Cyrillic
homoglyphs (M/C/A/E) over a custom base64 alphabet (comma->slash, tilde->pad,
dash->plus). Decoded get_file is absolute (old shared-txxx videos) or relative
(new vjav-infra, prepend host); adding f=video.m3u8 yields a portable, time-bound
ahcdn HLS (referer=none whitelisted, not IP-bound). Returned as m3u8 +
mobile_direct_ok so playback routes it through /proxy/hls: manifest passthrough,
segments direct from the phone (verified 206 cross-IP, 0 VPS video bandwidth).

Backend-only, no mobile change (JAV tab + jav param already shipped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 13:13:35 +02:00
goon-foss
4df1e01b31 feat(jav): separate JAV section (tab + feed gating) + enable javflix ingest
JAV is a distinct vertical (user decision): Asian codes/titles that do not dedup
against the western catalog, so they must not flood the main feed.

Backend (scenes.py): JAV_ORIGINS = {tube:javflix, tube:javguru, tube:vjav,
tube:supjav}; list_scenes gains a `jav` param. Default (jav=false) excludes any
scene with a live JAV-origin source; jav=true returns only those. The cached
default-count and _is_pure_default also exclude JAV so the main feed count matches.
JavflixScraper is now registered in ALL_BROWSE_SCRAPERS (scheduled ingest lands in
the JAV section, gated). Scraper hardened: requires a real server button
(class="myLink") so static pages (Terms/FAQ) are skipped, and unescapes HTML
entities in the title.

Mobile: a "JAV" top tab reuses ScenesScreen with { jav: true } (route param ->
listScenes jav=true). The 60s minimum-duration default is disabled in the JAV tab
because javflix does not expose duration (NULL >= 60 would hide the whole section).

Verified on prod: 16 javflix scenes appear only in the JAV feed and are excluded
from the 2.29M main feed; playback resolves to voe/doodstream/emturbovid.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 11:16:31 +02:00
goon-foss
d8d00295e1 feat(jav): javflix.cc scraper + extractor (first JAV source, gated off main feed)
First site of the JAV vertical (user request, separate section). javflix.cc is a
WordPress JAV aggregator, VPS-reachable and server-rendered. Scraper parses itemprop
metadata (title, thumbnail, uploadDate; no duration) and the JAV code (BKD-368 style)
as a tag. Playback: server buttons are <a class="myLink" href="<embed>"> (streamtape,
voe, doodstream, emturbovid) whose href sits in the raw HTML; the generic _embed_iframe
extractor already resolves those via its anchor-hoster pattern, so javflix registers
under sitetag "javflix" with a thin wrapper that drops the players.mp4 placeholder.
Added emturbovid to the anchor-hoster host list.

Verified end-to-end on prod: scrape a listing -> RawScene with metadata + code tag,
resolve -> emturbovid/voe/doodstream hoster sources (all Goon-playable).

NOT registered in ALL_BROWSE_SCRAPERS yet. JAV is a separate vertical (user decision)
that must be gated out of the main scenes feed before ingest so it does not flood the
western catalog. Next: feed gating (exclude JAV origins by default) + a mobile JAV tab
+ on-device playback test, then enable scheduled ingest. jav.guru / vjav / supjav
follow the same pattern.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:58:34 +02:00
goon-foss
62c2548450 fix(movie-resolve): route DoodStream clones to phone-side resolve, skip yt-dlp
extract_stream_from_hoster fell through to yt-dlp for DoodStream clones (playmogo,
doply, myvidplay, dood.*), which yt-dlp does not support -> "ERROR: Unsupported URL"
spam dominating the movie-resolve logs, plus wasted seconds per resolve before the
caller returned the embed as type='hoster' anyway. Now detects the dood-clone family
up front and returns None immediately (same pattern as the filemoon SPA handling), so
the embed goes straight to the mobile doodstream.ts resolver (pass_md5 with the user's
residential IP, which clears the invisible Turnstile). Verified: playmogo/myvidplay/
doply URLs now return None with no yt-dlp attempt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:05:11 +02:00
goon-foss
e30f6830f4 fix(mobile): stop Scenes feed repeating on scroll + mute audio during 2x hold
- Scenes feed repeated the same videos on scroll (report 304c9258): OFFSET
  pagination + continuous ingest means new scenes shift the offset, so later pages
  re-include earlier rows. Backend now appends Scene.id as a unique final tiebreaker
  to every sort (deterministic order), and the mobile Scenes list dedups by scene id
  when concatenating pages so a drifted overlap can never show a duplicate.
- Player: holding to fast-forward at 2x now mutes the sped-up (chipmunk) audio for
  the duration of the hold and restores the user's real mute preference on release
  (report 35bbf428).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:59:28 +02:00
goon-foss
b66817175a feat(hqfap): restore hqfap.com scraper + extractor (site back on new CDN)
hqfap was hard-removed 2026-06-25 when its entire CDN library started serving a
fixed /upload/videos/video_down.mp4 "server down" stub for every scene. The site
is back and now serves real video from a new CDN (d*.vstor.top/whlvid/...). Probe
of the live sitemap: 5/6 sampled scenes return a real mp4 (0 stubs), and the CDN
is portable cross-IP (HTTP 206 from a residential IP and from the VPS with the
hqfap referer).

Restores the PlayTube CMS browse scraper (HQFapScraper, sitetag hqfapcom) and the
JSON-LD contentUrl extractor, re-registered in both registries. The extractor now
sets mobile_direct_ok=True (vstor.top is not matched by _TIME_BOUND_CDN_RE, but is
verified portable) so mobile plays direct with zero proxy. The video_down.mp4 stub
guard is kept defensively. 4k69 stays removed (not re-checked).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:53:43 +02:00
goon-foss
cb22174657 fix(thumbnails): watchporn thumbs at ingest + backfill; SceneDetail uses live sxyprn thumb
Two bug-report clusters about missing thumbnails:

1. watchporn scenes had no thumbnail on the list, only appearing after opening
   SceneDetail (which auto-enriches og:image). Coverage was 1.3% (463/36,915).
   The browse scraper never captured a thumbnail. KVS stores the poster at a fixed
   derivable path (contents/videos_screenshots/<id//1000*1000>/<id>/preview.jpg,
   verified 8/8 loading). Scraper now sets thumbnail_url (og:image, else derived);
   backfilled 36,687 existing rows -> 100% coverage.

2. SceneDetail showed no thumb where the list showed one: the mobile detail picks
   the first source with a thumbnail_url (origin ASC often puts sxyprncom first),
   and sxyprn/trafficdeposit stored thumbs rot to 404. The list already swaps those
   for a live resolver (/proxy/sxyprn-thumb/), but the detail builder did not. It
   now applies the same live-resolver swap and nulls other rotting thumbs so the
   detail lands on a working image.

Both backend-only, no OTA needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:21:59 +02:00
goon-foss
4baf6ea896 fix(movie-enrich): studio/performer disambiguation for generic TPDB titles
Generic movie titles ("Monster Tits", "Pirates") map to many different TPDB
films with identical titles (different studios/casts, all title-score 1.0). The
old matcher searched per_page=10 and ranked by title only, so for a generic title
the correct film was often not even in the top 10, and among same-title
candidates it picked arbitrarily. Result: a ~95% no_match rate and silent
misattribution (e.g. "Monster Tits" by Venom Digital Media would get Galaxy
Productions' TPDB entry).

_best_match now:
  - searches per_page=40 (the right film for a generic title is often past top 10),
  - ranks title-gate survivors by a composite of title + studio similarity +
    performer overlap (our studio/cast from the primary source disambiguate which
    same-title film it is),
  - guards against misattribution: if we have a studio/cast signal and there is
    more than one near-identical-title candidate but the winner shares neither
    studio nor cast, return no_match instead of attaching a wrong same-title film.

Verified on prod data: a no_match-with-studio sample now matches 18/18 with the
correct studio (fixing Galaxy to Venom, Exquisite to Rodney Moore, and a no_match
to Cherry Boxxx), and an already-enriched sample keeps 16/18 identical picks with
the 2 differences being the same studio (benign TPDB duplicate). No wrong-studio
regressions observed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 11:31:38 +02:00
goon-foss
e215b48255 fix(watchporn): re-resolve stale CDN URL in-player, drop WebView page fallback
The zload CDN URL (remote_control.php) is a valid faststart progressive mp4 that
ExoPlayer plays fine when fresh: 206, no IP/referer binding, ~2h token TTL,
verified from a residential IP. Real-device failures (player_error/gone
telemetry) come from the static URL going stale: a rotated or dead CDN node, or
an expired token.

Instead of falling back to the tube page in a WebView (removed, it papered over
the real issue), PlayerScreen now re-resolves the scene fresh via the backend on
initial-load error for backend-native KVS tubes (watchporn). That yields a live
node plus a fresh token and stays on the native direct stream (0 VPS bandwidth).
For these origins a CDN 'gone' (404) means stale URL, not deleted, so we
re-resolve on gone too; a genuinely deleted post raises HosterDead (410) and
falls through to the normal fallback chain.

Also: add playback_events.error_detail (raw ExoPlayer message) to pin down the
exact failure of tubes we cannot reproduce on the emulator. Keep FLAG_SECURE on
release builds only (!__DEV__) so debug builds stay screenshottable for local UI
verification.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 01:18:08 +02:00
goon-foss
0c18472a15 fix(feedback): freeomovie posters + dead hoster + myvidplay; watchporn _embed_iframe guard
From user bug reports (8f8c10c0 freeomovie, c156e4b7/8db71220 watchporn scene):

freeomovie (app/connectors/freeomovie.py):
- Parse the detail-page poster (<img class="rmbd">); RawMovie was built with no
  poster_url, so title-only orphans (no canonical match) rendered blank cards. Re-ingest
  backfilled existing blanks 11 -> 1.
- _host_label now returns the registrable domain (parts[-2]) not the subdomain, so
  video.player4me.xyz labels as 'player4me' (was garbage 'freeomovie:video').
- Skip player4me (JS-SPA, no known resolver); pruned 28 dead freeomovie:video sources.
- myvidplay.com added to mobile DOOD_HOSTS (doodstream.ts): it 301s to playmogo.com
  (doodcdn clone), so it now routes to the native dood resolver instead of a dead WebView.

watchporn: the reported 4 duplicate/broken quality rows were the API process serving a
STALE extractor registry (never restarted after the re-enable deploy) -> _embed_iframe
scraped 2 tokenless get_file (403) + 2 preview trailers (404). The running api now serves
the native extractor (2 clean playing links, verified). Hardened _embed_iframe to skip
preview/videos_screenshots clips and tokenless get_file so this class can't recur.

Also: DonateScreen em-dashes -> commas/semicolon (no-em-dash rule).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 13:02:47 +02:00