Commit graph

297 commits

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 14:06:01 +02:00
goon-foss
8462ab50df feat(mobile): zakladka nazywa sie Edge; /version 0.4.0 runtime 1.4
Nazwa od edgingu: feed krotkich klipow bez konca (wybor Jana). W kodzie zostaje
Swipe (SwipeScreen, swipeTelemetry), etykieta i teksty user-facing to Edge.
Backend /version podaje 0.4.0 / 1.4, wiec starsze APK dostaja monit o nowej
wersji; plik app-release.apk podmieniany razem z publikacja.
2026-09-15 09:29:40 +02:00
goon-foss
538a72107e perf(clips): explore po podzapytaniu okna, kandydaci bez ORM i bez tagow, max(uuid) przez tekst
Strona feedu spadla z 310-470 ms do 50-130 ms (srednio 85 ms na 30 stronach,
0 powtorek). Postgres nie ma max(uuid): koniec okna liczony po rzutowaniu na
tekst (ten sam porzadek dla malych hex w stalym formacie).
2026-09-14 20:34:19 +02:00
goon-foss
0df2236b37 feat(clips): feed Swipe z afinicznoscia, pamiecia widzianych i telemetria (etap 3)
Tabele per urzadzenie (migracja 0037): clip_seen (wykluczenie, wiersz przy
podaniu klipu), clip_feed_events (append-only: impression z dwell, skip,
complete, like, unlike, not_interested, autoswipe), clip_affinity (wagi
tag/nisza/tworca w JSONB), clip_favorites, clip_blacklist. GIN na clips.niches.

GET /clips/feed: kursor base64 {seed, pk, page} zamiast offsetu; 80% z puli
afinicznosci (skany po tagu/niszy/tworcy od losowego uuid, punktacja
sum wag + 0,3 ln(1+lajki) + swiezosc, max 2 klipy tworcy na strone) + 20%
explore (okno 2000 id po PK, losowanie wazone lajkami, zawijanie na koncu).
Bez wag 100% explore. POST /clips/events: zapis, podniesienie outcome,
ulubione, delty wag (like +5, complete +3, dwell>=10 s +1, skip<2 s -1,
not_interested -4 i -8 na wskazany cel). Onboarding 3 tapow, opcje,
blacklista tag/nisza/tworca, reset feedu, ulubione. Import miedzy
urzadzeniami kopiuje clip_seen, clip_favorites i clip_blacklist.

Job clips-maintenance co 24 h: decay wag x0,97, retencja zdarzen 90 dni,
reaper (HEAD na 2000 najdawniej sprawdzanych). Logika bez bazy w
app/clips_feed.py z testami (kursor, delty, cap/decay, punktacja, sklad).
2026-09-14 20:29:49 +02:00
goon-foss
cd4803ed51 fix(clips): RedGifs 1 zapytanie/s, odstep z error.delay przy 429, przerwanie backfillu zamiast mielenia nisz
Pierwszy backfill po niszach przy ~3 zapytaniach/s po ~65 zapytaniach wpadl
w trwale 429 (cialo: delay 1167 s, subject per IP i endpoint) i przemielil
40 kolejnych nisz w bledach. Teraz: 1/s, odstep z Retry-After albo
error.delay, powyzej 5 min RateLimited i koniec przebiegu (wznowienie --skip).
2026-09-14 16:41:34 +02:00
goon-foss
4f5de92bfc feat(clips): tabele klipow do feedu Swipe + ingest RedGifs (etap 2)
Nowy wertykal krotkich pionowych klipow tworcow, osobno od scen: inne kolumny
(tworca, audio, lajki, nisze), inny cykl zycia, inna taksonomia, brak filtra
60 s. Tabele `clips` (unikalne source+source_id) i `clip_tags` z indeksem
(tag, clip_id) pod skan po tagu od losowego uuid w przyszlym feedzie.

Zrodlo nr 1: RedGifs, oficjalne API v2 z tokenem tymczasowym (zwiazany z IP
i UA, na 401 odnowienie). Globalne `order=latest` bez search_text daje ~100
na strone, kazde zapytanie widzi maks. 10 000 wynikow, wiec katalog chodzi
sie po niszach (skrypt backfillu). Pliki media.redgifs.com sa publiczne i bez
podpisu (206 z VPS-a i z telefonu), do bazy wchodzi gotowy adres.

Scheduler: job clips-latest co godzine (5 stron), zatrzymuje sie na stronie
bez nowych. Reaper (HEAD, 403/404/410 -> dead_at) jako skrypt, upsert
odzywia klip, ktory zrodlo znow podaje. API: GET /clips i /clips/stats do
pilota; wlasciwy feed, pamiec widzianych i telemetria to etap 3.

Sprawdzone tego dnia i odlozone: nsfwswipe (lustro v.redd.it, bez audio,
stoi od 19.08), Pornhub Shorties (zrodlo nr 2, HLS z tokenem 2 h, Referer
na segmentach, 0/110 performerow z kanonu).
2026-09-14 16:32:57 +02:00
goon-foss
be6c18b3b4 feat(scenes): sortowanie losowe (seed, okno po PK) i po dlugosci (indeks partial), zgloszenie ae6a045b
- random: md5(seed) -> uuid startu, okno 2000 id (8000 dla wertykalow) po pk_scenes,
  filtry na oknie; bez okna planer robil Merge Anti Join po 2,3 mln wierszy (7,6 s)
- duration_desc/asc: bez NULL, do 10 h, indeks ix_scenes_duration (migracja 0035)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 15:13:13 +02:00
goon-foss
c55596dd6f fix(thumbs): xhamster miniatury z JSON strony wynikow, mypornerleak z src i og:image posta, backfill brakujacych
- _search_base: hak _thumbnail_map (mapa url -> miniatura z calej strony) przed
  szukaniem <img> w oknie tekstu; xhamster mial 54% zrodel bez miniatury
- mypornerleak search: karty maja teraz src zamiast data-src; browse (REST) bez
  featured media -> og:image ze strony posta
