Commit graph

161 commits

Author SHA1 Message Date
goon-foss
7ed878ce16 feat(mobile): gorne belki w jednym wierszu, pasek w Edge chowa sie przy przewijaniu
- SegmentTabs w ui.tsx: zakladki w wierszu narzedzi obok ikon
- Ulubione, performerka, studio, Performers i Tags: jeden wiersz pod naglowkiem
  zamiast trzech-czterech (etykieta z licznikiem, zakladki, podpowiedz, sortowanie)
- gwiazdka na ekranie performerki i studia bierze /favorites?counts=false
- Edge: kolejny klip chowa pasek, cofniecie pokazuje; podpis, przyciski i postep
  jada razem z paskiem; FAB zgloszen ukryty, lezal na "Not interested"
- changelog 2026-09-15c/d

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 15:37:53 +02:00
goon-foss
8462ab50df feat(mobile): zakladka nazywa sie Edge; /version 0.4.0 runtime 1.4
Nazwa od edgingu: feed krotkich klipow bez konca (wybor Jana). W kodzie zostaje
Swipe (SwipeScreen, swipeTelemetry), etykieta i teksty user-facing to Edge.
Backend /version podaje 0.4.0 / 1.4, wiec starsze APK dostaja monit o nowej
wersji; plik app-release.apk podmieniany razem z publikacja.
2026-09-15 09:29:40 +02:00
goon-foss
9872d5e4ca feat(mobile): zakladka Swipe, pionowy feed klipow (etap 4, APK 0.4.0 / runtime 1.4)
Nowa zakladka w dolnym pasku: react-native-pager-view (pion, natywny snap), dwie
instancje createVideoPlayer (aktywna + nastepna w buforze), komorka z posterem,
podpisem tworcy i tagami, kolumna przyciskow, pasek postepu. Gesty bez reanimated:
tap = dzwiek, double-tap = ulubione z wybuchem serca i haptyka, przytrzymanie = 2x,
przesuniecie w lewo = arkusz "show less of this" (tworca / tagi / nisze / seen it,
plus blokada tworcy). Onboarding 3 tapow z top tagow, AutoSwipe (off/5/10 s),
licznik obejrzanych, nowe rozdanie.

Telemetria: SwipeTelemetry zbiera zdarzenia i wysyla paczki co 5 s / 10 zdarzen /
w tle; przy opuszczeniu strony impression z dwell, skip (<2 s) albo complete (petla
lub >=80%). Serwer z tego uczy wagi i uklada 80% nastepnych stron.

Pager to modul natywny, wiec import jest miekki (require w try/catch) i zakladka
pokazuje sie tylko od runtime 1.4; ten sam bundle leci OTA na 1.2/1.3 z wpisem
"pobierz 0.4.0" (onlyBelowRuntime), a wpis o Swipe ma nowe pole minRuntime.
Bump: app.json 0.4.0 / runtime 1.4, versionCode 14, AndroidManifest 1.4,
publish_update RUNTIME_DEFAULT 1.4, strona goon-foss.org pod 0.4.0.

Sprawdzone na emulatorze (APK 0.4.0): zakladka widoczna, onboarding zapisany na
serwerze, feed spersonalizowany 8/2, ExoPlayer dekoduje wideo i audio, swipe daje
zdarzenia complete/impression, double-tap daje like + ulubione + wagi.
2026-09-15 09:24:13 +02:00
goon-foss
f28acf8f0d fix(player): rodzina DoodStream, warstwy reklamowe nad playerem nie lapia juz stukniec
- DOOD_OVERLAY_JS (injectedJavaScript po zaladowaniu): fixed + z-index > 100000 bez
  Cloudflare -> pointer-events none, iframe sandbox/srcdoc usuwany; co 700 ms
- diagnoza devtools: pelnoekranowy div opacity 0.01 z z 2147463647, iframe reklamowy i
  pusty kwadrat 80x80 dokladnie na przycisku play; popunder u nas zablokowany, wiec
  warstwa nigdy nie znikala (zgloszenia e9fc12e8, 1278eb49)
- changelog 2026-09-14c, OTA 69b27e52 na 1.3

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 15:40:42 +02:00
goon-foss
656604e868 feat(mobile): sortowanie losowe, najdluzsze i najkrotsze w filtrze scen; seed losowy per lista, nowy przy pull-to-refresh
- changelog 2026-09-14b, OTA 6770483f na 1.3

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 15:19:58 +02:00
goon-foss
d5fb3fb521 fix(mobile): reset filtrow dziala od razu, licznik filtrow wzgledem domyslnych, rok w filtrze filmow 1900..2100
- ScenesFilterModal: Reset all filters stosuje domyslne i zamyka arkusz (f5193fba)
- ScenesScreen: has_playback domyslnie wlaczone nie liczy sie jako filtr, za to sort,
  min. dlugosc, min. jakosc i stuby tak
