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.
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.
Zadanie bylo "podpiac albo usunac". Sprawdzone i NIE DA SIE podpiac.
Fallback za Cloudflare (svb.professionalvisibility.cyou/...cf-master.<ts>.txt)
oddaje 403 w szesciu wariantach:
httpx + Referer hostera httpx + Referer galaxyporn.net
curl_cffi chrome120 z Ref curl_cffi bez Ref (oddaje strone CF)
znacznik czasu biezacy znacznik z linku glownego
I to samo 403 z lacza RESIDENTIAL, wiec to nie blokada datacenter. Adres
jest najpewniej zwiazany z sesja tego samego wywolania /api/v1/video,
a my siegamy po niego osobno i po czasie (znacznik w nazwie pliku bywa
5 dni stary). Podpiecie dokladaloby request, ktory ZAWSZE pada, na
sciezce bledu — czyli opoznienie zamiast ratunku.
Cel, ktoremu mial sluzyc (przezyc padniety nod CDN), jest juz osiagniety
inaczej: ponowny resolve wraca z innym adresem CDN (47547fe).
`proxy_no_verify` ZOSTAJE mimo ze nic go nie czyta: zapisuje realne
ryzyko (cert niepasujacy do golego IP), a jego usuniecie skasowaloby te
informacje. Falszywy komentarz o istniejacej galezi `verify=False` juz
poprawiony.
Wszystkie szesc prob zapisane w docstringu, zeby nikt ich nie powtarzal.
Kontrola po zmianie: extractor oddaje m3u8, proxy 200.
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.
1745 wystapien w 291 plikach (backend, scripts, mobile). Dominowal jeden ksztalt,
' — ' laczace zdania, wiec poszedl przecinek; myslnik otwierajacy mysl zdjety;
zakresy 0–5 i A–Z na dywiz.
Podzial komentarz/kod robil skaner stanow, nie regex, zeby nie ruszyc myslnika
stojacego w stringu albo w wyrazeniu regularnym. Potwierdzone maszynowo: po wycieciu
komentarzy z wersji HEAD i z dysku obie sa identyczne we wszystkich 291 plikach,
czyli poza komentarzami nie zmienilo sie nic. 233 pliki .py parsuja sie bez bledu,
tsc ma te same 11 bledow w tych samych 3 plikach co przed zmiana.
Dwie rzeczy wymagaly poprawki po automacie: wyrownane listy definicji, gdzie myslnik
byl separatorem kolumny (37 miejsc, kolumna przywrocona), i trzy przeniesienia mysli
do nowej linii, gdzie zostawal wiszacy przecinek na poczatku (poprawione recznie).
Bundla nie republikuje: Hermes i tak nie niesie komentarzy, wiec dla uzytkownika
to zero zmiany.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pornbusy.com exposes every field as a discrete itemprop node (title,
duration, uploadDate, thumbnail, description) plus a dedicated
<div id="video-actors"> cast block with no sidebar pollution. Measured
orphan risk is low: 80% of a 100-scene sample have a performer that
already carries a tpdb/stashdb ref, and 21% of titles strongly match
scenes we already hold. No studio field exists on the site.
Homepage pagination is broken (pages 1/2/3 return an identical set), so
the listing is driven off sitemap_index.xml -> 10 post-sitemaps sorted by
lastmod, chunked in crawl_page the same way the PlayTube base does it.
Playback dispatches on embedURL and covers ~69% of the catalog: the
seekplayer family (already handled by the engine after the earlier host
regex widening) and zpi.cx (the embedURL is the file itself), plus loadvid
at ~41%, which needed new plumbing.
loadvid hands back the CONTENT of an m3u8 over POST /videos/resolve-token
(CSRF + videoToken from the embed page) and has no manifest URL at all:
GET on that endpoint is 405 and the guessable .m3u8 paths are 404. So
make_token grew an optional `producer` marker and /proxy/hls calls the
producer instead of GETting a URL. Segments in the returned manifest are
absolute and fully portable (verified: 206 on a Range request with no
headers, no referer, no token), so the phone still pulls them straight
from the CDN and only the manifest travels through the VPS.
upload18 (~12%) and the tail are deliberately left unresolved: their token
embeds the fetcher's /24, so resolving server-side would force the whole
video through the VPS.
Verified: 19 scenes/page, 19/19 with duration, 17/19 with cast, 19/19 with
tags (names read from the title attribute since an icon element precedes
the anchor text), playback 8/8 via loadvid, and /proxy/hls returning a
116KB manifest with 869 absolute segments. Pilot ingest of 3 pages: 59
seen, 35 merged into existing scenes, 24 new, 0 errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
galaxyporn.net carries paysite rips with a dedicated <div id="video-actors">
cast block (no sidebar pollution), studio + date in the title prefix, healthy
/page/N/ pagination. Measured orphan risk is low: 92% of a 75-performer
sample already have a tpdb/stashdb ref in our DB and 79% of titles match
scenes we already hold.
seekplayer_engine host regex widened to cover seekplays|4meplayer|ezplayer|
seeks|upn and the pro|cloud|one TLDs. This is the same engine (identical
AES key/IV and /api/v1/video endpoint), just newer domains; the whitelist is
additive so existing hosts keep matching (verified, including that
upns.evil.com is still rejected). Unlocks all four galaxyporn player hosts
and the same family on other sites.
Two things the extractor had to get right:
- Call seekplayer_engine directly rather than via extract_stream_from_hoster:
the wrapper verifies the resulting URL and the hotlink-guarded HLS 403s, so
it discarded correctly decoded streams.
- Referer must be the PLAYER origin, not galaxyporn.net. With the site referer
the manifest 403s; with the player origin it returns 200. Verified end to
end: manifest 200 -> variant 200 (570 segments) -> segment 206.
Duration is absent from the HTML, JSON-LD and player payload, and a NULL
duration would silently hide scenes behind the min_duration_sec filter (the
porntrex incident), so it is computed from the player's thumbnail.vtt last
cue. The player API throttles bursts, hence the retry/backoff: that took
missing durations from 9/21 down to 3/21. The value runs ~2% short of the
true length (one thumbnail interval), which beats having none.
Pilot: 21 scenes/page with studio 21/21 and clean cast (max 3), ingest of
2 pages = 42 seen, 34 new, 8 merged, 0 errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Goon — self-hosted aggregator for adult-content scene metadata.
Indexes scenes from TPDB, StashDB, and 30+ public adult tube sites.
Cross-source deduplication via perceptual hash + Levenshtein distance.
FastAPI backend + APScheduler worker + React Native (Expo) mobile client.
FOSS, ad-free, donation-funded. See README for details.