- scripts/backfill_thumbs.py: uzupelnia miniatury ze strony sceny, od najnowszych

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 14:33:51 +02:00
goon-foss
385aeb3ddb perf(api): lista filmow serializowana wsadowo (7 zapytan/film -> 8 na strone), /sources z agregatem w pamieci na 5 min
- GET /movies 371 -> 82 ms, z has_playback 477 -> 209 ms; GET /sources 604 -> 8 ms
- VACUUM ANALYZE tabel filmow po tygodniu przemialu (11k martwych wierszy w movies)
2026-09-08 10:04:01 +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
994e4e98ad feat(tubepornclassic): konektor retro/vintage na silniku TXXX, wspolny tor HLS z vjav
tubepornclassic.com to SPA sieci TXXX (ten sam silnik co vjav): HTML ma pusty
<title> i zero linkow do scen, wszystko idzie z JSON API. Listing
/api/json/videos2/<cache>/str/latest-updates/60/..<page>.all...json oddaje
60 rekordow z pelnymi metadanymi (tytul, slug, dlugosc, post_date, obsada,
kategorie+tagi, miniatura), wiec nie ma fetchu per scena. ~168 tys. wideo,
wgrania codziennie. Koniec katalogu = 200 z code=videos_not_found.

Stream: videofile.php -> dekod video_url -> get_file -> f=video.m3u8 -> HLS
na ahcdn (klucz time-bound, nie IP-bound: adres wybity z VPS gra z lacza
domowego). Ten tor zyl dotad w tubes/vjav.py; wyniesiony do
_txxx.extract_hls, vjav i tubepornclassic wolaja to samo. HLS zamiast mp4,
bo mp4 z tego samego get_file ma w URL CDN speed=... (~1,2 MB/s), a segmenty
HLS leca ~3,6 MB/s. Wyzwanie 429 (ciasteczko w ciele) obsluzone w
ekstraktorze, scraperze i juz wczesniej w /proxy/hls.