- MovieFiltersSheet: rok poza 1900..2100 ignorowany zamiast 422 (2b6dbc75)
- changelog 2026-09-14a, OTA 6cca22ce na 1.3

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 14:38:59 +02:00
goon-foss
320d928927 feat(mobile): naglowki ekranow podrzednych jak sekcje glowne, ikony ulubione/ukryj, pasek dolny wyzszy z pierscieniem centrowanym przez layout
- screenOptions: tlo ekranu, bez cienia, tytul 17 display, tint accentText
- HeaderIconButton (star/star-outline, eye-off-outline) na 5 ekranach zamiast ★/🚫
- BottomTabsBar: 76 dp, pierscien statyczny w iconBox w spoczynku, kapsula tylko w
  trakcie przejscia, srodki zaokraglone do piksela
- changelog 2026-09-08b/c, OTA 1cbb9181 i 18ba425a na 1.3
2026-09-08 10:09:34 +02:00
goon-foss
44842478ae fix(studio movies): osobny klucz cache dla listy nieskonczonej, kolizja z useQuery w StudioScenes wywalala pages.length (Sentry 140915208)
- changelog 2026-09-08a, OTA 15f8e545 na 1.3
2026-09-08 09:53:20 +02:00
goon-foss
b0350baff0 fix(player): przekierowanie z pierwszego adresu przechodzi (myvidplay -> playmogo), rodzina dooda jako jeden host; jeden wiersz ikon na ekranie strony i performera
- WebView: przed pierwszym onLoadEnd kazda nawigacja top-frame to lancuch redirectow
  serwera, nie popunder; po zaladowaniu przeskoki w obrebie rodziny DoodStream tez OK
- SiteScenes: wyszukiwarka w obrebie strony + ikona tagow z licznikiem + X
- PerformerScenes: licznik scen + ikony szukaj-wiecej/filtr w jednym wierszu, chipsy
  top-tagow wyciete (tagi sa w filtrze), zbedne zapytanie performer-tags usuniete
- changelog 2026-09-07h, OTA 49cda698 na 1.3
2026-09-07 15:13:43 +02:00
goon-foss
e13463cba4 feat(sites): loga stron (favicon -> PNG w static, job co 24h) + sortowanie w arkuszu pod ikona
- scripts/site_icons.py: apple-touch-icon / icon / favicon.ico, PIL do 64x64 PNG,
  proxy Bright Data w odwodzie, mapa domen dla sitetagow bez TLD
- /sources: icon_url gdy plik istnieje (BACKEND_PUBLIC_URL albo wzgledne)
- SitesScreen: SiteLogo z literowym fallbackiem, SortSheet (most scenes, recently
  updated, best rated, name) zapamietany w SecureStore, koniec wiersza Top/Recent
- changelog 2026-09-07g, OTA 1e90f427 na 1.3
2026-09-07 12:13:58 +02:00
goon-foss
8c75b12066 feat(mobile): pasek chowa sie przy przewijaniu w dol (hystereza po drodze), FAB jedzie z nim, podpowiedz Sites do pierwszego przypiecia
- useAutoHideOnScroll: licznik drogi w jednym kierunku (48 px w dol chowa, 24 w gore
  pokazuje), strefy zawsze-widoczny przy gorze i dole listy, overscroll ignorowany
- HomeScreen useFocusEffect pokazuje pasek po powrocie z ekranu szczegolow
- changelog 2026-09-07e/f, OTA 40931479 i 8604dadb na 1.3
2026-09-07 11:53:31 +02:00
goon-foss
d9fbc08218 feat(mobile): pasek znika pod klawiatura, stukniecie w aktywna sekcje przewija na gore, Scenes w jednym wierszu ikon
- lib/bottomBar.ts: stale paska, szyna scroll-top, wartosc Animated do chowania
  (hysteresis po przebytej drodze, strefy gora/dol), inset dla list
- BottomTabsBar: absolute nad trescia, translateY z native drivera, null przy klawiaturze
- Scenes: Performers/Tags/Favorites jako IconButton obok lejka i zebatki, chipsy
  zapisanych wyszukiwan tylko przy fokusie albo wpisanym tekscie, Save jako chip
- changelog 2026-09-07d, OTA 3f7e21c5 na 1.3
2026-09-07 11:45:53 +02:00
goon-foss
90724af8ef feat(mobile): bez gornej belki, ikona filtra, darowizna i backend w ustawieniach
- pasek dolny nizszy (62) i przyciety na krawedzi ekranu, zaokraglone tylko gorne rogi
- IconButton (filter-variant z licznikiem) zamiast pigulki Filter, SettingsButton w
  wierszu narzedzi Scenes/Movies/Sites
