Trzecia proba i tym razem z dowodem z emulatora, a nie ze zgadywania. vikingfile.com
oddaje 302 na INNA domene (dzis vik1ngfile.site). WebView w aplikacji celowo blokuje
przejscie top-frame na inny eTLD+1, zeby popundery nie przejmowaly ekranu, wiec to
przekierowanie bylo odrzucane i zostawal czarny ekran. Z serwera tego nie widac, bo
httpx sledzi przekierowanie po cichu; widac dopiero w przegladarce na urzadzeniu,
gdzie w pasku adresu stoi vik1ngfile.site.
Poprawki:
- ekstraktor oddaje adres DOCELOWY (rozwiazuje 302 przy kazdym resolve, bo domena
zapasowa rotuje), wiec aplikacja od razu otwiera wlasciwa domene i zadna zmiana
domeny w ogole nie zachodzi
- wzorzec hosta we wstrzykiwanym skrypcie obejmuje obie pisownie (vik[i1]ngfile.),
wczesniej dopasowywal tylko vikingfile.com, wiec po przekierowaniu w ogole sie nie
uruchamial
Przy okazji z emulatora widac, ze zabezpieczenie to CHECKBOX "Verify you are human",
czyli wymaga kliniecia. Dlatego strona musi byc widoczna i uzywalna, a nie schowana.
Opublikowane OTA na 1.2 i 1.1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zgloszenie: "galaxyporn dalej czarny ekran po Loading video". Zdiagnozowalem to
wczoraj zle. WebView ma nieprzezroczysta zaslone (coverOverlay z tlem motywu), ktora
znika dopiero po SZTYWNYCH 15 sekundach albo wczesniej, gdy uda sie wyluskac adres
wideo. Dla hostera, ktory wymaga kliknięcia, znaczy to 15 sekund gapienia sie w
spinner, a strony i tak nie widac.
Na to naloilem wczoraj wlasny blad: oswajajac strone vikingfile chowalem CALA jej
oprawe i zostawialem tylko widget na czarnym tle. Gdy widget sie nie wyrenderowal,
po zdjeciu zaslony zostawala czysta czern, czyli gorzej niz przed moja zmiana.
Dwie poprawki:
- strona vikingfile NIE jest juz chowana, tylko podswietlamy ramke z zabezpieczeniem
i przewijamy do niej; najgorszy przypadek to normalna strona hostera
- gdy widget sie wyrenderuje, strona melduje to aplikacji (needs_interaction), a ta
zdejmuje zaslone OD RAZU, zamiast czekac 15 sekund
Podsluch POST-a z bezposrednim linkiem zostaje: gdy zabezpieczenie przejdzie samo,
user w ogole nie zobaczy strony, tylko natywny odtwarzacz.
Opublikowane OTA na 1.2 i 1.1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Jan slusznie zapytal, czy WebView jest w ogole potrzebny. Rozlozylem protokol do
konca: po przejsciu zabezpieczenia strona robi POST na WLASNY adres z cialem
'cf-turnstile-response=<token>' i dostaje JSON z polem link, czyli gotowy plik.
Endpoint to po prostu adres strony pliku, nie zadne osobne API.
Bez tokenu sie nie da: POST z pustym albo brakujacym cf-turnstile-response oddaje
zwykly HTML (701 kB), a nie JSON. Sprawdzone trzy warianty ciala. Tokenu nie
wyprodukuje klient HTTP, bo wymaga silnika JS. Ale NIE wymaga czlowieka: widget jest
w trybie flexible z callbackiem, wiec na czystym domowym laczu przechodzi sam.
Wykorzystujemy to: WebView zostaje jako silnik JS, tylko podsluchujemy ten jeden POST
i gdy w odpowiedzi pojawi sie link, oddajemy go aplikacji przez istniejacy kanal
video_url. Aplikacja przechodzi wtedy na NATYWNY odtwarzacz, bez reklam i bez
ogladania strony hostera. Oswojony wyglad strony zostaje jako zabezpieczenie na
wypadek, gdyby zabezpieczenie jednak zazadalo kliniecia.
Blok zwalidowany jako realny JavaScript (new Function po zamianie podwojnych
backslashy na pojedyncze, tak jak robi to szablon). Typecheck bez nowych bledow.
Opublikowane OTA na 1.2 i 1.1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zgloszenie 21d6f5af: galaxyporn laduje sie, a potem pusta strona, bez bledu.
Kierowanie bylo juz poprawne, problem byl wizualny. Vikingfile to STRONA PLIKU, nie
goly odtwarzacz: naglowek serwisu, nazwa pliku, rozmiar, przyciski pobierania,
progres i stopka, a wlasciwy widget Cloudflare siedzi w #captcha, czesto pod
zgieciem. W malym oknie odtwarzacza user widzial wiec pustke i nie mial pojecia,
ze ma gdzies kliknac.
Wstrzykujemy teraz dla tego jednego hosta krotki blok, ktory chowa cala oprawe
strony, wysrodkowuje #captcha-download na pelnym ekranie i dokłada jedna linijke
podpowiedzi. Gdy strona zdejmie z <video> klase hidden, chowamy widget i oddajemy
obraz na caly ekran. Dalej dziala zwykly scrape <source>, wiec gdy tylko pojawi sie
adres pliku, i tak przeskakujemy na natywny odtwarzacz.
Blok zwalidowany jako realny JavaScript (new Function na wyciagnietym fragmencie po
zamianie podwojnych backslashy na pojedyncze, tak jak robi to szablon).
Opublikowane OTA na 1.2 i 1.1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zgloszenia 57d6265a ("wszedzie doodstream resolver fail") i 3d3e1b33. Przyczyna nie
jest po naszej stronie: playmogo i klony DoodStreama przeszly z NIEWIDZIALNEGO
Turnstile na RENDEROWANY. Sprawdzone 2026-08-22 przez residential IP: strona ma 59 kB
i zawiera pass_md5, czyli sam protokol zyje, ale w HTML jest turnstile.render i ZERO
znacznikow trybu invisible. Z serwerowni ta sama strona ma 5 kB i pass_md5 w ogole nie
ma, wiec bez residential IP nie da sie tego nawet zdiagnozowac.
Skoro zadne ciche pobranie tego nie przejdzie, ekran "DoodStream resolver fail" z
przyciskiem "Open in WebView" byl juz tylko dodatkowym klikiem przed dzialajacym
odtwarzaniem. Teraz po nieudanym cichym resolverze wchodzimy do WebView od razu, czyli
tam, gdzie user moze kliknac widget. To ta sama sciezka, ktora dziala dla vikingfile.
Opublikowane OTA na 1.2 i 1.1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GOON-1S: 53 wystapienia u 35 osob od 2026-07-03, poziom fatal. Lancuch przyczyn jest
jednoznaczny: JSApplicationIllegalArgumentException przy ustawianiu wlasciwosci
maintainVisibleContentPosition na RCTScrollView, dalej
MaintainVisibleScrollPositionHelper.getUIManagerModule() robi assertNotNull i gdy
ScrollView powstaje w chwili, w ktorej UIManager jest niedostepny, leci AssertionError.
To blad React Native 0.76.9, nie da sie go obejsc konfiguracja.
Wlasciwosc byla anti-jankiem: przy sort=created_at scrapery dosypuja sceny na gore,
wiec refetch potrafil szarpnac trescia pod palcem. Skakanie listy jest gorsze niz nic,
ale crash jest gorszy od skakania. Do rozwazenia po podniesieniu React Native.
Przy okazji GOON-4N (Cannot read property 'length' of undefined, 2 osoby): dokladnego
miejsca NIE da sie wskazac, bo build 0.2.2 poszedl bez source map, a zaden z naszych
czterech getNextPageParam nie siega po .length. Dokladamy tam tania defensywe na
niepelna strone; jesli bedzie wracac, najpierw trzeba naprawic wysylke source map.
Opublikowane OTA na 1.2 i 1.1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
expo-video wola w init konstruktora VideoPlayer bezwarunkowy startService dla
androidx.media3 MediaSessionService (VideoPlayer.kt:233), a Android od 8.0
zabrania startu zwyklego serwisu z tla. Gdy ekran playera montowal sie juz w tle
(user wyszedl w trakcie resolve albo system wznowil stos ekranow), konstruktor
rzucal IllegalStateException i zamiast wideo pokazywal sie ekran bledu.
GOON-12: 63 wystapienia, 28 osob, wszystkie z in_foreground=false.
Konfiguracja tego nie wylacza, wiec bramkujemy montowanie: hooka nie da sie
warunkowac, stad wlasciwy ekran wyjechal do PlayerScreenActive, a eksportowany
PlayerScreen czeka na AppState 'active'. Bramka dziala tylko przy montowaniu,
wiec zejscie w tlo z juz dzialajacym playerem nie przerywa odtwarzania.
Opublikowane OTA na 1.2 i 1.1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zgloszenia 2026-08-20 ("hentaimama dalej 0 scen", "porndish zaprzestal ingestu",
"czemu sexu ma tylko 38 scen"). Trzy razy ten sam pierwotny powod, i to NIE ingest.
`api.ts` doklejal `min_duration_sec=60` do KAZDEGO listScenes bez wlasnej wartosci.
W SQL `duration_sec >= 60` jest nieprawda takze dla NULL, wiec prog wycinal nie tylko
krotkie sceny, ale wszystkie o NIEZNANEJ dlugosci. Zmierzone na produkcji:
supjav, hentaigasm, hentaimama, hentaiplay, javflix, xanimeporn 100% NULL
xhamster 90,3% (360 709) porndish 88,9% (37 736) porntrex 76,8% (616 345)
latestpornvideo 68,4% xnxx 65,2% (226 217) xvideos 63,8% (258 711)
Czyli wejscie w konkretny serwis ukrywalo ponad 1,5 mln scen i wygladalo jak martwy
albo zatrzymany tube. Ekrany drill-down (SiteScenes, PerformerScenes, StudioScenes,
TagScenes) przekazuja teraz 0: user wszedl JAWNIE w te pozycje, wiec ma zobaczyc jej
zawartosc. Glowny feed zostaje z progiem 60s, bo tam chroni przed teaserami.
Zweryfikowane na produkcji: hentaimama / supjav / xanimeporn 0 -> 50 pozycji.
Pulapka NULL opisana w api.ts, zeby ktos nie "uproscil" tego z powrotem.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SPROSTOWANIE: paska postepu NIE trzeba bylo budowac, on juz istnial (track + fill +
thumb + gest + czasy, 48px hit-box). Moja wczesniejsza diagnoza "player nie ma czym
przewijac" byla bledna: szukalem po nazwach Slider/progressBar/seekBar, a implementacja
nazywa sie scrub*. Zamiast dublowac funkcje, zostal realny blad, ktory przy okazji
wyszedl.
Blad: UI paska liczy sie z `dur = knownDuration || durationSec || 0`, czyli z fallbackiem
na dlugosc z metadanych sceny, ale seek w `onEnd` byl strzezony warunkiem na samym
`knownDuration` (to, co zglosil player). Dla zrodla, ktore nie poda dlugosci playerowi,
a ma ja w metadanych, uchwyt i czas jechaly za palcem, a po puszczeniu nie dzialo sie
nic. Teraz seek uzywa tej samej wartosci co rysowanie, przez `durRef` (gest powstaje raz
w useMemo, wiec domykalby stara wartosc).
Zweryfikowane na emulatorze na realnym odtwarzaniu: przeciagniecie paska przenioslo
pozycje z 1:36 na 18:03, wypelnienie i uchwyt zgodne.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Hero dostaje badge w rogach: jakosc po lewej, dlugosc po prawej, ten sam jezyk co na
kafelku, wiec przejscie z siatki do szczegolow nie zmienia zasad czytania.
Sekcja STUDIO zwinieta do linii metadanych (studio - serwis) pod tytulem. Zajmowala caly
blok na jeden chip. WAZNE: studio ZOSTAJE klikalne i dalej prowadzi do swoich scen,
zwiniecie wygladu nie moglo zabrac funkcji. Zweryfikowane na emulatorze: tap w "Gang AV"
otwiera ekran studia z 200 scenami.
Sekcja SOURCES usunieta. Pokazywala wewnetrzna nazwe konektora ("TUBE-SCRAPER"), ktora
uzytkownikowi nic nie mowila. Zastapiona nazwa serwisu wyliczana z originu (PORNDOE,
FULLPORNER) w tej samej linii co studio.
Naglowki sekcji dostaly kreske ciagnaca sie do prawej krawedzi: cztery sekcje mialy
cztery rozne odstepy i ekran nie mial rytmu.
Opis (Description) zostaje, wbrew makiecie, ktora go zgubila.
Zweryfikowane na emulatorze na prawdziwych danych (build debugowy podpisany kluczem
release): badge dlugosci, linia "Gang AV / PORNDOE", kreski przy naglowkach, zero
wystapien "TUBE-SCRAPER".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Kierunek A z makiet (miniaturki niosa ekran, chrome cichy) + jeden element z C:
jakosc i zrodlo widoczne wprost na kafelku.
Backend musial to najpierw WYSTAWIC, bo lista jedzie w trybie `light`, ktory okrawa
playback_sources do samej miniatury:
- `SceneOut.max_quality_p` (kolumna z migracji 0029, dotad uzywana tylko jako filtr),
- slim wpis niesie PRAWDZIWY `origin` zrodla wybranej miniatury zamiast "".
Kafelek: badge jakosci w LEWYM dolnym rogu (czas zostaje w prawym, ten sam ciezar
wizualny), a w linii meta studio + przygaszona nazwa serwisu. Badge pokazujemy TYLKO
gdy jakosc jest znana (6,5% scen), bo ma byc faktem, nie zgadywaniem.
Zweryfikowane na emulatorze na PRAWDZIWYCH danych: zeby to bylo mozliwe, zbudowalem
build debugowy podpisany kluczem release (przechodzi kontrole X-App-Signature, a jako
debug nie ma FLAG_SECURE, wiec da sie zrobic zrzut). Widac "4K" i "1280p" w rogu oraz
"ONLY FANS SXYPRN" w linii meta. Tymczasowa zmiana podpisu w build.gradle cofnieta.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Changelog: 17 sierpniowych wpisow drukowalo "AUGUST 2026" 17 razy, bo naglowek szedl
przy KAZDYM wpisie. Teraz wpisy sa laczone w grupy miesieczne (sa juz newest-first,
wiec wystarczy sklejac kolejne z tym samym `date`), naglowek leci raz na grupe.
Sites: usuniety tytul "SITES" + licznik i podpowiedz "tap a tube -> newest scenes".
Byl jedynym ekranem-zakladka z wlasnym naglowkiem, przez co jego tresc zaczynala sie
nizej niz na pozostalych. Martwe style (headerRow/headerLabel/headerCount/hint) wyciete.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zgloszenie 2026-08-18 (cztery zrzuty obok siebie): "rozne odstepy miedzy zakladkami,
kazda zakladka wyglada inaczej, rozne wielkosci text fields, rozne obramowki, chyba
nawet inne czcionki".
Przyczyna strukturalna: kazdy ekran-lista mial WLASNA kopie stylow search/toolbar/
przycisku filtra. Zmierzony dryf: rog pola 12 vs 10, ramka 1,5 vs 1, font 16 vs 14,
odstep toolbara 12 vs 8, dwa promienie pigulek (8 i 12), padding kontenera 16/16 vs
16/12 vs 0. "Inne czcionki" = etykiety mialy fontWeight:'700' BEZ fontFamily, a RN nie
syntezuje pogrubienia dla fontu custom -> chudy Regular zamiast bold.
Nowy `src/ui.tsx`: SearchInput, PillButton, Toolbar + wspolne stale SCREEN_PAD_*.
Jedna wysokosc kontrolek w wierszu, jeden promien, jedna ramka, waga przez fontFamily
(nie fontWeight), stan aktywny robi kolor. Scenes/Movies/Sites przepiete na to, ich
lokalne duplikaty stylow usuniete (w tym osierocony SegButton w Sites). JAV i Anime
reuzywaja ScenesScreen, wiec dostaja to samo za darmo.
Zweryfikowane na emulatorze: cztery zakladki jeden przy drugim maja identyczne pole,
przycisk, pigulki i marginesy. 403 na liscie to build debug spoza allowlisty, nie UI.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zgloszenie 2026-08-18: kropla "zrobila wiecej zlego niz dobrego". Trzy zarzuty,
wszystkie trafne:
- nie wygladala ladniej,
- rysunek SVG mial 44 px i wystawal ponad pasek, wiec naglowek spuchl i rozjechalo
sie wyrownanie wiersza do srodka,
- morfowanie ksztaltu nie przypominalo wzoru.
Research wzorcow z liderow (X/Twitter, YouTube, Reddit, App Store, Duolingo, apki
bankowe): gorne zakladki to wszedzie plaski, powsciagliwy pasek STALEJ WYSOKOSCI z
PRZESUWANYM wskaznikiem, nie morfowanym. Uzytkownik wybral podkreslenie (wzorzec
dominujacy na Androidzie).
TopTabsBar: aktywna zakladka = accentText + cienka kreska hugujaca tekst, przejezdza
w 220 ms ease-out (translateX + width z pomiarow onLayout). Wysokosc = wiersz tekstu,
wiec logo/zakladki/ikony znow sa w jednej linii. Naglowek wraca na theme.card (trik z
theme.bg byl tylko po to, zeby kropla byla widoczna).
Usuniete: LiquidTabs.tsx + lib/liquidTabPath.ts (caly aparat SVG-morph, martwy).
Zweryfikowane na emulatorze nagraniem klatka po klatce: kreska przejezdza Anime->Scenes
mijajac zakladki, kolory sie przelaczaja, laduje pod aktywna; wiersz wyrownany.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Prosba uzytkownika (zgloszenie 17376139). Backend mial juz parametr `min_quality_p`,
ale w praktyce byl NIEUZYWALNY i to zajelo wiekszosc pracy.
Wydajnosc, mierzona na produkcji przez EXPLAIN ANALYZE, prog 1080p:
EXISTS na playback_sources (stan zastany) 32 s 3 556 612 odwiedzonych scen
+ indeks funkcyjny per-scena 24 s
JOIN z DISTINCT po jakosci 1,1 s W IZOLACJI
ten sam JOIN + reszta filtrow feedu 52 s planer wraca do skanu po dacie
kolumna scenes.max_quality_p (0029) 2,0-2,6 s
+ indeksy czesciowe pod progi (0030) 0,09-0,11 s
Wniosek, ktory kosztowal najwiecej: ksztaltem zapytania sie tego NIE dalo zalatwic.
Koszt to LICZBA odwiedzonych scen, nie pojedynczy test, a przy `ORDER BY created_at
DESC LIMIT 24` planer i tak wracal do przechodzenia scen po dacie, gdy tylko doszly
pozostale filtry (bramka wertykalow, heurystyka szkieletow, prog dlugosci). Stad
denormalizacja + indeksy czesciowe z predykatem progu, ktore daja gotowe sortowanie.
Semantyka SUROWA, swiadomie: `quality` zapisujemy oportunistycznie, zna ja 6,5% scen
(210 302 z 3 236 368), najlepsze zrodlo ma 26% pokrycia. Wariant lagodny, przepuszczajacy
sceny o nieznanej jakosci, odrzucony po zmierzeniu: odsiewalby 88 647 z 3,2 mln, czyli
nie realizowalby intencji "nie chce ogladac ziemniaka". Filtr pokazuje wiec tylko jakosc
POTWIERDZONA, a UI mowi to wprost podpisem pod przelacznikiem, bo inaczej gwaltowny
spadek liczby wynikow wyglada na zepsuta aplikacje.
Warianty tekstowe 4K/UHD usuniete z warunku: 0 wystapien na 238 452 zywe zrodla,
a `OR ilike` blokowal uzycie indeksu.
Odswiezanie w taxonomy_counts (co 3h), z czyszczeniem do NULL gdy scena traci zrodlo
z jakoscia. Backfill: 210 302 sceny w 2m56s.
Zweryfikowane na emulatorze: sekcja MIN QUALITY renderuje sie z podpisem ostrzegawczym.
Lista wyszla pusta, ale to build debugowy dostajacy 403 (podpis debug spoza allowlisty),
nie blad filtra: ten sam URL z poprawnym podpisem oddaje 50 wynikow w 0,12 s.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dwa zgloszenia z apki, dwa rozne pierwotne powody.
perverzija (zgloszenie af9be63a, 520 bledow "Input does not start with #EXTM3U",
ZERO sukcesow): strona porzucila player xtremestream/xs1.php i osadza teraz mixdrop.
Stare URL-e xs1.php oddaja HTML zamiast manifestu HLS, stad kazdy playback padal.
Rejestr przelaczony z natywnego perverzija.extract na _embed_iframe.extract, ktory
wyluskuje mixdrop i oddaje type='hoster' -> telefon resolwuje w WebView. Natywny
ekstraktor zostaje w drzewie, gdyby xtremestream wrocil.
UWAGA co do weryfikacji: mixdrop gejtuje odtwarzanie za adsco.re (antybot). Sprawdzone
w prawdziwym Chrome na IP residential - MDCore.wurl zostaje null, zero requestu wideo,
bo brama celuje w AUTOMATYZACJE. Dla realnego usera w WebView player mixdrop gra
normalnie (to caly biznes mixdropa), ale nie dalo sie tego zautomatyzowac end-to-end.
To i tak scisle lepsze niz obecny stan 100% martwy.
naughtymachinima (zgloszenie ef728604 "od razu fallbackuje do strony, 502/429"):
ekstraktor SPRAWNY, direct mp4 bez tokenu, IP-bound do residential (403 z datacenter,
telefon gra). Telemetria 64 sukcesy / 19 bledow, blad to przejsciowy Connection reset
z CDN na dzialajacym URL-u. Bez re-resolve pojedynczy reset od razu spychal na WebView,
ktory ladowal zdlawiona strone tube'a - stad 502/429 w zgloszeniu. Dopisany do
BACKEND_RERESOLVE_ORIGINS: przy bledzie odswieza polaczenie zamiast uciekac do WebView.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zgloszenie: "zamiast slicznych animowanych przesuwajacych sie elementow mam
statyczna kropke". Dwie niezalezne przyczyny, obie konieczne do naprawy:
1. Animacja NIE MIALA FIZYCZNEJ MOZLIWOSCI sie wykonac. Kazda zakladka byla
osobnym ekranem native stacka, a przelaczenie robilo navigation.replace(t),
czyli wymienialo caly ekran razem z naglowkiem. LiquidTabs montowal sie od
nowa z kropla juz na docelowej pozycji (pierwsze ustawienie celowo bez
animacji). Fix: jeden HomeScreen, zakladka to stan lokalny, pasek przezywa
przelaczenie. key={tab} na tresci zachowuje dotychczasowy reset stanu.
2. Pasek byl NIEWIDZIALNY: wypelnienie theme.card na naglowku o tle theme.card.
Z calego "roztapiania" zostawala sama akcentowa kropka. Fix: naglowek na
theme.bg.
Do tego drobne: easing Easing.out(cubic) 260ms (wczesniej bez znaczenia, bo kod
nigdy nie dzialal); BugReportFAB czyta zakladke z params.tab (nazwa trasy to
teraz zawsze 'Scenes'); ikony naglowka ujednolicone na wszystkich zakladkach;
App.tsx: blad ladowania fontow przestaje wieszac boot na wiecznym spinnerze
(fail-open na system font) - obnazone przez rozjazd JS/natywki w dev buildzie.
Trasy Movies/Sites/JAV/Anime wyrejestrowane (nic poza paskiem do nich nie
nawigowalo); typy w RootStackParamList zostaja dla useNavigation.
Zweryfikowane nagraniem ekranu emulatora klatka po klatce: kropla plynie
Scenes->Sites i JAV->Anime z wedrujacym wglebieniem, pasek widoczny, tresc
i przycisk Performers/Tags zgodne z zakladka.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Domkniecie tej samej rodziny bledu co przy tagach i studiach. Pomiar rozstrzygnal,
ze oba wertykaly wymagaja INNEGO rozwiazania, wiec nie ma tu jednego filtra:
animacja 12 698 scen -> 0 performerow
JAV 54 888 scen -> 1 392 performerow
JAV: /performers dostaje parametr `vertical`, liczony na zywo, bo zdenormalizowany
`performers.scene_count` z zalozenia opisuje wylacznie glowny feed (job taxonomy_counts
wyklucza originy wertykalowe). Bez tego zakladka pokazywala zachodnia obsade, a wlasne
nazwiska mialy licznik 0 i ladowaly na koncu listy. Po zmianie: Satomi Suzuki (137),
Kei Mizushima (128), yui hatano (68).
Animacja: przycisk Performers jest chowany. Zero obsady to nie brak danych, tylko
wlasciwosc tresci: dla postaci rysowanych nie istnieje kanon (TPDB/StashDB ich nie maja),
wiec zaden scraper nie ma czego przypisac i zaden nigdy nie bedzie mial. Filtrowanie
dawaloby gwarantowanie pusta liste, czyli dokladnie ten sam objaw, ktory naprawiamy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Trzy rzeczy, jedna rodzina bledu "klikniecie prowadzi donikad".
1. Ekran Tags nie znal wertykalu, wiec z zakladki Anime i JAV pokazywal slownictwo
GLOWNEGO katalogu. Backend liczyl to poprawnie od dawna (parametr ?vertical=),
tylko apka go nie przekazywala. Po zmianie Anime dostaje swoje 3380 tagow
(Schoolgirl, Rape, Uncensored, Harem) zamiast zachodnich, ktore w tej sekcji nie
maja pokrycia. Tag otwarty z tej listy niesie wertykal dalej.
2. Lista i filtr przestaja pokazywac tagi z zerem scen: 33 427 z 208 822. To glownie
slownictwo animacji i JAV, bo `tags.scene_count` z zalozenia nie liczy scen
wertykalowych. Widac je bylo przy WYSZUKIWANIU (sortowanie po popularnosci trzymalo
je na koncu listy), a kazdy taki tag konczyl sie pustym ekranem.
3. Znaczniki jakosci zniknely wczesniej po stronie danych, wpis w changelogu.
Zakres swiadomie zatrzymany: `/performers` nie ma wsparcia dla wertykalu, wiec przycisk
Performers na zakladce Anime nadal pokazuje zachodnia obsade. To wymaga zmiany backendu
i jest osobnym zadaniem.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zgloszenia 195ae42e i e9de414c: klikniecie studia w anime nic nie robilo, a tag
kliniety w anime pokazywal sceny spoza anime.
Jedna przyczyna: TagScenes/StudioScenes/PerformerScenes wolaly listScenes BEZ
parametru vertical, a backend bez niego wyklucza wszystkie wertykaly. Studio
animacyjne mialo wiec zero scen (pusty ekran = wyglada na martwy klik), a tag
zwracal wylacznie sceny glownego katalogu.
SceneOut dostaje pole "vertical" liczone z originow zrodel, czyli jedno zrodlo
prawdy w app/verticals.py zamiast dublowania listy originow w apce. W trybie
light dociagamy origin z tego samego wiersza co miniaturka, wiec zero dodatkowych
zapytan. SceneDetail przekazuje wartosc dalej w paramach nawigacji.
Dotyczy tak samo sekcji JAV, ktora miala ten sam blad.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zgloszenie 7f2234eb: "samo wideo dziala, a aplikacja zglasza problem
z hostem". Ekstraktor NIE jest zepsuty:
- try_extract oddaje dzialajacy manifest w 0,4 s
- z Refererem ekstraktora (galaxy.4meplayer.pro) link daje 200; bez
niego 403, wiec naglowek jest ustawiany poprawnie
- pobranie przez nasze /proxy oddaje 200 i playliste z wariantem 1080p
- telemetria 14 dni: 1140 udanych, 25 bledow (2,1%)
Padal POJEDYNCZY nod CDN. Kolejne wywolania resolve tej samej sceny
wracaja z ROZNYMI adresami (185.237.107.133, potem 203.188.166.163), a
token ma ~2,8 h TTL i nie jest IP-bound. Czyli ponowny resolve po prostu
laduje na zywym wezle — dokladnie wzorzec, ktory dziala juz dla watchporn.
Stad `tube:galaxyporncom` w BACKEND_RERESOLVE_ORIGINS.
Po drodze skorygowany FALSZYWY komentarz w seekplayer_engine.py: twierdzil,
ze stream_proxy.py ma galaz `verify=False` dla hostow pod golym IP. Nie ma
jej — slowo `verify` nie wystepuje w tym pliku ani razu. `proxy_no_verify`
i `cf_fallback` sa ustawiane przez trzy ekstraktory i przez NIC nieczytane.
cf_fallback jest o tyle bolesny, ze to gotowy zapasowy URL, ktory uratowalby
wlasnie ten przypadek. Osobne zadanie.
Blad diagnostyczny po drodze, dla potomnosci: pierwszy test dal 404, bo
przetestowalem URL uciety wlasnym printem [:70], bez /master.m3u8.
Wzorowane na reelu _code_and_chill_ ("the bar melts around it"), ale
technika wzieta z jego drugiego zdania: "every socket is solved for
tangency, so the liquid never creases". Czyli sciezka LICZONA, nie
rozmywana.
Filtr "goo" (rozmycie + prog alfy) byl pierwszym pomyslem i zostal
ODRZUCONY po zajrzeniu w zrodlo react-native-svg. Filtry na Androidzie
dzialaja (GroupView extends RenderableView, ktory obsluguje mFilter), ale
RenderableView.java:376 przy KAZDYM rysowaniu robi Bitmap.createBitmap(
canvas.getWidth(), canvas.getHeight(), ARGB_8888), rysuje do niej element,
naklada programowy filtr i wrzuca wynik z powrotem. Przy animowanej kropli
to pelnoekranowa alokacja na klatke, w nagłowku KAZDEGO ekranu.
liquidTabPath: gniazdo to dwa luki styczne jednoczesnie do krawedzi paska
(srodek na y=top+k) i do kropli (odleglosc srodkow = r+k), stad
dx = sqrt((r+k)^2 - (top+k-cy)^2). Jedna <Path>, zero alokacji.
Weryfikacja liczbowa (nie wizualna): trzy niezmienniki stycznosci trzymaja
sie do 1e-9, piec przypadkow brzegowych OK. Test wylapal brakujacy warunek
`cy - r < top`: bez niego wzor ma rozwiazanie takze gdy kropla siedzi CALA
w pasku (top=26, cy=45, r=17, k=12 -> dx≈28,1) i powstawaloby gniazdo, w
ktore nie ma sie co wtopic.
Animacja: Animated.Value + listener przepisujacy cx do stanu, bo sciezka
to string i nie da sie jej podac Animated wprost (brak Reanimated w
projekcie). ~12 re-renderow SVG na 200 ms przejscia, poza tym komponent stoi.
useNativeDriver=false swiadomie: animujemy geometrie, nie transform.
Etykieta aktywnej zakladki siedzi na wypelnieniu akcentu — jasny tekst daje
tam 5,03:1, jedyny wariant tego koloru przechodzacy AA (patrz theme.ts).
Pomiar na 200 tys. grywalnych scen >=60 s (2026-08-13): przy JEDNEJ linii
pelny tytul widzialo **14,3%** scen. Mediana tytulu to 46 znakow, a w
kolumnie dwukolumnowej siatki miesci sie ~24 na linie, wiec 85,7% tytulow
bylo przycietych. Przy dwoch liniach pelny tytul widzi 54,4%.
To SWIADOMIE odwraca czesc wczesniejszej decyzji ("Jan feedback: wieksze
miniaturki, mniej tekstu" w docstringu tego pliku) — uzgodnione, bo tamta
uwaga dotyczyla nadmiaru metadanych, nie przycinania samego tytulu.
Miniaturka zostaje w tym samym rozmiarze, rosnie tylko blok tekstu (~18 px).
Do tego `titleWithoutStudio`: gdy druga linia pokazuje studio, zdejmujemy
jego nazwe z PRZODU tytulu ("MYLF - Aria's MILF Temptation" nad meta
"MYLF"). Dotyczy 8,2% scen. Zdejmujemy tylko przedrostek, wiec studio na
koncu tytulu ("… - ATKGirlfriends") zostaje nietkniete. Gdy po zdjeciu
zostaje <12 znakow, oddajemy tytul nietkniety, bo "Scene 1" jest gorsze
niz powtorzenie. 9 przypadkow testowych na realnych tytulach.
Korekta wlasnej diagnozy z przegladu: napisalem tam, ze tytul i studio
maja niemal rowna wage. Nieprawda — 14 px display/fg vs 10 px mono/muted
wersalikami. Hierarchia byla w porzadku, problemem bylo obciecie.
Pomiar WCAG na realnych parach z apki (2026-08-13):
accent #B23A48 jako tekst: 3,21 na bg | 2,96 na bgElevated | 2,75 na card
border #3A3128 jako granica: 1,48 na bg | 1,27 na card
Czyli kolor MARKI byl ponizej nawet progu 3:1 dla elementow interfejsu,
a nie tylko ponizej 4,5 dla tekstu. Dotyczylo to aktywnych zakladek,
gwiazdek ulubionych, linkow i chipow. Ramki przy 1,27 nie byly granica,
tylko cieniem.
NIE zmieniam koloru marki. Podniesienie samego `accent` do progu tekstu
wymagaloby zejscia w roz (#CE6975), co likwiduje tozsamosc, ktorej broni
naglowek theme.ts. Zamiast tego rozdzielam ROLE tego samego koloru:
accent zostaje do WYPELNIEN — jasny tekst na nim ma 5,03, przechodzi
accentText #C75260 dla tekstu i obwodek — 4,30 / 3,96 / 3,68
62 podmiany w 24 plikach (34 color, 26 borderColor, 2 thumbColor).
38 wypelnien nietknietych. Sprawdzone skryptem, ze zaden zmieniony tekst
nie stoi na tle akcentu.
borderStrong #7B7065 dla granic NIOSACYCH ZNACZENIE (pola tekstowe, 12
miejsc); dekoracyjne wloski zostaja na `border`. Wartosc dobrana pod obie
powierzchnie, bo pola leza i na bg, i na card: #6B6157 dawal na karcie
2,66, a #73695E dokladnie 2,999, czyli wciaz ponizej progu.
Studio bywa WYLACZNIE filmowe: Jonathan Jordan XXX 0 scen / 654 filmy,
Kink Clips 0/616, EAGLE 0/523. Lista ulubionych pokazywala wtedy samo
"0 scenes", czyli wygladala na pusta, mimo ze badge "+N" liczyl filmy
juz od 2026-07-28 (_merged_new_counts).
Backend: `FavoriteStudioOut.movie_count`, liczony NA ZYWO. Ulubionych
studiow jest kilkaset na urzadzenie, a filmow o rzedy wielkosci mniej niz
scen, wiec agregat jest tani i nie trzeba kolejnej zdenormalizowanej
kolumny do utrzymania.
Apka pokazuje oba liczniki, a gdy jednego nie ma, pomija go, zeby nie
robic z tego "0 scenes · 654 movies".
Domyka to temat zaczety zakladka Movies na ekranie studia: dodanie do
ulubionych od strony filmu juz dzialalo (gwiazdka w StudioMoviesScreen).
1. WERTYKALY. Hentai i 3D szly do glownego feedu wymieszane z zachodnim
katalogiem, mimo ze argument za odgrodzeniem byl ten sam co przy JAV.
Zamiast drugiej kopii mechanizmu JAV wprowadzam wspolne pojecie wertykalu
(app/verticals.py): mapa nazwa -> originy, jeden predykat, `?vertical=`.
Brama po originie jest DOKLADNA, zmierzone: 9507 scen animowanych, ZERO
z originem spoza listy (nie maja sie z czym zdeduplikowac). Dlatego osobna
baza nie jest potrzebna, rozdzielam logicznie.
Tagi to samodzielny powod: z 3116 tagow przy scenach animowanych tylko 452
wystepuja tez poza animacja, czyli 85% to slownictwo wylacznie animacyjne.
`/tags?vertical=` liczy je NA ZYWO (male zbiory, zero migracji), a
zdenormalizowany Tag.scene_count opisuje juz WYLACZNIE glowny feed.
Przy okazji naprawione zasmiecenie JAV-em istniejace od lipca:
taxonomy_counts wliczal wertykaly do licznikow, ktore opisuja feed ich
nie pokazujacy. Refresh: 1476 tagow, 1402 performerow, 154 studia.
Stary `?jav=true` DZIALA dalej (instalacje sprzed sierpnia go wysylaja).
2. FILMY NA EKRANIE STUDIA. Zgloszenie: polubione studio od filmow nie
pokazuje nowych filmow i nie ma "+1". Backend liczyl je poprawnie
(_merged_new_counts scala sceny i filmy od 2026-07-28). Blad byl w apce:
tap na ulubione studio ZEROWAL licznik (markStudioSeen) i wchodzil na
ekran wylacznie ze scenami, wiec "+N" z nowych filmow znikalo, a filmy
nie mialy sie gdzie pokazac. StudioMoviesScreen istnial, ale wchodzilo
sie do niego tylko z detalu filmu. StudioScenes dostaje zakladki
Scenes/Movies, jak PerformerScenes.
Pasek zakladek w headerze przewija sie w poziomie, bo piata pozycja
(Anime) nie miescila sie na waskich telefonach.
Animacje SFM/Blender. Kanon nie istnieje tak samo jak przy hentai, wiec
kazda pozycja jest orphanem i to poprawne.
Playback: KVS z jawnymi flashvars (4 jakosci, bez license_code), ale
`v-acctoken` jest ZWIAZANY Z IP tego, kto pobral strone. Test krzyzowy:
URL wygenerowany przez proxy i pobrany z VPS = 403, ten sam URL z IP
generujacego = 206 ftypisom 70 MB. Po zdekodowaniu tokenu adresu nie
widac wprost (inaczej niz fpoxxx), wiec samo ogladanie nie wystarcza.
Dlatego bez mobile_direct_ok: telefon resolwuje sam, UPFRONT, istniejaca
sciezka isGetFileUrl()/resolveGetFilePage z SceneDetailScreen. Rozszerzam
getfileResolver o flashvars, bo dotad umial tylko <source> (hdporn.gg,
fullmovies.xxx). Zweryfikowane end-to-end z residential IP: strona ->
flashvars 720p -> 302 na boomio-cdn -> 206 ftypisom 39,8 MB.
Bramka dlugosci zestrojona z `min_ingest_duration_sec` (prod 180 s)
zamiast wlasnej liczby: pierwsza wersja miala 60 s i liczniki klamaly
(seen 57, new 31, skipped 26). Po zestrojeniu seen 20, new 20, skipped 0.
Krotka tresc wycina ~70% katalogu (mediana 68 s).
Tagi TYLKO z class=tag_item. `class=button` wyglada na wlasciwe, a jest
chmura "Top Tags": przy filmie o Lux siedzialy tam "cell (dbz)" i
"queen of pain (dota)". Autor animacji zapisany jako studio.
1745 wystapien w 291 plikach (backend, scripts, mobile). Dominowal jeden ksztalt,
' — ' laczace zdania, wiec poszedl przecinek; myslnik otwierajacy mysl zdjety;
zakresy 0–5 i A–Z na dywiz.
Podzial komentarz/kod robil skaner stanow, nie regex, zeby nie ruszyc myslnika
stojacego w stringu albo w wyrazeniu regularnym. Potwierdzone maszynowo: po wycieciu
komentarzy z wersji HEAD i z dysku obie sa identyczne we wszystkich 291 plikach,
czyli poza komentarzami nie zmienilo sie nic. 233 pliki .py parsuja sie bez bledu,
tsc ma te same 11 bledow w tych samych 3 plikach co przed zmiana.
Dwie rzeczy wymagaly poprawki po automacie: wyrownane listy definicji, gdzie myslnik
byl separatorem kolumny (37 miejsc, kolumna przywrocona), i trzy przeniesienia mysli
do nowej linii, gdzie zostawal wiszacy przecinek na poczatku (poprawione recznie).
Bundla nie republikuje: Hermes i tak nie niesie komentarzy, wiec dla uzytkownika
to zero zmiany.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
32 miejsca w 14 plikach: changelog, onboarding, ekrany Sites/Blacklist/Login/Player,
komunikaty bledow, placeholdery. Zamiast myslnika przecinek, dwukropek, kropka albo
nawias, zaleznie od tego co dane zdanie robi.
Zostawione swiadomie: pojedynczy glif U+2014 jako znacznik BRAKU WARTOSCI
(release_year ?? '—', nieocenione osie w SitesScreen, separator zakresu w filtrze
filmow). To element interfejsu, nie proza, a zwykly dywiz wyglada tam gorzej.
Zostawione tez komentarze w kodzie, w tym te wewnatrz INJECTED_JS.
Przy okazji: MigrationBanner dostal twardy warunek na runtime (needsManualMigration).
Wczesniej przed pokazaniem go nowej wersji chronilo TYLKO to, ze kanal OTA 1.2 byl
pusty. Pierwsza publikacja na 1.2 wyslalaby ten sam bundle i baner kazalby migrowac
z wersji, na ktora user wlasnie przeszedl.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Weryfikacja na emulatorze (build debugowy, Metro): pasek i modal renderuja sie
poprawnie, kod synchronizacji sie pokazuje, przycisk otwiera goon-foss.org.
Tresc byla za dluga, urywala sie na naglowku kroku 4 i wygladala jak zepsuta;
po skroceniu miesci sie bez scrollowania.
Przy okazji potwierdzone na dexach: ExpoKeepAwake/KeepAwakeModule wchodzi teraz
do APK, wiec keep-awake zadziala po wydaniu 0.2.2.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Klucz podpisujacy stare buildy przepadl, wiec update in-place jest niemozliwy:
Android nadpisze aplikacje tylko buildem z tym samym podpisem. Odinstalowanie
czysci SecureStore, a w nim goon.device_id, czyli kod synchronizacji, bez ktorego
ulubione/postep zostaja na serwerze bez sposobu wskazania ich. Baner pokazuje kod
na wierzchu i prowadzi przez kroki (kopiuj kod, pobierz, odinstaluj, wklej kod).
expo-keep-awake: sprawdzenie stringow w dexach APK 0.2.1 potwierdzilo, ze modulu
ExpoKeepAwake tam nie ma (jest tylko interfejs z expo-modules-core), wiec ekranu
gasnacego w trakcie ogladania NIE dalo sie naprawic przez OTA. Teraz jawna
zaleznosc, autolinking ja widzi, wchodzi do APK 0.2.2 (runtime 1.2).
UWAGA przy publikacji banera na runtime 1.1: manifest bierze runtimeVersion z
argumentu --runtime, wiec 1.1 jest serwowane poprawnie mimo app.json=1.2, ale
extras nadal niosa app.json (APP_VERSION zaczyna raportowac 0.2.2). Dlatego
serwerowe /version trzeba bumpnac do 0.2.2 razem z wgraniem APK, inaczej stary
dialog Update available wyskoczy z mylacym Server 0.2.1 / App 0.2.2.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zgloszenie b52470be ('Doply resolver chyba padl', err 'Source error None of the').
Diagnoza: protokol dziala (doply -> playmogo, pass_md5 obecny, CDN oddaje 206
video/mp4), ale strona jawnie mowi '<h1>Not Found</h1> video you are looking for is
not found' - wideo jest USUNIETE. Detekcja szukala doslownej frazy 'video not found',
ktora w tym wariancie NIE pada, wiec resolver uznawal usuniete wideo za sukces.
Playmogo mimo usuniecia dalej wystawia token pass_md5 i serwuje plik-zaslepke, stad
u usera 'Source error' zamiast czytelnego komunikatu.
Rozszerzone markery: 'is not found', 'no_video_' (obrazek-zaslepka
i.doodcdn.io/img/no_video_3.svg - najpewniejszy), 'video has been deleted',
'file was deleted'. Blad 'video_deleted' jest NIEretryowalny, wiec apka od razu
pokaze komunikat i pozwoli oznaczyc zrodlo jako martwe.
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.
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.
User-request 89845707 ('quality customisation button in player'). Do tej pory
jakosc dalo sie wybrac TYLKO przed startem (PlaybackQualityModal w SceneDetail);
zeby ja zmienic, trzeba bylo wyjsc z playera i puscic scene od nowa.
SceneDetail przekazuje teraz cala liste jakosci w params.qualityLinks (label+url+
headers), player pokazuje ikone kolka gdy jest >1 wariant. Przelaczenie robi
replace() i przywraca pozycje sprzed podmiany (replace resetuje czas, wiec
zapisujemy currentTime i ustawiamy go po zaladowaniu), czyli user nie traci
miejsca w filmie. Lista jako overlay, nie Alert - Androidowy AlertDialog renderuje
max 3 przyciski, a jakosci bywa wiecej.
Bug-reports 40ec88cc / 92e9133e: perverzija zacina sie na pierwszych sekundach
i robi loop. Player xtremestream (pervl4.xtremestream.xyz) serwuje w HTML WYLACZNIE
preroll.mp4 + midroll1/2.mp4 z opencdn.b-cdn.net i odtwarza je zanim poda wlasciwy
stream (ten doladowuje sie dopiero w runtime, w kodzie strony go nie ma).
isLikelyAd odsiewal te URL-e przy auto-ekstrakcji, ale strona i tak je ladowala,
wiec user ogladal reklame w kolko. Dodane do AD_HOSTS.
To lagodzi objaw; pelny resolve streamu xtremestream wymaga przesledzenia XHR
w DevTools (osobne zadanie). Zasieg maly: 2 proby odtworzenia w 8 dni.
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.
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.
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
& 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.
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.
REGRESJA z 3355372 (diagnostyka sxyprn): wzorzec challenge sprawdzany PRZED
data-vnfo, a 'challenge-platform' to skrypt Cloudflare JSD wstrzykiwany do KAŻDEJ
strony za CF (bez challenge) → false positive na DOBRYCH stronach → return [] →
phone-resolve padał wszystkim → fallback backend/proxy → CAŁE wideo przez VPS
(potwierdzone: 49MB/chunk na trafficdeposit) + WebView z reklamami.
Fix: najpierw prawdziwy sygnał (data-vnfo), diagnoza powodu DOPIERO gdy go brak.
'challenge-platform' usunięty z listy (za szeroki). Diagnostyka znów czysto
obserwacyjna — nie przerywa resolve na heurystyce tekstowej.
Wykryte przez samą diagnostykę: sxyprn=challenge_197503b / challenge_75831b
(197KB/75KB = pełne strony, nie interstitiale).
'sxyprn ładuje reklamy' jest niereprodukowalny z naszych IP (strona zwraca
data-vnfo → resolver OK) → podejrzenie region/IP-gate u usera. resolveSxyprnPage
zapamiętuje powód ostatniego resolve (http_<status> / challenge_<len> /
no_vnfo_<len> / post_not_found / vnfo_parse_err / ok_N) i BugReportFAB dokleja go
jako sxyprn=<reason> do auto-contextu. Przy kolejnym zgłoszeniu zobaczymy CO sxyprn
realnie zwrócił temu userowi, bez pytania. Non-behavioral (nie rusza resolve).
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.
Sentry ddec9d6b (fatal, Android): RuntimeException 'Adding window failed' /
DeadObjectException gdy RN Alert (natywny DialogFragment) pokazuje się przez
WindowManager.addView na oknie activity które leci w tło / jest ubijane (martwy
binder). Trigger: alert z async handlera (np. 'Update available' na boocie)
odpalony gdy user zbackgroundował apkę.
Fix: globalny patch Alert.alert (src/lib/alertGuard, side-effect import w App.tsx)
— no-op gdy AppState.currentState !== 'active'. Obejmuje wszystkie ~56 call-site
bez owijania każdego. Transientowe alerty w tle i tak bez sensu; update wróci przy
następnym foregroundzie.
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.
Przy scrape ścieżce (WebView otwiera stronę hostera żeby przechwycić stream)
player hostera po autostarcie ustawiał video.muted=false / volume=1 i dźwięk
buchał zanim ExoPlayer przejął (raport usera). Sam override play() łapał za
wcześnie. Teraz LOCKujemy muted/volume na HTMLMediaElement.prototype: próba
odciszenia przed gestem usera jest ignorowana. Po tapie (watch-in-WebView dla
CF-blocked hosterów) odblokowanie + odciszenie istniejących <video>/<audio>.
Patch leci injectedJavaScriptBeforeContentLoaded, więc przed page JS.
Źródła które grają przez WebView (embed) → INJECTED_JS wyłuskuje direct mp4 →
nav.replace('Player', {mode:'video'}) gubiły origin i title. Player bez origin
→ success-effect (!playOrigin) SKIP → udane odtworzenia NIE raportowały się.
freshporno (KVS ale VPS resolve spada na embed → phone WebView-extract) miało
przez to 0 success / same błędy → health=0 → fałszywe offline.
3 nav.replace w EmbedWebViewPlayer (hoster-resolve, extractedUrl effect, banner)
teraz przekazują origin/title/playbackId/entityKind z params. Zweryfikowane na
realnym telefonie: origin=tube:freshpornoorg, success-effect FIRE, backend
zapisał 2× success.
Playback reports ("doesn't start", "audio lags") came in with no way to know the
device or which source/server was used, forcing a follow-up question. Now the bug
report auto-context also carries:
- device = phone model / Android version (Platform.constants, zero-dep)
- play = last-played origin/host, mode, position, and last player error
New in-memory lastPlayback store written by PlayerScreen on source/status change, read
by BugReportFAB when composing a report. Reset on app restart (current session only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
User request (07-10): a quick way to grab the direct video URL to share or open
elsewhere. Added a link icon in the player top bar that copies the current playing
URL to the clipboard (direct CDN URL for most sources, so it pastes into VLC/MX/a
browser; proxy-wrapped/referer-bound sources are best-effort).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>