Bramka: 38% tytulow to generator SEO ("Fabulous Sex Movie Vintage Try To
Watch For Ever Seen"). Z doczepionym nazwiskiem scena jest odnajdywalna
i zostaje; bez obsady (22%) nie wchodzi, bo nie ma po czym jej znalezc
ani z czym zdeduplikowac. Obsada u 46% scen, studiow brak.

Pilot: 2 strony, 120 scen, 111 nowych, 9 juz w bazie, wszystkie z dlugoscia.
Odtworzenie na emulatorze: playback_events success (ttff 3,3 s), AudioTrack
started. vjav po refaktorze: ten sam wynik ekstraktora co przed.
2026-09-07 10:04:24 +02:00
goon-foss
9906c665ec feat(porndupe): konektor, skorka KVS z plikami na OK.ru i zaszyfrowanym kluczem sesji
Z szesciu stron z listy piec juz jest lub bylo w bazie: fullmovies.xxx,
hdporn.gg, neporn.com sa zywe (ingest z dzisiaj, odtwarzanie 84-99%),
a hqfap.com i 4k69.com nadal oddaja Cloudflare JS-challenge na podstronach
(403 "Just a moment" takze z lacza domowego, wiec to nie blokada po IP).
Jedyna nowa to porndupe.

Porndupe wyglada jak KVS, ale to atrapa: kazdy get_stream/<id>-<q>.mp4?md5=
odpowiada doslownie "error" (sprawdzone z sesja, Refererem strony i embedu,
z permutacja md5 kodem licencyjnym). Prawdziwy tor widac w DevTools:

  generate_mp4('<b64 JSON>', '<haslo>', '<okid>', '<id>')
  -> {ciphertext, iv, salt, iterations: 999}
  -> PBKDF2-SHA512 + AES-256-CBC -> klucz sesji OK.ru (staly; haslo i
     ladunek zmieniaja sie co wczytanie, to zaciemnienie)
  -> api.ok.ru/fb.do method=video.get -> url_low/medium/high/fullhd,
     duration (ms), created_ms, thumbnail_url

Wariant PBKDF2 ustalony empirycznie: SHA-1/SHA-256 daja bad decrypt,
SHA-512 oddaje dokladnie klucz z trace'u.

okcdn: srcIp wbite w URL, NIE egzekwowane (URL z lacza domowego pobrany
z VPS -> 206, 514 MB, ftypisom) -> mobile_direct_ok. Cap 720p, bo OK.ru
dlawi polaczenie do ~2,1 Mbps (decyzja z 4k69/8kporner).

Browse po id (vjav pattern): kazdy listing to catch-all z tymi samymi 24
linkami, sitemapy pokrywaja 3500 z 12 887 id. /video/<id>/ -> 301 slug
(istnieje) albo 302 / (brak). Dlugosc z api.ok.ru przy ingescie (HTML nie
ma duration ani uploadDate). Daty CELOWO nie: created_ms to dwie fale
hurtowego wgrania (07.2024, 04.2025), nie premiery.

Katalog ZAMROZONY od kwietnia 2025, wiec to jednorazowy import, nie zrodlo
swiezosci. Wchodzi, bo 87% scen (52/60) nie mamy, a to tresc studyjna
(Nubile Films, NF Busty, Family Strokes) trafiajaca w kanon, w odroznieniu
od hentaicloud (17%). Pilot crawl_page(1): 22/22 z dlugoscia, 21/22 z
performerem, studia i tagi per-video.

Blad diagnostyczny po drodze: strona blankuje sie do about:blank po wykryciu
CDP (disable-devtool z jsdelivr); trace przezyl, DOM nie.
2026-09-05 22:34:39 +02:00
goon-foss
25416a2858 fix(movies): rodzina DoodStream (playmogo/doply/myvidplay) na koniec listy zrodel
Zgloszenia "Playmogo nie dziala tutaj" (1278eb49, 2026-09-04) i seria
"Myvidplay nie dziala" (3b75cb54, d3af0813, 11d7b17b). myvidplay to 301
na playmogo, a playmogo to klon DoodStream z KLIKANYM Turnstile: widzet
pojawia sie po tapie w play i przeladowaniu, wiec pass_md5 nie ma w HTML
i telefon nie rozwiaze tego sam. Telemetria: ZERO zdarzen odtwarzania
w 30 dniach (droga WebView nic nie raportuje), gdy mixdrop/voe/luluvid/
vidara graja w ~99%.

Przyczyna kolejnosci: _movie_origin_priority dawal tym originom neutralne
500, wiec sortowaly sie z dzialajacymi po created_at DESC, a doply/playmogo
bywaja dopisane jako OSTATNIE -> ladowaly na GORZE "Watch on". Zgloszony
film 12e9d0c1 mial obok zywy mixdrop.

Pomiar 2026-09-05: rodzina siedzi w 54 446 filmach, 54 320 (99,8%) ma
dzialajaca alternatywe, tylko 126 zalezy od niej wylacznie. Nowy tier 800
(za neutralnymi 500, przed martwa rodzina seekplayer 900): dla tych 126
zostaje jako ostatnia deska ratunku, wiec nikomu nie zabiera dostepu.

Weryfikacja po deployu: film 12e9d0c1 -> [mangoporn:mixdrop, mangoporn:playmogo].
2026-09-05 22:21:13 +02:00
goon-foss
01298c9699 fix(sxyprn): blokada uploaderow ze spamem obsady/tagow + dopasowanie nazwisk bez przedrostka w obie strony
- person_named_in: jednowyrazowe nazwisko tylko co do znaku (albo zlepek sasiednich
  czlonow tytulu), przedrostek co najwyzej o 2 znaki; "Thebdck" lapal kazde "the"
- sxyprn: autor z sciezki miniatury, _BLOCKED_AUTHORS (Shizuka, Ajx, Denzel),
  karty z >20 hashtagami wchodza bez tagow
- scripts/sxyprn_purge_uploaders.py: dry-run/apply, sceny tych autorow + smieciowi performerzy
2026-09-04 11:09:37 +02:00
goon-foss
f1b8b8d466 feat(favorites): przypinane strony (favorite_sites) z endpointami list/add/remove
Prosba z apki 2026-09-02: ulubione strony maja siedziec na gorze zakladki Sites. Po
stronie serwera jak reszta ulubionych, bo kod synchronizacji to device_id i tabele
kluczowane po nim przechodza na nowe urzadzenie razem. Origin bez klucza obcego
(zrodla nie maja tabeli po origin), za to przy dodawaniu sprawdzany w playback_sources,
a sam napis ograniczony wzorcem, zeby nie dalo sie wpisac smieci.

Migracja 0034 (create table, bez blokad). Sprawdzone TestClientem w kontenerze api:
dodanie, powtorne dodanie (created=false), lista w kolejnosci dodania, nieznany origin
404, zly wzorzec 422, usuniecie 204.
2026-09-02 22:44:35 +02:00
goon-foss
59b7b5a651 fix(movies): poprawki po code review scorera, merge_movies i rozdzielania
Scorer tytulu (`movie_score._title_signal`), na zywym ingescie:
* sklejanie ogonkow apostrofu obejmowalo KAZDA pojedyncza litere, wiec "watch a whore s
  tale" dawalo "watcha", a przedimek "a" nigdy nie wpadal do wypelniaczy; lustra z A/I
  na poczatku tytulu przestawaly sie laczyc. Teraz tylko s/t/d.
* rowne zbiory zlozone z samych liczb ("adult movie 2019" vs "porn film 2019" -> {2019})
  dawaly 1.0; teraz sufit.
* zaostrzenie "rozne slowa = sufit" zabijalo warianty zapisu: Vol./Volume, Pt./Part,
  Gang-Bang/Gangbang, literowki, liczbe mnoga. Skroty rozwijane, zlepki porownywane po
  zdjeciu spacji, slowa wlasne obu stron parowane jeden do jednego: liczba mnoga = 0.95,
  literowka tylko przy >= 0.92 i slowach od 4 liter. Prog 0.85 na slowie przepuszczal
  "sexy"/"sex", "intense"/"interns" i "infedele"/"fedele" (niewierna vs wierna), a
  porownanie calych posortowanych ciagow "girls only 4" vs "girls on girls 4".
Sprawdzone na 28 parach, w tym wszystkich przykladach z review.

`merge_movies`: ulubione i postep odtwarzania przenoszone na `keep` przed skasowaniem
`drop`. Oba maja FK ondelete=CASCADE, wiec kazde scalenie po cichu wymazywalo userowi
dane. Dotyczy tez dedup po TPDB.

Skrypt rozdzielania:
* `_istniejacy_film` dostaje pelna liste performer_id (jak resolver), nie tylko przekroj,
  ktory zawyzal Jaccarda (3 z 5 wspolnych dawalo 1.0); kandydaci z trigramow PLUS
  dokladne trafienie w title_normalized, bo LIMIT 50 gubil "control 2" wsrod sasiadow;
  wstepny test tytulu oszczedza zapytan o obsade; flush przed blokowaniem.
* klastry rozdzielone w tym samym filmie nie moga sie do siebie dolaczyc (klastrowanie
  juz orzeklo, ze to rozne filmy).
* przed przepisaniem kotwicy sprawdzenie, czy zbior refow nie zmienil sie w trakcie
  pobierania (wyscig miedzy shardami).
* dry-run pokazuje tez dolaczanie do istniejacych; liczniki liczone przy tworzeniu.
* sprzatanie dubli po `updated_at` (created_at jest cofane i nie nadaje sie na znacznik
  przebiegu), keep = wiecej refow, potem starsze pierwsze zobaczenie; try/except per
  film; --after-id; naiwny timestamp = UTC.
2026-09-02 22:37:32 +02:00
goon-foss
c4845e9f61 fix(unmerge): szukaj istniejacego filmu przed utworzeniem, sprzataj duble, dziedzicz created_at
Trzy skutki pierwszego przebiegu rozdzielania (2026-09-02, 5846 nowych filmow), oba
zgloszone z apki tego samego dnia:

1. Duble (a5cdda7f). Klaster poza kotwica dostawal ZAWSZE nowy film, choc "Control 2"
   z innego zrodla juz istnial: 798 nowych o tytule sprzed przebiegu, 408 dubli miedzy
   soba. Teraz najpierw `find_movie_candidates` + `score_movie_candidate` (ten sam
   resolver co ingest) i przy >= 0.85 refy ida do istniejacego. Tryb
   `--dedupe-created-after <ts>` scala juz utworzone przez `merge_movies` (691 scalonych).

2. Scorer przepuszczal jeszcze pary z roznymi slowami po obu stronach: "hardcore
   fucking sluts 2" vs "foot fucking sluts 2", "santa list gangbang" vs "gangbang d"
   (token_set 85-94, ze zgodnym studiem i rokiem auto-merge). Lustra nie zmieniaja
   tytulow, wiec: rowne zbiory slow po zdjeciu wypelniaczy SEO = 1.0, podzbior albo
   rozne slowa po obu stronach = sufit 0.6. Ogonki po apostrofie sklejane ("she s" ->
   "shes"), bo normalize() tnie apostrof na spacje. Lista dubli spadla z 941 do 691 i
   sa to same identyczne tytuly.

3. Falszywe "+N nowych" (1db95176). Nowy film dostawal created_at = teraz, a badge w
   ulubionych od lipca sumuje sceny i FILMY: 2196 filmow z obsada z dzisiejsza data
   zapalilo "+N" u kazdego z performerem w ulubionych, przy zerze nowych scen na liscie.
   Teraz created_at = pierwsze zobaczenie refow klastra; 5231 juz utworzonych
   poprawione w bazie tym samym kryterium.
2026-09-02 15:29:21 +02:00
goon-foss
ec38403e40 feat(movies): rozdzielanie zlepionych filmow + sufit dla tytulu-podzbioru w scorerze
Skrypt `scripts/movie_unmerge.py` rozdziela filmy, ktore stary scorer zlepil z kilku
tytulow (8204 filmy z >=2 refami z jednego zrodla, 31 299 refow). Musi pobierac strony
na nowo, bo rekordy zewnetrzne filmow trzymaja tylko {slug, html_len} / {hex_id,
html_len}, a ingest jest przyrostowy, wiec skasowane rekordy same sie nie odbuduja.

Dla kazdego filmu: refy pobierane przez konektory zrodel (paradisehill, dooplay x4,
freeomovie; reszta profil ze sluga), klastry union-find po wspolnym adresie embedu
(bez prefiksu zrodla, ten sam plik siedzi pod mangoporn/pandamovies/streamporn) albo
po nowej ocenie zlozonej >= 0.85. Klaster z najstarszym refem zostaje filmem
(zachowuje id, ulubione, postep), kazdy inny dostaje nowy film z refami, hosterami,
obsada, tagami i rozdzialami. Kotwica zostaje z hosterami potwierdzonymi przez swieze
strony; reszta z rodzin luster leci, bo pandamovies zdazyl zrotowac hostery (swieza
strona ma 0 z 4 kluczy z bazy), wiec to i tak zwietrzale linki.

Proba na "The Doctor" ujawnila druga luke scorera: po normalizacji zostaje samo
"doctor", a jedno slowo jest podzbiorem kazdego tytulu z tym slowem, wiec "granny s
doctor games" i "we need a doctor" dostawaly 100 i szly do kotwicy. Teraz podzbior z
prawdziwymi dodatkowymi slowami ma sufit 0.6, a przedrostki SEO luster ("watch cece
adult movie online free") sa zdejmowane przed testem, zeby prawdziwe lustra nadal sie
laczyly. Po poprawce "The Doctor" rozpada sie na 11 klastrow, kotwica to sam
paradisehill, a "Doctor Adventures 14" laczy swoje cztery lustra.
2026-09-02 12:54:42 +02:00
goon-foss
ca80ae44b6 fix(movies): nie lacz filmow rozniacych sie numerem serii (The Doctor = 9 filmow)
Zgloszenie 32100b94: "w pierwszym linku jest granny porn". Pod filmem "The Doctor"
siedzialo 55 zrodel z co najmniej 9 roznych filmow pandamovies (Doctor Adventures 14 i
21, Granny's Doctor Games, Pervy Doctor 9, The Doctor Is In 2, We Need a Doctor...).

Przyczyna: tytul porownywany przez `token_set_ratio`, ktore mierzy czesc wspolna, wiec
tytul bedacy podzbiorem drugiego dostaje pelne 100 ("the doctor" vs "the doctor is in
2", "fantasies" vs "dark fantasies 3"). Numerowane serie wychodza na 90-96, tez ponad
progiem auto-merge 0.85. Gdy zrodlo nie ma roku ani studia, o wszystkim decyduje sam
tytul i cala seria zapada sie w jeden wpis: "Her way to use Tinder 61" ma 102 strony,
"Women Seeking Women 56" 87. W bazie 1878 filmow ma >=2 rozne strony z pandamovies.

Dwie zasady oparte na numerze serii (ostatnia liczba w tytule, z pominieciem lat):
* oba tytuly maja numer i sie rozni -> twarde odrzucenie,
* numer ma tylko jedna strona -> tytul najwyzej 0.6, wiec sam nie wystarczy do
  auto-merge, ale ze zgodnym studiem i rokiem trafia do recznego przegladu.
Podzbior bez numerow zostaje bez kary celowo: "cece" vs "watch cece adult" to prawdziwe
lustro z przedrostkiem SEO, dla niego jest token_set.

Sprawdzone na 11 parach z bazy, w tym kontrolnych (lustro SEO bez kary, rok nie liczy
sie jako numer). Dziala tylko w przod; rozdzielenie juz polaczonych to osobna robota.

Osobno `scripts/browse_catchup.py`: jednorazowe nadrobienie N stron jednego browse-
scrapera z pliku. Powstal, bo `docker compose run -d ... python3 -` ze skryptem na
stdin nigdy nie startuje: przy -d stdin nie jest domkniety i python czeka w
nieskonczonosc. Tak "chodzilo" nadrabianie porndoe przez 2 dni bez jednego zapisu.
2026-09-02 12:26:20 +02:00
goon-foss
5e41285d44 fix(porndoe): scrape przez proxy, bo tub blokuje IP serwerowni (10 dni bez nowych scen)
Watchdog zglaszal "tube:porndoecom (browse) bez nowych tresci (173h, prog 48h)" i
potraktowalem to jako szum razem z alertami dla tubow, ktore faktycznie przestaly
publikowac. Bledna ocena: porndoe to nasze czwarte co do wielkosci zrodlo (356 tys.
zrodel), a ostatnia nowa scena wpadla 2026-08-21.

Przyczyna: porndoe zaczal oddawac HTTP 403 na IP serwerowni. Scraper dostawal strone
bledu, znajdowal zero linkow i konczyl sie bez wyjatku, wiec z zewnatrz wygladalo to na
"tub sie wyczerpal", a nie na awarie. Ten sam ksztalt pomylki co przy porntrex, gdzie
cicha zmiana markupu ukryla 6479 scen.

Sprawdzone 2026-08-31: bez proxy 403 i 0 scen, przez Bright Data ISP proxy 200 i 31 scen
z pierwszej strony, z datami z 30 sierpnia, dlugosciami i obsada. Wzorzec i uzasadnienie
kosztowe jak przy superporn: ISP proxy jest ryczaltowe, wiec deep-crawl nie kosztuje
wiecej, a przez proxy leci sam HTML, nigdy strumien.

Bez skonfigurowanego proxy `crawl_page` zwraca pusta liste zamiast dobijac sie o 403.
2026-08-31 09:46:31 +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
b84ff5bdbc fix(vjav): powtorz pobranie manifestu z ciasteczkiem wyzwania (100% bledow -> gra)
vjav mial 587 bledow odtwarzania i ZERO udanych, przez caly czas, odkad zbieramy dla
niego zdarzenia. Kazdy blad to ten sam komunikat odtwarzacza: "Source error Response
code: 429". Dotyczylo to 58 779 zrodel, czyli tub nigdy ani razu nie zagral.

Siec TXXX dlawi ruch z serwerowni: zamiast tresci oddaje 429 i mikroskopijna strone,
ktora w JS ustawia jedno ciasteczko i przeladowuje sie. Wartosc stoi wprost w tej
odpowiedzi, wiec wystarczy ja odczytac i powtorzyc zapytanie, bez wykonywania JS.

Ekstraktor vjav robil dokladnie to od 2026-08-21, ale TYLKO przy `videofile.php`. Adres
manifestu oddawany odtwarzaczowi tej sztuczki nie dostawal, a `/proxy/hls` pobiera go z
VPS przy KAZDYM odtworzeniu. Stad komplet bledow.

To dlatego bug byl niewidoczny z zewnatrz: `try_extract` konczyl sie sukcesem, wiec w
kazdym pomiarze zrodla vjav wychodzily jako zywe (149 na 150), podczas gdy u userow nie
dzialalo nic. "Zywe" znaczy "ekstraktor zwrocil adres", a nie "to gra".

Sprawdzone na prodzie: przed poprawka /proxy/hls oddawal 429, po poprawce 200 i poprawny
#EXTM3U z segmentami na vjav0.ahcdn.com. Ponowienie odpala sie wylacznie przy 429 z
odpowiedzia ponizej 4 KB, wiec nie dotyka pozostalych hosterow.

Osobno potwierdzone, ze blokada jest po adresie IP: ta sama strona z VPS oddaje 429, a
przez proxy z innym IP 200 i 72 KB tresci.
2026-08-27 19:23:55 +02:00
goon-foss
365c97a1de fix(seekplayer): sprawdzaj czy adres CDN naprawde odpowiada, plus obsluga sciezki Tiktok
Zgloszenie a405b9d6 "znowu galaxyporn nie dziala". Przyczyna byla inna niz sie wydawalo:
nasz resolver dzialal, tylko oddawal adres do pliku, ktorego juz nie ma.

Co ustalone przez reverse engineering ich bundla i pomiary:

1. Adres strumienia siedzi w KILKU polach, a serwis sam podaje w `streamingConfig`,
   ktorej sciezki uzyc i w jakiej kolejnosci:
   {Cloudflare: cf, Tiktok: hlsVideoTiktok, Google: hlsVideoGoogle, "In-House": source}.
   Czytalismy WYLACZNIE `source`, wiec sceny majace tylko `hlsVideoTiktok` traktowalismy
   jak martwe. A one graja: zweryfikowany manifest 1080p, 200 i z serwerowni, i z lacza
   domowego. Doszlo skladanie adresu wg ich regul (`/hls/` -> `/hlsmod/<domain>/` + params).

2. WAZNIEJSZE: adres do usunietego pliku wyglada normalnie, a CDN oddaje na niego 502.
   Sprawdzone: wezly 94.131.217.172/175/177 rotuja i WSZYSTKIE daja 502 dla jednego pliku,
   podczas gdy TEN SAM wezel .172 serwuje inny plik poprawnie. Czyli CDN zyje, brakuje
   konkretnych plikow. Oddawalismy taki adres jako dobry, aplikacja pokazywala czarny
   ekran, a ratunek z vikingfile nigdy sie nie uruchamial, bo lista zrodel nie byla pusta.
   Teraz kazdy kandydat jest sprawdzany (`_responds`) i zwracamy tylko ten, ktory
   naprawde odpowiada manifestem.

3. galaxyporn: gdy player mowi wprost, ze pliku nie ma, a na stronie NIE MA tez linku do
   vikingfile, przepuszczamy `HosterDead` dalej zamiast zwracac None. Wczesniej takie
   sceny dawaly 503 "sprobuj ponownie" i wracaly w kolko.

Weryfikacja, ze `_responds` nie odrzuca dzialajacych: scena `#puwcko` -> http=200,
responds=True, prawdziwy #EXTM3U (przyjeta); `#bgitoa` -> 502 na wszystkich wezlach
(odrzucona). Na probce 20 scen galaxyporn 85% trafia teraz do vikingfile zamiast dostawac
martwy adres. Scena ze zgloszenia zostala oznaczona martwa przez prawdziwy endpoint
resolve (410 zamiast czarnego ekranu).

Czego NIE zrobilem: vikingfile wymaga tokenu z WIDOCZNEGO checkboxa Cloudflare
(`POST <adres strony>` z `cf-turnstile-response=<token>`). Obchodzenia tego nie buduje.
2026-08-27 08:59:28 +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
360af9fabc fix(movies): rozwiazuj przekierowanie hostera na serwerze, zanim embed trafi do WebView
Zgloszenia 3b75cb54/11d7b17b/d3af0813: "Myvidplay nie dziala", czarny ekran.

Mechanizm to powtorka z galaxyporn (vikingfile -> vik1ngfile), tylko w drugiej galezi,
ktorej wtedy nie sprawdzilem: myvidplay.com i doply.net odpowiadaja 30x na playmogo.com,
a WebView w apce blokuje top-frame skok na inna domene (ochrona przed popunderami).
Telefon dostawal surowy adres myvidplay, przekierowanie bylo blokowane i zostawala czern.
Lekcja "sprawdz te sama pulapke w pozostalych galeziach" byla zapisana w pamieci po
galaxyporn; ta galaz wlasnie ja potwierdzila.

`resolve_movie_playback` rozwiazuje teraz przekierowanie po stronie serwera i UTRWALA
koncowy adres w `embed_url`, wiec kazdy adres kosztuje jeden fetch raz w zyciu, a po
utrwaleniu regex przestaje pasowac i krok jest darmowy. Fetch odpala sie WYLACZNIE dla
rodziny DoodStream (znanej ze zmiany szyldu co pare miesiecy); zwykle embedy ida bez
dotykania sieci. Blad hostera (5xx) nie jest utrwalany, zeby nie zabetonowac chwilowej
awarii jako nowego adresu.

Easyvidplayer z tych samych zgloszen NIE wymagal zmian: zrodla juz sa oznaczone
martwymi przez niedzielny mechanizm HosterDead, czyli samoleczenie dziala.

Zweryfikowane na wszystkich trzech zgloszonych filmach: resolve oddaje
https://playmogo.com/e/..., baza utrwalona, telefon rozpoznaje playmogo natywnie
(DOOD_HOSTS), a strona playmogo z tymi sciezkami byla sprawdzona 2026-08-24 (200,
markery Turnstile). Deploy backendu, bez OTA.
2026-08-26 14:00:56 +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
b7a8911441 fix(sxyprn): koniec z przypisywaniem scen po samym imieniu
Zgloszenie e28f2517: scena "Bridgette B, Gigi Rivera, Julia Ann, Phoenix Marie, ..."
miala przypisana Julie B., ktorej w tytule nie ma.

Mechanizm: scraper wola strone performera i sprawdza, czy scena naprawde go dotyczy,
porownujac czlony nazwiska z tytulem. Robil to jednak KAZDY Z OSOBNA i tylko od trzech
znakow. Dla "Julia B." czlon "b." odpadal na dlugosci, zostawalo samo "julia", i
przypisanie lapalo kazda scene z tym imieniem w tytule. Stad tez "Chloe S" przy
"Chloe Kreams", "Sharon D" przy "Sharon White", "May E" przy "Danielle Maye".

Nowa regula (`person_named_in` w `app/normalize/text.py`): czlony musza stac OBOK
SIEBIE i w tej samej kolejnosci. Od trzech znakow wystarczy zgodnosc przedrostka, zeby
przezyly warianty zapisu ("Savanna Bond" przy tytule "Savannah Bond", "Jyn Maze" przy
"Jynx Maze"). Inicjaly musza zgadzac sie dokladnie. Tytul tniemy wczesniej na segmenty
po przecinkach i myslnikach, bo bez tego smieciowy performer "Rope Bondage" dopasowywal
sie do doklejonego ogona tagow "- rope - bondage".

Swiadomy koszt: odwrocona kolejnosc ("Goldy Kim" wobec "Kim Gold") nie przejdzie, a
performer z inicjalem zamiast nazwiska nie dostanie ze sxyprn nic. Przy wyborze miedzy
pominieciem sceny a przypisaniem jej niewlasciwej osoby wolimy pominac, bo to bledne
przypisanie widac na ekranie performera i to ono jest zglaszane.

Smoke test po zmianie: Lana Rhoades, Julia Ann, Angela White i Abella Danger dalej po
30 scen ze strony performera, wiec scraper sie nie zamrozil (to sie juz raz zdarzilo
przy zbyt ostrym filtrze). "Julia B." oddaje teraz zero zamiast cudzych scen.

Dolozony `scripts/sxyprn_fix_overattribution.py`, ktory stosuje te sama regule wstecz.
Uruchomiony na produkcji: skasowane 85 379 z 239 686 przypisan (35,6%). Ruszamy tylko
sceny majace WYLACZNIE zrodlo sxyprn i tylko przypisania od scrapera; kanon
(tpdb/stashdb) nietkniety. Regula sprawdzona recznie na dwoch probkach po ~20 pozycji,
wszystkie kasowane byly faktycznie bledne.

Skutek uboczny: scen bez zadnego performera przybylo z 3 622 do 23 891. To sceny,
ktorych jedyne przypisanie bylo bledne, wiec brak jest uczciwszy niz cudze nazwisko.
2026-08-24 13:49:31 +02:00
goon-foss
5a48175a85 fix(movies): przestan podsuwac hostery z rodziny seekplayer, ktore nie maja plikow
Zgloszenia z 2026-08-24: "Easyvidplayer nie chce odpalic" (ccbc75da), "Embedseek tez
nie rusza" (d59fc396) i sasiednie. To NIE byl nasz blad parsowania.

Co ustalone: `/api/v1/video` odpowiada 200 i poprawnie sie odszyfrowuje, tylko nie ma
w odpowiedzi pola `source`. W ich wlasnym bundlu warunek jest doslownie taki sam i
konczy sie komunikatem "Video is not ready yet". Potwierdzone w przegladarce z lacza
domowego (plakat obok oddal 502), z VPS i przez brytyjskie proxy, wiec to nie blokada
po IP ani po kraju. Protokol sie nie zmienil, hoster po prostu nie ma juz plikow.

Skala na 250 losowych zrodlach: 3 zywe, 88 razy HTTP 404, 79 razy brak `source`.
Czyli okolo 2% jeszcze gra.

Dwie zmiany:
* `seekplayer_engine.extract` rzuca `HosterDead` zamiast zwracac None. Dopiero wtedy
  `resolve_movie_playback` oznacza zrodlo martwe. Zwracanie None dawalo WebView z tym
  samym komunikatem, w kolko, i wlasnie to zglaszali uzytkownicy. Katalog czysci sie
  teraz sam, w miare jak ludzie po nim chodza.
* De-ranking calej rodziny w `_movie_origin_priority`, zeby na wierzch wychodzily
  hostery, ktore graja. Nie usuwamy ich z listy, bo te 2% bywa jedynym zrodlem.

Bezpieczne: filmow zaleznych WYLACZNIE od tej rodziny jest w bazie jeden, pozostale
26 223 maja alternatywe.

Dolozony `scripts/seekplayer_reap.py` do sprzatania calosci na zadanie. NIE odpalam go
w tle: przy limitach hostera (32% odpowiedzi to 429) pelny przemial to kilkadziesiat
godzin ciaglego pukania, co grozi zablokowaniem naszego IP dla prawdziwych resolve.

Zweryfikowane na filmie ze zgloszenia: piec zrodel seekplayer oznaczonych martwymi,
zostaly mixdrop (206 video/mp4) i voe (200 m3u8), oba sprawdzone spoza serwerowni.
2026-08-24 13:39:40 +02:00
goon-foss
9fe6d5c1ed fix(galaxyporn): lap tez nowa pisownie domeny vikingfile
Regex w backendzie dopasowywal wylacznie vikingfile.com, mimo ze serwis rotuje
domena. Poszerzony na vik[i1]ngfile z dowolna koncowka. W aplikacji ten sam wzorzec
byl juz poszerzony, backend zostal w tyle.

Na 20 losowych scenach: 16 oddaje vik1ngfile.site, 4 nie maja zadnego zrodla (stary
player padl, a linku do vikingfile na stronie nie ma wcale). Te 4 to uczciwe 503, nie
awaria po naszej stronie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 21:10:40 +02:00
goon-foss
612558c880 fix(galaxyporn): rozwiazuj przekierowanie TAKZE w galezi z iframem
Wczorajsza poprawka objela tylko galaz zapasowa (link vikingfile w tresci strony), a
nie te, ktora obsluguje nowsze sceny, gdzie vikingfile JEST iframem. Polowa katalogu
dalej dostawala wiec stary adres vikingfile.com, ktory oddaje 302 na inna domene,
WebView to blokowal i zostawal czarny ekran.

Znalezione dopiero, gdy sprawdzilem KONKRETNA scene zglaszana przez uzytkownika
("Stella Cox passes on tennis") zamiast losowej probki: resolve oddawal
vikingfile.com, mimo ze losowe sceny testowane wczesniej oddawaly juz vik1ngfile.site.

Po poprawce na 10 losowych scenach: 9 oddaje vik1ngfile.site, 1 bez zrodla.
Kontrola pliku: 2,93 GB, nazwa zgodna ze scena.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 20:45:31 +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
95c51f78d2 fix(galaxyporn): stary katalog NIE jest martwy, tylko iframe zwietrzal
Korekta mojej wczorajszej diagnozy. Twierdzilem, ze stary katalog galaxyporn padl po
stronie hostera: player wypisuje "Video is not ready yet", a /api/v1/video oddaje
payload BEZ jakiegokolwiek adresu wideo (75% probki 16 scen). Objawy sie zgadzaly,
wniosek byl zly.

Na TYCH SAMYCH stronach jest link do vikingfile, tylko nie w iframie, lecz w zwyklym
<a href>, wiec go nie widzielismy. Pliki tam zyja: sprawdzone trzy, 890 MB, 742 MB i
2,5 GB, nazwy zgodne ze scenami. Zwietrzaly byl iframe (news.upns.pro,
sport.seekplays.com, galaxy.4meplayer.pro), zostawiony po migracji.

Szukamy wiec vikingfile po calym HTML. Kolejnosc celowa: seekplayer PIERWSZY, bo
resolwuje sie po naszej stronie i gra bez CAPTCHA, vikingfile jako ratunek, ktory
kosztuje usera przejscie Turnstile w WebView. Martwy player potrafi RZUCIC
(HosterDead przy 404), nie tylko oddac pustke, wiec lapiemy tez wyjatek, inaczej
ratunek nigdy sie nie wykonuje.

Na 12 losowych scenach: bylo 0 rozwiazanych, jest 11. ZADNYCH scen nie kasujemy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 12:00:30 +02:00
goon-foss
83a6092d89 fix(pornbusy): probuj generycznego hostera zamiast od razu poddawac
Zgloszenie 3b03a744 ("Pornbusy pisze ze temporary problem with the host"). Wbrew
mojej pierwszej diagnozie to NIE byla awaria rodziny seekplayera: pornbusy w ogole
juz jej nie uzywa. Probka 10 najswiezszych scen (2026-08-21): morencius.com 4,
cdn.loadvid.com 4, playmate.to 1, upload18 1.

Morencius to zwykly JWPlayer z P.A.C.K.E.R.-em i HLS-em, bez Turnstile, wiec radzi
sobie z nim nasz generyczny rozpakowywacz BEZ zadnych zmian (oddaje gotowy
master.m3u8). Zamiast wiec zwracac None dla kazdego nieznanego hostera, najpierw
podajemy embed generycznemu: najgorszy przypadek to None, czyli stan sprzed zmiany.

Bylo 0/5, jest 3/5. Zostaja playmate.to (rozpakowywacz go nie zna) oraz upload18,
ktory pomijamy swiadomie, bo ma token zwiazany z IP.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 11:51:04 +02:00
goon-foss
ae5f2aa7ac fix(extractors): vjav przechodzi wyzwanie 429, galaxyporn oddaje vikingfile telefonowi
Znalezione w nocnym smoke tescie (9 ostrzezen, w tym trzy ekstraktory po 0/3).

vjav: /api/videofile.php oddaje z serwerowni 429 i 343-bajtowa strone, ktora w JS
ustawia JEDNO ciasteczko i sie przeladowuje. Wartosc jest wprost w tej odpowiedzi,
wiec czytamy ja i powtarzamy zapytanie, bez wykonywania JS. Sprawdzone: druga proba
oddaje 200 i poprawny JSON. Bylo 0/3, jest 5/5.

galaxyporn: serwis przenosi NOWE wgrania na vikingfile.com. Probka: 12/12 najnowszych
scen na vikingfile, 12/12 najstarszych dalej na rodzinie seekplayera. Vikingfile chowa
wideo za RENDEROWANYM Cloudflare Turnstile (turnstile.render, bez trybu invisible), a
<video> jest puste i ukryte, dopoki wyzwanie nie padnie. Serwerowo nie do obejscia,
wiec oddajemy embed jako type=hoster i telefon otwiera go w WebView z domowego IP.
Rozroznienie po hoscie, bo seekplayer jako SPA w WebView pokazuje pusty player.
Najnowsze sceny: bylo 0/3, jest 3/3.

ZOSTAJE OTWARTE: rodzina seekplayera zmienila format odpowiedzi /api/v1/video. Stary
klucz AES dalej odszyfrowuje poprawnie, ale w miejsce sources sa teraz pola pk,
streamingConfig i hlsVideoTiktok ze SCIEZKA wzgledna. Zlozenie jej z hostem playera
daje 404, a z domenami z streamingConfig 403, wiec URL jest podpisywany po stronie
klienta z pola pk. Dotyczy starego katalogu galaxyporn ORAZ pornbusy (0/5).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 11:35:05 +02:00
goon-foss
5065df6220 fix(ingest): odrzucaj daty premiery odlegle w przyszlosc
Zgloszenie de732da2 ("porndish jakby zaprzestal ingestu"). Ingest dziala, 106 nowych
zrodel w 7 dni i 12-18 scen dziennie z poprawnymi datami. Problem byl na samej gorze
listy: dwie sceny porndish z datami 2026-12-02 i 2026-09-04, dodane jeszcze w maju,
stoja przy sortowaniu po premierze nad wszystkim, wiec pierwsze, co user widzi, nigdy
sie nie zmienia.

Data odlegla o miesiace to literowka w roku albo blad parsera, nie zapowiedz.
Przyjmujemy do 14 dni w przod, dalej odrzucamy, czyli scena sortuje sie po dacie
dodania. Wyczyszczone tez wstecz: 10 wierszy w calej bazie, po tym porndish ma na
gorze sceny z 2026-08-19.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 16:45:03 +02:00
goon-foss
e26c78df24 fix(ingest,proxy): pusta strona to nie koniec katalogu + miniaturki blokowane po IP
naughtymachinima (zgloszenie 83eb300d, "tylko 148 scen"): deep-crawl uznal katalog
za wyczerpany na stronie 8, bo trafil na pusta strone. Listing ma 1770 stron po 30
filmow, a ponowne wejscie na strone 9 oddalo 13 scen i ZERO bledow pobrania, czyli
tamto zero bylo chwilowym dlawieniem. Pusta strona bywa tez calkiem legalna, bo
bramka odrzuca klipy < 180 s, a to 2/3 tego katalogu. Konczymy wiec dopiero po trzech
pustych stronach pod rzad. Kursor odblokowany, kontrolny run przeszedl strony 9-14:
49 scen, 7 nowych, bez oznaczenia exhausted.

fullvideosporn (zgloszenie f4995691, "brak miniaturek"): adresy w bazie sa poprawne,
ale tn.sextu.com odrzuca nasz adres serwerowni: 429 przy kazdej probie, takze po
przerwie, a przez residential proxy 200 i 26 kB. Proxy obrazkow po odmowie
(401/403/429) ponawia teraz raz przez to proxy. Obrazek ma kilkadziesiat kB i klient
cachuje go dobe, wiec to nie jest proxowanie wideo. Sprawdzone: 6/6 miniaturek
laduje sie (15-116 kB), wczesniej 0/6.

Uwaga na przyszlosc: helper wladowal sie przy pierwszym podejsciu MIEDZY dekorator
trasy a proxy_image, wiec @router.get udekorowal jego, a /proxy/img/ oddawalo URL
proxy z loginem i haslem jako JSON. Naprawione, w docstringu ostrzezenie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 16:43:29 +02:00
goon-foss
fa7fb668b6 fix(sites): sortuj po dacie premiery z fallbackiem na date dodania + napraw miniaturki
Zgloszenie 1df50de3 ("hqporner: brak nowych scen ze strony, brak miniaturek").
Oba objawy mialy inne przyczyny i oba sie potwierdzily.

1. Kolejnosc. Sceny byly i ingest dzialal (91 nowych w 7 dni, ostatnia tego dnia),
ale tuby daty premiery zwykle NIE podaja: xhamster 99,2% scen bez daty, xnxx 97,7%,
porntrex 95,8%, hqporner 93,5%, sxyprn 85,7%. Przy release_date DESC NULLS LAST
wszystkie bezdatowe ladowaly ZA datowanymi, wiec 82 z tych 91 scen siedzialy za
3,4 tys. starszych pozycji. Teraz sortujemy po dacie premiery, a gdy jej brak, po
dniu trafienia do katalogu; sceny z prawdziwa data (kanon) bez zmian. Wyrazenie jest
immutable (jawne AT TIME ZONE 'UTC'), wiec wchodzi do indeksu, migracja 0033.

2. Miniaturki. Kafelki bez obrazka byly podpisane FULLPORNER, nie HQPORNER. Picker
bral pierwsze zrodlo alfabetycznie, a tube:fullporner < tube:hqpornercom. Dwie wady
naraz: czesc miniaturek fullporner to 153-bajtowa atrapa oddawana z kodem 200, a
czesc wskazuje CDN hqporner, ktory odrzuca Referer fullporner.com (ten sam plik:
Referer fullporner.com 403, wlasny host obrazka 200, 30 kB). Wiec: przegladany
serwis wygrywa wybor miniaturki, a proxy obrazkow po 403 ponawia raz z wlasnym
originem obrazka.

Pomiar na 40 kafelkach hqporner: przed 38 ladowalo i 1 nie, po 39 ladowalo i 0 nie,
wszystkie podpisane wlasciwym serwisem. Glowny feed bez zmian.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 16:25:53 +02:00