- ustawienia: sekcje Support the project i Backend (host + wylogowanie), tytul Settings
- changelog 2026-09-07c, OTA 5c8895d6 na 1.3
2026-09-07 11:37:12 +02:00
goon-foss
dce738b8ab chore(mobile): usun gorny pasek zakladek, zastapiony dolnym 2026-09-07 11:23:56 +02:00
goon-foss
b847b300bf feat(mobile): zakladki na dole ekranu, pierscien swiatla rozciaga sie do nowej ikony
- BottomTabsBar: pigulka nad krawedzia, aktywna ikona w pierscieniu; przy zmianie
  przednia krawedz wystrzela, tylna dogania (kapsula od starej do nowej), jeden
  kolor accentText z miekka poswiata zamiast neonu z reela
- naglowek: nazwa sekcji obok logo zamiast gornego paska
- BugReportFAB wisi nad paskiem na ekranie-gospodarzu
- changelog 2026-09-07b, OTA a2328005 na 1.3
2026-09-07 11:23:49 +02:00
goon-foss
7fe9a11136 chore(mobile): wpis changelogu o tubepornclassic, porndupe i kolejnosci zrodel w filmach
Nowe strony wchodza po stronie backendu, wiec bez publish OTA uzytkownik nie
dostaje popupu What's new (changelog jedzie w bundlu). Sam wpis, bez zmian w
kodzie apki.
2026-09-07 10:15:21 +02:00
goon-foss
9c988bc12a feat(mobile): przypinanie stron w zakladce Sites + filtry zapamietywane per sekcja
Dwie prosby z apki 2026-09-02.

Sites: dlugie nacisniecie przypina albo odpina strone (gwiazdka i akcent na ramce),
przypiete ida na gore listy w tej samej kolejnosci co reszta, takze przy szukaniu i przy
sortowaniu "Recent". Stan po stronie serwera (/favorites/sites), wiec przechodzi kodem
synchronizacji jak inne ulubione.

Filtry: `usePersistedState` w SecureStore, osobny klucz dla Scenes, JAV, Anime
(`filters_<sekcja>`) i Movies. Zapis dopiero po wczytaniu, zeby domyslne z pierwszego
renderu nie nadpisaly zapisanych; odczyt scalany z domyslnymi, zeby nowe pole w kolejnej
wersji dostalo wartosc. Zapytanie o liste czeka na wczytanie (`enabled`), bez podwojnego
strzalu. SecureStore ma ~2 KB na klucz; przy bardzo dlugiej liscie tagow zapis moze sie
nie udac i wtedy filtr zyje tylko do zamkniecia apki, ale ekran sie nie wywraca.

tsc: 11 bledow przed i po (baza). Wpis w changelogu 2026-09-02b.
2026-09-02 22:44:54 +02:00
goon-foss
e5eb27228e fix(player): dolny pasek sterowania nad systemowym paskiem nawigacji
Zgloszenie 386ef7ab (Galaxy S25, Android 16, nawigacja trzema przyciskami): pasek
przewijania niewidoczny w pionie. `controlsBottom` mial `bottom: 0` i stale
`paddingBottom: 18`, bez marginesow systemowych. Od Androida 15 apka rysuje pod paskiem
nawigacji, wiec przy trzech przyciskach (~48 dp) scrubber ladowal pod nimi.

Dolozony `useSafeAreaInsets()`: dol plus lewy i prawy, bo w poziomie pasek przyciskow
siedzi z boku. Z gestami margines to kilka dp, wiec wyglad prawie bez zmian.
`SafeAreaProvider` juz owija apke, ten sam hook jest w nawigacji.

tsc: 11 bledow przed i po, zadnego w okolicy zmiany. Wpis w changelogu 2026-09-02a.
2026-09-02 12:26:20 +02:00
goon-foss
dd87f646cc docs(changelog): wpis 2026-08-27a (vjav gra, odswiezanie zrodel 8kporner i perverzija, 81 tys. martwych zrodel usunietych) 2026-08-27 20:40:15 +02:00
goon-foss
ef43b61a12 fix(playback): odrzucaj nie-manifest z 200 i odswiezaj zrodlo dla 8kporner i perverzija
Sprawdzenie dwoch tubow, ktore w statystyce bledow odtwarzania wygladaly zle. Oba maja
inna przyczyne niz vjav i ZADEN nie jest awaria calego tuba.

**perverzija.** Naglowkowe "44% bledow" jest mylace: 132 ze 176 bledow pochodzi z awarii
13-18 sierpnia, ktora sama minela (te dni maja zero udanych odtworzen). Ostatnie 8 dni to
~16%. Wszystkie trzy sceny, ktore realnie padly u userow, resolwuja sie dzis poprawnie i
przechodza przez /proxy/hls jako prawidlowy manifest, wiec biezacej awarii nie ma.

Zostaje jednak realna dziura: hoster potrafi oddac 200 z trescia, ktora manifestem nie
jest (strona bledu albo reklama). Przepuszczalismy to dalej jako
`application/vnd.apple.mpegurl` ze statusem 200, a odtwarzacz konczyl komunikatem "Input
does not start with the #EXTM3U header" (203 zdarzenia w 14 dni). Gorsze od samego bledu
bylo to, ze przy statusie 200 apka uznawala odpowiedz za dobra i nie probowala odswiezyc
zrodla. Teraz w takiej sytuacji leci 502.

**8kporner.** Bledy to 502 i 400 z okcdn, rozlozone rownomiernie, przy stale dzialajacym
tubie. To zwietrzaly zapisany adres, ten sam wzorzec co watchporn. Potwierdzone na
czterech scenach, ktore padly u userow: swiezy resolve kazdej z nich oddal 206 z trescia.
Jeden przypadek w tej probce byl bledem DNS po stronie klienta, nie naszym.

Stad oba origins dopisane do `BACKEND_RERESOLVE_ORIGINS`, czyli mechanizmu juz dzialajacego
dla watchporn i galaxyporn.

Sprawdzone na prodzie po wdrozeniu: prawdziwy manifest dalej przechodzi (200, 58 kB),
a odpowiedz nie bedaca manifestem dostaje 502 zamiast 200 ze smieciami.
2026-08-27 20:36:24 +02:00
goon-foss
38eee03902 fix(player): nie wstrzykuj naszego skryptu na stronach rodziny DoodStream
Zgloszenie Jana: myvidplay i easyvidplayer na filmach dalej nie dzialaly, mimo
wczorajszych poprawek backendu.

Backend byl OK, sprawdzone na zywo: myvidplay resolwuje sie teraz na playmogo.com, a
easyvidplayer oddaje 410 i znika z listy. Problem byl PO STRONIE APLIKACJI.

Playmogo (tam laduja myvidplay i doply) zmienil zabezpieczenie. Nasza notatka mowila, ze
to niewidzialny Turnstile przechodzacy automatycznie. To juz NIEPRAWDA: ich strona wola
turnstile.render z size flexible, czyli WIDOCZNY widget, i to dopiero po kliknieciu w
przycisk play, a po weryfikacji przeladowuje strone i dopiero wtedy pojawia sie pass_md5.

Nasz wstrzykiwany skrypt psul dokladnie ten przeplyw. Widget siedzi w kontenerze o klasie
captcha-player z z-index 100000, czyli w tym, co nasz usuwacz nakladek traktuje jak
reklame, a nasze auto-klikniecie w plakat odpalalo brame, zanim widget zdazyl sie
wyrenderowac. Do tego patchujemy prototypy HTMLMediaElement, co Turnstile potrafi uznac
za podejrzane srodowisko (dokladnie ten sam objaw mielismy na vikingfile).

Straz, ktora dotad obejmowala tylko vikingfile, obejmuje teraz cala rodzine bramkowana
Cloudflare. Na stronie pliku i tak nie potrzebujemy ani wyciszania autoplay, ani ad-blocka.

Pulapka po drodze, warta zapamietania: komentarz z backtickami wewnatrz literalu
szablonowego INJECTED_JS przerywa ten literal i wywala parsowanie calego pliku.

Zweryfikowane: regex po rozwinieciu szablonu pomija playmogo/myvidplay/doply/vikingfile/
d0000d/ds2play, a zostawia dzialajacy skrypt na galaxyporn, sxyprn i eporner; podobnie
brzmiacy goodplay.com sie nie lapie. Typecheck wrocil do bazowych 11 bledow.

NIE mam na to dowodu z urzadzenia: przejscie Turnstile trzeba potwierdzic na telefonie.
2026-08-27 09:10:16 +02:00
goon-foss
c0a5d02ece feat(performers): pelny filtr scen na ekranie performera
Prosba 39314780: "Add similar filters to when we search for videos by pornstars".

Ekran performera dostaje TEN SAM modal co glowny feed (ScenesFilterModal), nie osobny:
jakosc, minimalna dlugosc, sortowanie, zrodlo/hoster, tagi, studia oraz "Also featuring"
(sceny takze z inna osoba). Chipsy top-tagow zostaja OBOK, jako jednodotykowy skrot na
najczestszy przypadek; ich wybor scala sie z tagami z modala.

Trzy roznice wzgledem glownego feedu, wszystkie zamierzone:
* domyslne sortowanie po dacie premiery (tak ten ekran dzialal od zawsze),
* prog dlugosci domyslnie 0 (wejscie w konkretnego performera nie ma ukrywac scen o
  nieznanej dlugosci, bo NULL nie przechodzi `>= 60`; wybor "5+ min" podnosi go jawnie),
* "Also featuring" zamiast "Performers": backend laczy performer_ids koniunkcja, wiec
  wybrani sa dokladani do biezacego performera przez AND, nie zastepuja go. Modal
  dostal na to prop `performersLabel`.

Licznik na przycisku liczy sie wzgledem domyslnych TEGO ekranu, inaczej has_playback=true
podbijaloby "Filter 1" na czysto.

Backend bez zmian: /scenes juz przyjmuje wszystkie te parametry.
2026-08-26 14:19:36 +02:00
goon-foss
ccba96376c fix(performers): "Search more scenes" odpowiada od razu, wyszukiwanie mieli w tle
Zgloszenie 23c64a28: "Search more scenes button not working". Przycisk DZIALAL, tylko
wygladal na zepsuty: endpoint byl synchroniczny i przy performerce z 871 scenami search
po ~25 tubach trwal dluzej, niz telefon utrzymuje polaczenie. W logu zostaly 4 starty
performer_driven bez ANI JEDNEJ domknietej odpowiedzi HTTP: kazdy tap konczyl sie
"Refresh failed", uzytkownik klikal znowu i szukania mielily sie rownolegle, a wyniki
i tak dopisywaly sie w tle, tylko bez zadnego sygnalu dla czlowieka.

Endpoint startuje teraz watek i odpowiada od razu (`status="started"`). Rate-guard 60s
bez zmian, `last_searched_at` idzie w gore PRZED startem watku, wiec chroni tez przed
zdublowaniem samego startu. Watek ma wlasna obsluge bledow, bo nie ma juz requestu,
ktoremu moglby oddac wyjatek.

Mobile: przy `status="started"` komunikat "Searching... new finds appear within a
minute or two" i odswiezenie listy po 60 s. Stare pola odpowiedzi zostaly, wiec klient
sprzed OTA pokaze "0 new scenes", co jest znosne przez kilkuminutowe okno do publikacji.

Zweryfikowane na produkcji: odpowiedz w 0,03 s, drugi strzal 429, watek tla skonczyl
po 30 s i zalogowal wynik.
2026-08-26 14:12:25 +02:00
goon-foss
031c309091 fix(mobile): stary APK po OTA podawal sie za nowa wersje i nie dostawal monitu
Zgloszone przez uzytkownika: po wydaniu 0.3.0 nie dostal propozycji aktualizacji.

Przyczyna jest moja. `APP_VERSION` czyta `Constants.expoConfig.version`, czyli app.json,
a app.json przyjezdza do aplikacji RAZEM Z PACZKA OTA. Podbilem wersje na 0.3.0 i
opublikowalem te paczke rowniez na stary kanal 1.2, wiec kazdy uzytkownik APK 0.2.2
zaczal raportowac 0.3.0 i sam siebie uznal za aktualnego. Skutek podwojny: nie dostal ani
monitu o nowym APK, ani wpisu w changelogu, ktory byl kierowany dokladnie do niego.

Poprzednia poprawka (dad4bbf, porownanie "nowsza" zamiast "rozna") tego NIE naprawiala:
przy dwoch identycznych numerach oba warunki daja falsz.

Jedyny numer odporny na OTA to runtime z AndroidManifest, bo expo-updates uzywa go do
sprawdzania zgodnosci paczek i nie moze brac go z paczki. Stad `NATIVE_RUNTIME`
w `src/lib/appVersion.ts`, a serwer oddaje teraz `runtime_version` obok `version`.
Porownanie leci po runtime, z zapasowym porownaniem wersji, gdy serwer go nie poda.
Bramka wpisow w changelogu przeszla z `onlyBelowVersion` na `onlyBelowRuntime`.

`expo-application` bylby czystszym zrodlem natywnej wersji, ale to modul natywny, wiec
nie wszedlby przez OTA do ludzi na starym APK, czyli dokladnie do tych, ktorych to
dotyczy. Runtime dziala na tym, co juz maja zainstalowane.

Przy okazji tresc dialogu: pokazywala "Server: 0.3.0, App: 0.3.0", czyli dwie identyczne
liczby, bo drugi numer byl z paczki, a nie z APK. Teraz nie pokazujemy numeru
zainstalowanej wersji, bo po OTA nie mamy wiarygodnego.

Zweryfikowane na emulatorze w obie strony, na podpisanych APK:
* APK 0.2.2 (runtime 1.2) po pobraniu paczki: monit jest, tresc czytelna.
* APK 0.3.0 (runtime 1.3): monitu nie ma.
Instalacja 0.3.0 na wierzch 0.2.2 przeszla ponownie.
2026-08-24 14:47:04 +02:00
goon-foss
bdac60f022 feat(mobile): Chromecast (0.3.0, runtime 1.3)
Zgloszenie de93ba42 ("Can't stream to Chrome cast"). Cast to natywny SDK, wiec NIE da
sie go wyslac przez OTA: to nowe APK, ktore ludzie musza pobrac sami. Klucz podpisujacy
ten sam, wiec ALLOWED_APP_SIG_HASH bez zmian i aktualizacja wchodzi na wierzch starej.

Argument, ktory przewazyl: od czerwca release ma wlaczone FLAG_SECURE, wiec zwykle
mirrorowanie ekranu na telewizor jest zablokowane. Cast jest jedyna droga na duzy ekran.

Zasieg: 77% udanych odtworzen konczy sie bezposrednim adresem, plus czesc hosterow
filmowych oddajacych gotowy plik. Okolo 13% (porndoe, mypornerleak, superporn) idzie
przez WebView i castowac sie NIE DA, tam przycisku nie ma.

Wpiete recznie, bez `expo prebuild`, bo katalog android/ jest w repo i ma reczne zmiany,
ktore prebuild by przepisal. Cztery edycje, dokladnie to co robi config plugin:
manifest (OPTIONS_PROVIDER + expanded controller), MainActivity, castFrameworkVersion
w rootProject.ext oraz JAWNA zaleznosc play-services-cast-framework w app/build.gradle.
Ta ostatnia jest konieczna, bo biblioteka deklaruje ja jako `implementation`, co nie
jest przechodnie na sciezke kompilacji, i bez niej build pada na compileReleaseKotlin.

Identyfikator odbiornika CELOWO zaden: bez wpisu biblioteka bierze domyslny odbiornik
Google. Rejestracja wlasnego wiazalaby konto Google z Goonem, a przy tresci dla
doroslych latwo o cofniecie.

Urzadzenia bez Google Play Services zabezpieczone w DWOCH miejscach, bo mamy uzytkownika
na LineageOS (GOON-3B) i sideload na zegarku (GOON-51): `getSharedInstance` w try/catch
po stronie natywnej, a po stronie JS cala obsluga w osobnym `CastControl`, montowanym
dopiero gdy `useCastAvailable` potwierdzi Play Services. To nie jest ostroznosc na
wyrost: hooki biblioteki synchronicznie subskrybuja natywne zdarzenia i bez GMS wywracaja
ekran, a hooka nie da sie wywolac warunkowo.

Chromecast pobiera plik SAM i nie wysyla naszych naglowkow, wiec zrodla wymagajace
Referera ida przez /proxy (dokłada go po stronie serwera), a reszta bezposrednio, zeby
nie obciazac VPS. Do tego proxy przestaje przekazywac CORS hostera: mixdrop oddawal
`Access-Control-Allow-Origin: https://mixdrop.my`, co odbiornik odrzucal przy HLS.

Przy okazji GOON-3B: doszedl brakujacy wpis `com.google.android.gms.version`, ktory
wywracal apke na LineageOS, gdy Chromium probowal podpiac skaner kodow.

Zweryfikowane na emulatorze na podpisanym APK: certyfikat identyczny ze starym
(3294aba5...), instalacja NA WIERZCH 0.2.2 udana, wersja 13/0.3.0, runtime 1.3 w
manifescie, aplikacja wstaje bez crasha, ExoPlayer gra (MediaCodec dla video), a SDK
Casta startuje poprawnie: dynamite sie laduje i `MediaRouterProxy` czyta NASZ CastOptions.
Logika wyboru adresu przetestowana osobno na osmiu przypadkach.

CZEGO NIE ZWERYFIKOWALEM: realnego rzutu na telewizor. W sieci emulatora nie ma zadnego
Chromecasta, wiec `loadMedia` i odtwarzanie po stronie odbiornika sa niesprawdzone.

Build wymaga SENTRY_DISABLE_AUTO_UPLOAD=true, bo sentry.properties czeka na
SENTRY_ORG/SENTRY_PROJECT/SENTRY_AUTH_TOKEN ze srodowiska (Infisical, workspace
goon-app). Skutek: slady JS z 0.3.0 beda w Sentry nieczytelne do czasu przebudowy z tymi
zmiennymi.
2026-08-24 14:27:41 +02:00
goon-foss
dad4bbf0ab fix(mobile): nie namawiaj na instalacje STARSZEJ wersji
Apka porownywala wersje z serwerem przez `!==`, a nie "nowsza niz moja". Serwer trzyma
numer najnowszego APK na sztywno w `app/main.py`, wiec w momencie, gdy aplikacja
wyprzedza serwer, KAZDY uzytkownik nowej wersji dostawal monit "Update available" z
propozycja zejscia w dol.

Zlapane na emulatorze przy weryfikacji 0.3.0: swiezo zainstalowana 0.3.0 kazala
zainstalowac 0.2.2. Bez tej weryfikacji poszloby to do ludzi.

Wspolny `isNewerVersion` w `src/lib/appVersion.ts`, uzywany teraz i przez monit o APK,
i przez bramkowanie wpisow w changelogu (byla tam druga kopia tej samej logiki).
Sprawdzone na przypadkach granicznych, w tym 0.3.10 wobec 0.3.9 i pusta odpowiedz
serwera.
2026-08-24 14:27:06 +02:00
goon-foss
c9fa6edc6d feat(mobile): scalaj wiele duplikatow naraz zamiast parami
Zgloszenie c7f5e59e: "przydalaby sie mozliwosc zaznaczania wiecej niz 2 video
przy duplikatach". Przy pieciu kopiach tej samej sceny stary uklad wymagal
czterech przebiegow, kazdy z osobnym dialogiem, i za kazdym razem trzeba bylo
na nowo wskazac oryginal.

Model jest teraz odwrocony: dlugie przytrzymanie wybiera scene, ktora ZOSTAJE
(plakietka KEEP), a kolejne tapniecia zaznaczaja i odznaczaja jej duplikaty
(plakietka DUPLICATE, kafelek gasnie). Banner liczy zaznaczone i scala wszystkie
jednym przyciskiem. Dzieki temu uzytkownik swiadomie wybiera te kopie, ktorej
tytul i miniaturka przetrwaja, zamiast trafiac w nia przypadkiem.

Backend bez zmian, endpoint scala parami, wiec lecimy petla. Kazde scalenie to
osobna transakcja, wiec czesciowa porazka nie cofa udanych i raportujemy ja
wprost zamiast udawac sukces.

Sprawdzone na emulatorze na opublikowanej paczce: pozycja w menu, plakietki
KEEP i DUPLICATE, licznik 2 -> 1 -> 2 przy odznaczaniu, tresc potwierdzenia
z lista scen. Samego scalania nie wykonalem, to sa prawdziwe sceny z produkcji.
2026-08-23 21:25:32 +02:00
goon-foss
646f03d7be test(player): nie wstrzykuj naszego skryptu na stronach z Turnstile
Kolejny podejrzany o negatywna weryfikacje Cloudflare: nasz wlasny INJECTED_JS.
Wstrzykujemy go PRZED zaladowaniem strony, a on podmienia gettery i settery na
prototypie HTMLMediaElement (wyciszanie autoplay) oraz usuwa elementy uznane za
reklamy. Turnstile potrafi uznac tak zmodyfikowane srodowisko za podejrzane.

Na hostach vikingfile konczymy teraz wykonanie zaraz po naszym bloku: zostaje tylko
podswietlenie ramki z zabezpieczeniem, meldunek needs_interaction i podsluch POST-a
z bezposrednim linkiem. Reszta patchy sie nie wykonuje. Na stronie pliku i tak nie
potrzebujemy ani wyciszania autoplay, ani ad-blocka.

To jest TEST HIPOTEZY, nie potwierdzona naprawa. Nie udalo mi sie odtworzyc bledu u
siebie: w Chrome na emulatorze, na tej samej sieci, weryfikacja przechodzi zarowno w
trybie mobilnym, jak i desktopowym. Do apki na emulatorze nie dojde ta scena, bo ma
duration NULL i w glownym feedzie jest ukryta progiem 60 s, a przez strone aktorki
trzeba by przewinac 701 pozycji.

Przy okazji: naprawiony pojedynczy backslash w regexie hosta (szablon go zjadal) i
zaktualizowany komentarz naglowkowy, ktory dalej opisywal chowanie strony, usuniete
dwie zmiany wczesniej.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 21:35:42 +02:00
goon-foss
2071b36311 fix(player): nie podstawiaj desktopowego UA hosterom z Cloudflare
Dla hosterow z zabezpieczeniem Cloudflare (vikingfile, playmogo, klony DoodStreama)
przestajemy nadpisywac User-Agent i zostawiamy wlasny UA WebView. Dotad podstawialismy
Chrome na Windows, podczas gdy silnikiem jest Android WebView, a Cloudflare porownuje
deklaracje ze srodowiskiem.

UCZCIWE ZASTRZEZENIE: to NIE jest potwierdzona przyczyna. Test A/B w Chrome na
emulatorze (ta sama siec co telefon): tryb mobilny przechodzi weryfikacje, tryb
desktopowy TEZ przechodzi. Czyli sam UA nie wystarcza do odtworzenia bledu. Zmiane
zostawiam, bo zgodnosc UA ze srodowiskiem jest po prostu poprawniejsza, ale przyczyny
szukam dalej. Kolejny podejrzany: nasz INJECTED_JS, ktory patchuje prototypy
HTMLMediaElement przed zaladowaniem strony.

Potwierdzone przy okazji: strona i wyzwanie dzialaja na tej sieci, po klikniecu
checkboxa pojawia sie odtwarzacz i przycisk Download.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 21:27:24 +02:00
goon-foss
46e7839fb2 fix(galaxyporn): czarny ekran to zablokowane przekierowanie na druga domene
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>
2026-08-22 20:03:54 +02:00
goon-foss
a1717e4b5e fix(player): czarny ekran na galaxyporn to byla 15-sekundowa zaslona
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>
2026-08-22 19:52:33 +02:00
goon-foss
1f73dad7d3 feat(vikingfile): przechwytuj bezposredni link zamiast pokazywac strone
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>
2026-08-22 19:46:13 +02:00
goon-foss
1154834170 fix(player): oswoj strone vikingfile, zeby nie wygladala na pusta
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>
2026-08-22 19:24:31 +02:00
goon-foss
a62d438500 fix(player): po nieudanym resolverze wchodz od razu w WebView
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>
2026-08-22 19:17:33 +02:00
goon-foss
1e6be1926e fix(mobile): zdejmij maintainVisibleContentPosition, wywala apke na amen
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>
2026-08-20 17:01:54 +02:00
goon-foss
b4c1216133 fix(player): nie twórz playera, gdy apka jest w tle
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>
2026-08-20 12:16:33 +02:00
goon-foss
ae3c4ac9bb fix(listy): prog dlugosci nie ukrywa juz scen o NIEZNANEJ dlugosci w drill-downach
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>
2026-08-20 10:07:58 +02:00
goon-foss
20c04698b1 fix(player): scrubber seekuje takze gdy dlugosc zna tylko scena, nie player
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>
2026-08-18 14:55:32 +02:00
goon-foss
068a65dd8c feat(ui): przebudowa ekranu szczegolow sceny wg makiety (kierunek A)
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>
2026-08-18 14:36:56 +02:00
goon-foss
bbc2059728 feat(ui): badge jakosci i nazwa serwisu na kafelku sceny
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>
2026-08-18 12:41:16 +02:00
goon-foss
576058497a fix(ui): grupuj changelog po miesiacu, zdejmij naglowek z Sites
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>
2026-08-18 12:23:04 +02:00
goon-foss
17e4ecaa8a fix(ui): jeden wspolny zestaw kontrolek naglowka zamiast kopii per ekran
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>
2026-08-18 11:42:32 +02:00
goon-foss
6d338219ea fix(ui): przesuwane podkreslenie zamiast ciekłej kropli w zakladkach
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>
2026-08-18 11:22:02 +02:00
goon-foss
0fed952c5c feat(filtr): minimalna jakosc w filtrze scen (720p/1080p/4K)
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>
2026-08-18 11:06:34 +02:00
goon-foss
085c0c1dd6 fix(playback): perverzija na nowy hoster, naughtymachinima re-resolve na reset
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>
2026-08-18 10:23:05 +02:00
goon-foss
0949091f78 fix(ui): pasek zakladek naprawde plynie - zakladki jako stan, nie trasy
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>
2026-08-18 09:59:24 +02:00
goon-foss
f48fbbd4ad fix(performers): wlasna obsada dla JAV, brak przycisku dla animacji
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>
2026-08-14 12:51:39 +02:00
goon-foss
3818cd6141 fix(tags): wlasna lista tagow dla wertykalow + bez tagow z zerem scen
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>
2026-08-14 12:41:07 +02:00
goon-foss
a1f604a7a4 fix(verticals): przenos wertykal przy przejsciu do tagu/studia/performera
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>
2026-08-14 11:42:47 +02:00
goon-foss
47547fe694 fix(playback): galaxyporn re-resolwuje sie po bledzie zamiast poddawac
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.
2026-08-14 10:22:08 +02:00