resolve_kvs zwracal None na 404, API dawalo 503 bez konca i zrodlo nigdy
nie znikalo; ok. polowa yespornvip to usuniete strony. Teraz TubePageError,
wiec resolve oznacza je martwe. Skrypt reap_kvs_404 czysci zaleglosci
(dwa 404 w odstepie i brak odtwarzacza).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Watchdog odtwarzania: origin z >= 300 zywymi zrodlami i zerem udanych
odtworzen w 7 dni (hentaimama i xanime padly tak, ze nic nie alarmowalo).
latestpornvideo: link podgladu pixhost zamieniany na obrazek, usuniety
obrazek i brak miniatury -> plakat odtwarzacza lulu; skrypt dla starych.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hentaimama: nowy zapis id posta i 5 playerow w admin-ajax, adresy w JSON-ie;
bierzemy mp4 z gdvid (3 jakosci, bez tokenu), POST najpierw bez proxy.
Ogon "Watch Online Free in HD" w tytulach ucinany.
xanimeporn: przekierowanie download.php rozwiazywane na serwerze, apka
dostawala .php, otwierala WebView i pobierala plik zamiast grac.
Blad resolve (extractor pusty, HTTP strony) trafia do playback_events.
Filmy: tytul z okruszkow (motyw dooplay losuje "Watch"/"Now Playing:"),
linki nitroflare/rapidgator nie sa juz brane za wideo, sam landing idzie
do WebView, a przytrzymanie w apce nie zabija ostatniego linku filmu,
jesli serwer widzi, ze zyje. Skrypty naprawcze: tytuly dooplay,
tytuly i miniatury hentaimama, repair_dooplay_movies dla streampornvip.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- xtremestream od 12.10 szyfruje segmenty (AES-128-CBC, IV = numer segmentu, klucz spod
tokenu zwiazanego z IP i UA): producent manifestu bierze xs1.php, przepisuje sciezki
na _enc i dokleja EXT-X-KEY; klucz oddaje /proxy/hls/<token>/key.bin na wlasny token
- proxy: Accept-Encoding identity (skompresowany manifest bez naglowka konczyl na
"Input does not start with the #EXTM3U header"), play.m3u8 z nazwy pliku jako manifest
- ingest_watchdog: porndoe jako zrodlo zamrozone (nowe sceny przekierowuja z kazdego IP)
- scripts/porntrex_duration_walk.py: dlugosci z listingu /latest-updates/N/, z dry-run
Osobny punkt wejscia (update-required.tsx) z samym ekranem blokady, bez
reszty aplikacji i bez przycisku "Pozniej". Publikowany tylko na kanaly OTA
starych runtime'ow 1.0-1.3 (0.3.0 to dzis ~8% ruchu): stare APK nie dostaja
poprawek natywnych, a ich bledy wracaly w zgloszeniach. Uzywa tylko modulow
obecnych w kazdym APK. Runtime 1.0/1.1 (stary klucz podpisu) dostaje kroki
z kodem synchronizacji, od 1.2 nowa wersja instaluje sie na wierzchu.
publish_update.py --entry podmienia pole main w package.json na czas
eksportu i odmawia publikacji na biezacy runtime.
Emulator: prawdziwe APK 0.3.0 i 0.2.1 z ta paczka pokazuja ekran, pobieranie
otwiera APK w przegladarce, kopiowanie kodu dziala, Wstecz zamyka apke,
0.4.2 instaluje sie na 0.3.0 i startuje normalnie.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Zrodlo znikalo tylko po dlugim przytrzymaniu przez uzytkownika. Teraz
zgloszenie "Response code: 404/410" uruchamia w tle ponowny resolve z serwera;
martwe dopiero, gdy ekstraktor mowi "usuniete" albo plik z serwera tez daje
404/410 (dwie kontrole). Na sucho na 84 parach z 14 dni: 0 martwych, 83 zywe,
czyli 410 z telefonu prawie zawsze znaczy zly adres, nie skasowany plik.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
edge_replay_features.py liczy na prodzie cechy znane w chwili kazdego
wyswietlenia, edge_tuning_analysis.py ocenia formuly (AUC w obrebie
urzadzenia, podzial w czasie). Na nich dobrana punktacja z 4666fcb.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Grupy po hashu urzadzenia, tylko slot affinity, srednie po urzadzeniach.
Test A/A na tygodniu przed wdrozeniem: dokonczenia 13,0% vs 13,1%, lajki
3,4% vs 3,1%, ucieczki 49,1% vs 49,6% (357 i 111 urzadzen), czyli szum ~0,5 pp.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Analiza zrodel z theporndude (zrzuty JSON, raporty i piec skryptow,
ktore je czytaly), probka strony streamtape i nieuzywana strona
landing/ (goon-foss.org serwuje site/).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ekran serwisu (/scenes?origin=tube:X&sort=release_date) dla serwisow,
ktorych scen nie ma wsrod najnowszych w katalogu (perverzija, hdporn.gg,
tubepornclassic, yesporn), sortowal wszystkie ich sceny: 9-19 s na
zimnym cache, 1-4 s na cieplym, 39 wejsc w 3 h.
Wzorem scene_tags.sort_date (GOON-64): data sortu powielona w
playback_sources i pilnowana wyzwalaczami (0048), wypelniona skryptem,
indeks (origin, sort_date DESC, scene_id DESC) WHERE dead_at IS NULL
(0049). API dolacza DISTINCT ON zgodny z indeksem, bo 190 tys. scen ma
dwa zywe zrodla z tego samego serwisu. Po zmianie 0,03-0,24 s, takze
dalsze strony.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scraper siski do 494b15a zapisywal kilka osob z alt jako jedna. Skrypt
przepina sceny, filmy i ulubione na prawdziwe osoby (resolve_performer),
czarnych list nie przenosi. "Woods, Monique" rozpoznaje jako jedna osobe
tylko gdy tytul sceny to potwierdza. Na prodzie: 660 zlepkow, 1194
powiazania, 4 nowe osoby, 4 niejasne zostaly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Strona filmu hqporner nie ma wlasnej okladki, a pierwszy _main.jpg na niej to kafelek
polecanego filmu. Scraper go bral, wiec ~90% zrodel dostalo cudze miniatury (62 tys.
zrodel, 5,4 tys. roznych miniatur). Okladka jest tylko w kafelku listingu
(cover_<id>): browse zbiera je z listingu, wyszukiwarka z wynikow wyszukiwania.
scripts/hqporner_fix_thumbs.py poprawia zapisane miniatury przechodzac listing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ekran tagu (jeden tag, sort=release_date, 200 scen) sortowal po dacie z `scenes`, a filtrowal
po `scene_tags`. Postgres szedl od najnowszej sceny calego katalogu i kazda sprawdzal; przy
tagach rzedu 40-60 tys. scen (`rough-sex`) to 46 tys. scen na strone, 7-15 s na zimnym cache.
Dwie przebudowy samego zapytania nie pomogly (2x albo 30 s na duzych tagach), cache tez nie,
bo wejscia rozkladaja sie na setki tagow.
`scene_tags.sort_date` (0042) trzyma ta sama date co `_effective_date_desc()`, pilnowana przez
wyzwalacze w bazie, indeks (tag_id, sort_date DESC, scene_id DESC) w 0043. Wypelnianie 23 mln
wierszy: scripts/backfill_scene_tags_sort_date.py, partiami z pauza.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Opisy scen szly do bazy z `"`, `<br>` 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>
xvideos (JSON-LD) i kilka innych tubow oddaje tytuly z encjami HTML5
(`we're`, `(AI)`), 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>
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.
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).
- _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>
- 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
- 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
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.
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.
Pierwszy prawdziwy przebieg na "The Doctor" padl na kluczu glownym movie_performers:
helpery resolvera sprawdzaja "czy juz jest" SELECT-em, ktory bez flush nie widzi
wierszy dodanych przez poprzedni profil klastra, wiec ten sam performer z dwoch luster
wpadal dwa razy. Teraz flush po kazdym profilu; transakcja per film, wiec nieudany
film wycofuje sie w calosci i nic nie zostaje w polowie.
Dopelnianie pol (tylko braki) z kazdego pobranego lustra klastra, nie tylko ze wzorca:
wzorcem bywa paradisehill bez roku, a mangoporn ma rok i studio ("Doctor Adventures 14"
tracil rok 2013).
`--shard k/n` po hashtext(id) do rownoleglych kontenerow: 8204 filmy w jednym watku to
~16 h (40 filmow w 4,6 min w probie), w trzech ~6 h.
Wynik na "The Doctor": 16 refow -> 11 filmow, kotwica z jednym refem i rozdzialami,
"Granny's Doctor Games" z dokladnie swoimi dwiema stronami i embedami, 76 zwietrzalych
lub cudzych hosterow skasowanych z kotwicy, 115 przeniesionych do wlasciwych filmow.
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.
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.
`.gitignore` ma regule na `_*.py` (pliki robocze), przez co wspolny modul sondy wypadl z
poprzedniego commita i zostaly w nim dwa skrypty importujace nieistniejacy modul.
Uogolnienie `sxyprn_reap_dead.py` na pozostale tuby. Werdykt bierze sie z `try_extract`,
czyli z kodu, ktorego uzywa aplikacja przy odtwarzaniu, wiec sonda nie widzi czegos
innego niz user. Martwe pada TYLKO na 404/410 albo `HosterDead`; pusty wynik ekstraktora
to "nieznane" i zrodla nikt nie rusza.
Bramka odpala sie ZA KAZDYM URUCHOMIENIEM, zamiast polegac na tym, ze ktos pamieta wynik
wczesniejszego pomiaru. Sprawdza jednoczesnie, czy sonda widzi smierc (adresy scen, ktore
nie moga istniec, musza wrocic martwe) i czy nie zabija zywych (sceny odegrane w ostatnich
7 dniach musza wrocic zywe). Nie zdana bramka konczy skrypt bez tkniecia bazy.
Wynik pierwszego pomiaru: przemial ma sens dla hqporner (~29%) i galaxyporn (~14%).
porntrex, xvideos, neporn, supjav i reszta soft-404 odpadaja, bo sonda ich smierci nie
widzi. youperv odpada, bo oddaje martwe na 25% scen, ktore realnie sie odegraly.
Trzy rzeczy, ktore wyszly dopiero przez kontrole, nie przez czytanie kodu:
* Pierwsza wersja sondy pytala tylko o status HTTP i uznala SXYPRN za tuba, na ktorym nic
nie widac (0/6), chociaz wlasnie wygasilismy tam 34% zrodel. Sxyprn oddaje skasowany
post jako HTTP 200, a `HosterDead` leci dopiero z ekstraktora. Po przejsciu na
`try_extract` negatywna daje 7/7.
* Kontrola pozytywna przy 12 probach byla za ciasna: jeden trup to 8% i przewracal prog
5%, chociaz realny szum galaxyporn to ~3%. Stad 40 prob i okno 7 dni zamiast 14, bo im
swiezsze odtworzenie, tym mocniej "martwe" wskazuje na nasz blad, a nie na kasowanie.
* Budowanie adresow nieistniejacych przez podmiane cyfr nie dzialalo dla tubow BEZ numeru
sceny w adresie (hentaigasm, mypornerleak, freshporno). Wychodzily jako "0/0", czyli
niezmierzone, a to okolo 950 tys. zrodel. Teraz kolejno: numer w query, segment-
identyfikator, a dopiero na koncu slug. Kolejnosc jest istotna, bo psucie segmentu
trasy (`videos`) sprawdzaloby, czy tub obsluguje adres, a nie czy istnieje scena, wiec
tub oddajacy 404 na zla trase i 200 na nieistniejaca scene falszywie zdalby bramke.
Sonda siedzi w `_reap_probe.py` wspolnym dla pomiaru i przemialu, zeby bramka testowala
dokladnie ten kod, ktory potem mieli baze.
Po sxyprn (34% martwych na 188 tys. zrodel) nasuwa sie przemielenie tak samo calej
reszty. Metoda sxyprn nie przenosi sie wprost:
* Twardy sygnal smierci (`HosterDead`) ma tylko 6 z 42 ekstraktorow. Dla reszty "nic nie
zwrocil" znaczy naraz "skasowane", "zmienil sie markup" i "rate limit". Wygaszanie na
tej podstawie schowaloby ZYWE sceny, jak przy porntrex (6479 scen po cichej zmianie
markupu).
* Zywych zrodel jest ~3,9 mln, czyli ponad tydzien ciaglego pukania do wlasnej podazy.
Dlatego najpierw pomiar. Skrypt jest wylacznie do odczytu, niczego nie oznacza.
Martwe pada tylko na twardych sygnalach: HTTP 404/410 albo `HosterDead`. Pusty wynik
ekstraktora to "nieznane" i zrodla nikt nie rusza.
Kazdy tub dostaje DWIE kontrole, bo sam wynik proby niczego nie dowodzi: "0% martwych"
znaczy albo "tub zdrowy", albo "nie widzimy trupow".
* Pozytywna: zrodla scen, ktore realnie odegraly sie w ostatnich 14 dniach. Musza wrocic
zywe. Lapie tuba, ktory zaczal oddawac 404 wszystkiemu bez sesji, czyli przypadek, w
ktorym przemial skasowalby caly katalog. Prog to 5%, nie zero, bo czesc scen znika
naprawde. Odsetek z kontroli odejmuje sie od wyniku proby.
* Negatywna: prawdziwy adres z numerem sceny podmienionym na absurdalny. Taka strona nie
moze istniec, wiec musi wrocic martwa.
Negatywna od razu sie oplacila: pierwsza wersja pytala tylko o status HTTP i uznala
sxyprn za tuba, na ktorym sonda jest slepa (0/6), chociaz wiemy, ze ma tam 34% trupow.
Powod: sxyprn oddaje skasowany post jako HTTP 200, a `HosterDead` leci dopiero z
ekstraktora. Po przejsciu na `try_extract` negatywna daje 7/7.
Tuby resolvowane tylko w WebView na telefonie sa pomijane, bo z VPS sa nieweryfikowalne.
Po wznowieniu przerwanego przebiegu pierwsza porcja dala 498 zywych i ZERO martwych,
przy sredniej 35%. Powod: przebieg idzie `ORDER BY id`, a poprzedni zdazyl sprawdzic
151 tys. pozycji. Martwe wypadly ze zbioru, ale 100 763 POTWIERDZONYCH JAKO ZYWE
zostalo i skrypt sprawdzal je po raz drugi. To 73% pracy i tyle samo zbednych zadan do
sxyprn, czyli dokladnie to, czego chcialem uniknac przy tym zrodle.
Dolozony `--after-id`: pomija wszystko o id <= podanego. Granice bierze sie z bazy jako
najwyzsze id wsrod juz oznaczonych (`max(id::text)::uuid`), sposob zapisany w komentarzu
przy zapytaniu.
Sprawdzone, ze granica jest wlasciwa: przed nia 0 martwych na 500, zaraz za nia
6 martwych na 10. Do zrobienia zostalo 37 391 zamiast 138 154.
Przebieg po 151 tys. sprawdzonych zrodel przepadl, bo sam ubilem go wlasnym
`docker compose restart worker` przy wdrazaniu poprawek seekplayera. Log urwal sie
o 06:54, kontener wystartowal o 06:58. Proces zostal jako pusta skorupa (jeden watek,
zero postepu), a wygladalo to na zawieszenie: sxyprn odpowiadal normalnie w 0,2 s,
baza byla bez blokad.
Trzy zmiany, kazda usuwa jedna slabosc, ktora to ukrywala albo pogarszala:
* PORCJAMI po 500, ze swieza pula na kazda porcje. `pool.map` na calej liscie
kolejkowal 188 tys. zadan naraz, wiec przerwanie w polowie nie zostawialo zadnego
punktu zaczepienia, a pamiec rosla bez potrzeby.
* JEDEN `UPDATE` na porcje zamiast jednego na wiersz.
* `flush()` po kazdej porcji. Log do pliku byl buforowany i milczal godzinami, przez co
martwy przebieg wygladal identycznie jak pracujacy.
W docstringu jawne ostrzezenie: to zadanie NIE MOZE chodzic w kontenerze workera, bo
kazdy deploy backendu je ubija. Odpalac przez `docker compose run -d --rm worker`,
czyli w osobnym kontenerze. Wznawianie jest darmowe, bo bierzemy tylko zywe zrodla.
Stan: 52 998 zrodel juz oznaczonych martwymi, wznowione na pozostalych 138 154.
Na prosbe Jana wygaszone hurtem 338 904 zrodla rodziny seekplayer (easyvidplayer,
embedseek, seekplayer, upns, player4me, rpmplay) na 26 248 filmach.
Dowody, ktore to uzasadnily, trzy niezalezne:
1. Swieze identyfikatory wziete PROSTO ze strony serwisu tego samego dnia zachowuja sie
tak samo jak nasze z bazy: brak adresu albo 404. Czyli to NIE jest nasza staroc,
tylko hoster nie serwuje (przy galaxyporn ten sam test wychodzil odwrotnie).
2. Pomiar per marka, po 6 probek na kazda: 0 grajacych na 36.
3. Rozkodowany ich wlasny player: komunikat "Media source is not playable" pada dopiero
po wyczerpaniu WSZYSTKICH czterech sciezek CDN (Ce.shift() az do pustej listy). Czyli
ich klient tez sie poddaje.
Zabezpieczenie: NIE wygaszono zrodel filmu, ktory nie ma nic innego (4 zrodla, 1 film),
zeby nic nie zniknelo z katalogu. Po operacji 0 filmow stracilo wszystkie zrodla, a te,
ktore mialy ta rodzine, maja srednio 10,6 zywych zrodel.
Odwracalne: ustawiamy dead_at + czytelny dead_reason, nie kasujemy wierszy.
Skrypt: `_probe` deleguje teraz do `seekplayer_engine.extract`, zeby werdykt byl TEN SAM
co u resolvera aplikacji. Wczesniej mial wlasna, luzniejsza regule (sa pola = zywe) i
uznawal za zywe zrodla z adresem do usunietego pliku, na ktorych CDN oddaje 502.
Usuniete nieuzywane importy i akapit docstringu, ktory po tej zmianie mowil cos
przeciwnego niz kod.
Obserwacja Jana: scena sxyprn z widoczna miniatura gra, bez miniatury w ~90% nie, i
jest sporo takich smieci. Sprawdzone i potwierdzone mechanicznie.
Miniatura sxyprn NIE jest brana z zapisanego thumbnail_url (te sa podpisane czasowo,
TTL < 1h, dawno wygasly), tylko z /proxy/sxyprn-thumb/<id>, ktory NA ZYWO pobiera
strone posta i wyluskuje poster. Odtwarzanie bierze data-vnfo z DOKLADNIE tej samej
strony. Skasowany post = pusty kafelek ORAZ brak streamu. Stad korelacja widoczna w apce.
Sygnal smierci jest twardy: usuniety post zwraca HTTP 200 ze strona "Post Not Found"
(soft-404), a ekstraktor rzuca wtedy HosterDead. Tylko to oznaczamy martwym. Strona
bez data-vnfo (niepewny przypadek) zostaje nietknieta.
Oznaczamy dead_at (odwracalne), NIE kasujemy wiersza: gdyby to byl chwilowy blad albo
sxyprn wskrzesil post, wystarczy wyzerowac znacznik. Efekt w UI ten sam co kasowanie.
Wolno i grzecznie (3 watki, 0,5 s odstepu), bo sxyprn to nasz TOP origin (~12 tys.
odtworzen miesiecznie) i nie chcemy bana. Przebieg testowy 5000: 65% zywych, 35%
martwych (1755 oznaczonych), 2 niepewne, 18 min, zero oznak rate-limitu.
Pelny przemiał 188 602 zywych zrodel uruchomiony odpiety w kontenerze.
Bez tego mapy mial WYLACZNIE bundle wbudowany w APK, a praktycznie kazdy uzytkownik
dociaga paczke OTA przy pierwszym uruchomieniu i od tego momentu w Sentry widac
`app:///index.android.bundle` zamiast nazw plikow i numerow linii. Czyli przebudowa APK
z tokenem sama w sobie dawala czytelne slady na kilkadziesiat sekund zycia instalacji.
Trzy zmiany w `publish_update.py`:
* `expo export` z `--source-maps`
* `upload_sourcemaps()` woła oficjalny `expo-upload-sourcemaps.js` z @sentry/react-native.
Dopasowanie idzie po `debug id` zaszytym w paczce, wiec nazwa release'u ani dist nie sa
potrzebne. Brak `SENTRY_AUTH_TOKEN` NIE jest bledem, bo publikacja ma dzialac takze u
kogos, kto stawia wlasna instancje; wtedy tylko o tym mowimy. Nieudana wysylka rowniez
nie blokuje publikacji: gorsza jest apka bez poprawki niz nieczytelny slad.
* `strip_sourcemaps()` kasuje mapy z `dist` PRZED scp. Mapa wazy 11 MB przy 3 MB paczki i
zawiera caly kod zrodlowy, a `scp -r .` wyslalby ja razem z reszta, wiec lezalaby
publicznie obok paczki. `metadata.json` jej nie wymienia, wiec manifest sie nie psuje
(sprawdzone).
Pulapka skryptu Sentry: siega po konfiguracje Expo, gdy brakuje KTOREGOKOLWIEK z
SENTRY_ORG, SENTRY_PROJECT i SENTRY_URL, i wtedy konczy bledem. SENTRY_URL nie jest
sekretem, wiec podstawiamy sentry.io. Musi tez dzialac z katalogu `mobile`, bo zaklada,
ze stoi w korzeniu projektu.
Publikuj przez `iclaude goon -- ...`, wtedy token wjezdza ze srodowiska.
Zweryfikowane end-to-end na katalogu testowym na VPS, bez ruszania zywych kanalow:
mapy poszly do Sentry (debug id e2feb975), zostaly usuniete z dist (11,1 MB), manifest
zbudowany z 23 assetami, a na serwerze wyladowalo 0 plikow .map.
Przy okazji ustalone: paczki juz stojace na wszystkich trzech kanalach maja identyczna
tresc z ta, ktorej mapy wyslalem, wiec slady dla obecnych uzytkownikow odczytaja sie bez
zmuszania kogokolwiek do ponownego pobrania 3 MB.
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.
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.
Deep-crawl przemielil listing HTML do konca (kursor 548, exhausted), a mimo to
sitemapa ma sceny, ktorych nie mamy. Pomiar na osmiu submapach po 60 losowych
adresow: 46% angielskich URL-i nieznanych, w nowszych submapach nawet 75%. Przy
ok. 29 tys. adresow to rzedu 13 tys. scen. Listing nie wystawia calego katalogu.
Skrypt, nie job w schedulerze, bo superporn nic juz nie publikuje: submapy sa
ulozone chronologicznie, a najnowszy wpis ma date 2025-01-28. To nadrobienie raz.
Wznawianie za darmo, bo bierzemy tylko adresy nieobecne w playback_sources.
Sceny leca z backfill=True, zeby katalog 2022-2025 nie udawal swiezosci.
Kontrola jakosci na pierwszej partii: obsada 20% (korpus superporna ma 17,2%),
srednio 4,7 tagu (3,4), dlugosc w 100%, zero bledow.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"Natural Tits", "Big Black", "Anal Milf", "Cum Swallow", "Fat Ass" i 94
inne siedzialy w tabeli performers z tagow tubow wciaganych jako obsada.
Ugryzly 2026-08-14 przy rozplataniu zlepkow: regula uznala "Big Black" za
osobe wymieniona w tytule i dala mu 124 sceny.
TRZY OCZYWISTE HEURYSTYKI SPRAWDZONE I ODRZUCONE, kazda z kontrprzykladem:
1. "nazwa jest tez tagiem" -> prawdziwe dla Lauren Phillips, Julii Ann,
Nikki Benz (tuby robia tagi z nazwisk), 7625 z 74150 nazw
2. "nie ma kanonu" -> TPDB SAM MA "Big Black" i "Lesbian Love"
jako performerow, a realna "Mena Mason" refow nie ma
3. "tag >> performer" -> dziala dla "Natural Tits" (2147x) i "Rough
Sex" (1552x), ale "Big Black" ma 0,2x, "Lesbian Love" 0,0x
Kryterium jest wiec STRUKTURALNE i nie zalezy od zadnej z tych baz: cala
nazwa zlozona wylacznie ze slow opisujacych tresc. Kandydatow 101, czyli
na tyle malo, ze lista zostala PRZEJRZANA RECZNIE.
Przeglad wylapal falszywki: "Dick Nasty" ma refy z szesciu zrodel, w tym
StashDB, i jest realnym meskim performerem (obsada "Sugar Daddy 17" obok
Dave'a Cummingsa). "King Cock" wykluczony z ostroznosci. Oba w
_JEDNAK_LUDZIE, z uzasadnieniem w kodzie.
Wynik: 11 793 przypisania zdjete od 99 kategorii, do archiwum. Same rekordy
performerow ZOSTAJA: scene_count spadl do 0, wiec i tak wypadaja z list
z only_with_content, a skasowanie rekordu zerwaloby refy kanoniczne przy
czyms, co TPDB u siebie trzyma jako performera.
Kontrola: Big Black/Natural Tits/Anal Milf/Fat Ass -> 0 scen, Lauren
Phillips 2146 i Dick Nasty 69 nietkniete.
Scraper tworzyl osoby, ktore nie istnieja, biorac imie jednej i nazwisko
drugiej osoby z tej samej sceny:
"Lilly Blossom" = Lilly Bell + Blake Blossom
"Chloe Ryder" = Chloe Temple + Sera Ryder
"James Driller" = Kenna James + Ryan Driller
"Parker Banks" = Zoe Parker + Cassidy Banks
prune_token_overlap_attributions ich nie widzi, bo wymaga INNEGO
udokumentowanego performera na scenie, a zlepek jest zwykle JEDYNYM
przypisanym. Znowu ODZYSKIWANIE, nie kasowanie: obie prawdziwe osoby stoja
w tytule i nie byly przypisane.
Wynik: 3993 zlepki zdjete, 7988 prawdziwych przypisan dolozonych.
Zyskali m.in. Lauren Phillips +74 sceny, Gianna Dior +45, Jenna Sativa +42,
Aaliyah Love +41, Keiran Lee +41.
BLAD W PIERWSZYM PRZEBIEGU I JEGO NAPRAWA: regula uznala nazwy-KATEGORIE
za "wlasciciela" wymienionego w tytule i "Big Black" dostal 124 sceny,
a dziewiec innych po kilka. Zdjete osobno (197 przypisan, do archiwum),
plus jawna lista wykluczen w skrypcie. Lista jest JAWNA, bo obie oczywiste
heurystyki zawodza: "nazwa jest tez tagiem" jest prawdziwe dla Lauren
Phillips i Julii Ann, a "ma kanon" jest prawdziwe dla "Big Black".
CZEGO NIE RUSZAM: 3150 zlepkow MAJACYCH kanon. "Nikki Monroe" czy
"Valentina Lopez" moga istniec naprawde, a "Lauren Smith" wzielo sie
z trojczlonowego nazwiska aktorki ("lauren lee smith"). Istnienie osoby
nie przesadza, czy jest w TEJ scenie.
Szersza reguła "w tytule stoi ktos inny" ODRZUCONA po probce: 31% trafien
to byly kategorie-smieci, a similarity trigramowe nie rozdziela klas
(siostry Dellai 0,318 vs Nikki Nevada/Brooks 0,316).
Siedem performerow o nazwie JEDNOCZLONOWEJ ("James", "Blue", "Moon",
"Crystal", "Cruz", "Starr", "Knight") zbieralo sceny wielu roznych osob
dzielacych ten czlon: "Blue" mial sceny Anity, Delilah i Bonnie Blue,
"Starr" mial Violet, Natashe i Bobbi Starr.
prune_token_overlap_attributions z zalozenia ich NIE RUSZAL i to nie byl
niedopatrzenie: dla nazwy jednoczlonowej za dowod uznaje samo wystapienie
tego slowa w tytule, wiec "James" jest "udokumentowany" przez kazda scene
wspominajaca jakiegokolwiek Jamesa. Stad 0 skasowanych z tej siodemki.
To NIE bylo kasowanie, tylko ODZYSKIWANIE: w probce 14/14 wlasciwa osoba
NIE byla przypisana do sceny, czyli Bonnie Blue nie miala tych scen na
swojej stronie.
Kryterium: przypisanie ze scrapera (kanon nietykalny — z 605 przypisan
tych siedmiu 518 jest ze scrapera) + istnieje performer, ktorego nazwa
konczy sie tym czlonem po spacji + ta PELNA nazwa stoi w tytule sceny
jako ciag calych slow. Ostatni warunek odroznia odzyskanie od zgadywania.
Wynik: dolozono 271 wlasciwych przypisan, zdjeto 268 mononimow (roznica
to sceny, gdzie w tytule stoja DWIE takie osoby, np. Bonnie i Mick Blue —
obie sa dokladane, mononim schodzi raz).
Zyskali m.in.: Violet Starr +22 sceny, Mick Blue +16, Stacy Cruz +15,
Rachel Starr +13, Alexis Crystal +12, Natasha Starr +8.
Mononimy spadly: Starr 93->28, Cruz 45->8, Moon 64->23, Blue 113->73.
Reszta zostaje nietknieta, bo nie ma w tytule wskazanego wlasciciela —
"Blue" i "Cruz" maja refy StashDB, wiec czesc z nich moze byc prawdziwa.
Zdjete wiersze ida do scene_performers_pruned, cofniecie to INSERT..SELECT.
Kasowane wiersze ida najpierw do `scene_performers_pruned`, w TEJ SAMEJ
transakcji co DELETE: albo wiersz jest zapisany i skasowany, albo nie
dzieje sie nic. Cofniecie to `INSERT ... SELECT`, nie backup calej bazy.
Archiwum trzyma tez nazwe performera i tytul sceny, wiec da sie je
przejrzec bez odtwarzania joinow. Tabela swiadomie poza alembikiem: to
slad po jednorazowym sprzataniu, nie czesc schematu.
Kryterium doprecyzowane po dwoch losowych probkach:
1. „brak nazwy w tytule" samo w sobie kasowalo MESKICH performerow (tuby
nie wypisuja ich w tytulach, przypisanie szlo z listy obsady) -> stad
warunek „inny performer sceny ma dowod I dzieli czlon".
2. Dowodem dla nazwy o >=2 czlonach jest kazdy czlon jako OSOBNE SLOWO,
nie spojna fraza: „Silvia and Eveline Dellai" to scena Silvii Dellai,
ale ciagu „silviadellai" tam nie ma (1 blad na 22 w probce). Nazwy o
jednym uzytecznym czlonie („Eliza E") zostaja przy ostrym kryterium,
bo inaczej lapia kazda inna Elize.
3. Granica slowa przez `strpos` na znormalizowanym tekscie, NIE regex:
nazwy z nawiasami wywalaly caly przebieg („parentheses not balanced"),
a metaznaki po cichu psulyby dopasowania.
Dry-run: 321 833 przypisania (vs 370 587 przed poprawka 2). Szkoda
rozproszona, nie skoncentrowana: rekordzistka traci 20 z 909.
Zgloszenie 2026-08-13: strona Tiffani Time pelna scen o Tiffany Tatum,
Tiffani Madison i Victorii Tiffani.
Przyczyna: `_search_base.search` dokleja szukanego performera do KAZDEJ
sceny bezwarunkowo (`all_performers = [RawPerformer(name=query), ...]`),
wiec cala poprawnosc obsady wisi na filtrze tokenow. A filtr testowal
PODCIAG na luznych tokenach, wiec:
"tiffany" ⊂ "lp-s-tiffany-love-first-time-gonzo" (inna osoba)
"time" ⊂ "adult-time", "first-time", "multiple-times" (pospolite slowo)
Historia tej linijki to trzy poziomy: any() -> all() -> (teraz) fraza.
`all()` naprawil "Ava Koxxx na scenach Avy Devine", ale zostawil oba
powyzsze. Teraz slug musi zawierac CALA nazwe jako ciag, z granica slowa
po bokach, z dowolnym separatorem miedzy czlonami.
Dozwolone koncowe "s": slug gubi apostrof, wiec "TiffaniTime's" zapisuje
jako "tiffanitimes". Nie luzuje bramki, bo przed tym "s" stoi cala fraza.
hqporner mial WLASNA kopie tego filtru (i wlasny zestaw dziur) - podpiety
pod ta sama funkcje, zeby sie nie rozjezdzalo.
12 przypadkow testowych z realnych danych, w tym te ktore MUSZA przejsc
(tiffani-time-*, tiffanitimes-*, mia-li-* z czlonem <3 znaki).
Do tego skrypt czyszczacy juz istniejace pomylki. Kryterium zawezone po
obejrzeniu probki: samo "brak nazwy w tytule" kasowalo MESKICH performerow
(tuby nie wypisuja ich w tytule, a przypisanie szlo z listy obsady, nie
z searcha). Dolozony warunek "inny performer sceny ma dowod I dzieli
czlon" - probka 14/14 to realne pomylki.
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>
RUNTIME_DEFAULT 1.1 -> 1.2 (APK 0.2.2 z expo-keep-awake). Kanal 1.1 zostaje zywy
dla instalacji sprzed 0.2.2, ktore nie zaktualizuja sie in-place (stary klucz
podpisujacy przepadl) i dostaly baner migracji; poprawki dla nich publikuj jawnie
przez --runtime 1.1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Kazde szukanie slowa w tytulach bylo sekwencyjnym skanem 3,46 mln wierszy. Blokowalo
to ranking over-attribution: metryka "ile scen ma te nazwe w tytule, ale NIE jest do
niej przypisanych" wymaga jednego skanu NA KANDYDATA, a kandydatow jest ~800. Proba
zostala ubita po 10 minutach.
GIN + gin_trgm_ops obsluguje LIKE, ILIKE i regexy, a pg_trgm sam normalizuje wielkosc
liter, wiec indeks na surowym title wystarcza. Efekt: 26 ms zamiast sekund na
zapytanie, ranking 800 kandydatow w 48 sekund zamiast godzin. Indeks 315 MB.
Zbudowany CONCURRENTLY w autocommit_block: zwykle CREATE INDEX trzymaloby lock
blokujacy zapisy na scenes przez cala budowe i zatrzymalo ingest.
Ranking od razu pokazuje dwie rozne rzeczy. Czyste smieci ("Pornhub" 105.9, "Monster"
92, "Pretty" 63, "Nice" 42) oraz SAME NAZWISKA (Devine, Starr, Dior, Cruz, West,
Knight, Johnson, James) - wpisy powstale z rozbicia imienia i nazwiska, ktore potem
lapia kazda scene z tym nazwiskiem, nalezaca do zupelnie innej osoby.
Usuniete przy okazji: "Pornhub" (108 scen, 0 z kanonu, wszystkie to "full video on
pornhub") i "Precious" (119 scen, 0 z kanonu, sam przymiotnik).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ostatnia klasa smieci: REALNA osoba o nazwie bedacej pospolitym slowem, do ktorej
tube-search dokleja wszystko, co ma to slowo w tytule. Rapture miala 30 z 72
przypisan falszywych (film "The Rapture" z Mimi Rogers, literowka "hymen raptured",
tytuly scen).
NIE MA na to sygnalu automatycznego. Przetestowalem piec i zaden nie rozstrzyga:
- sama provenance ze scrapera: realni tworcy spoza TPDB (Amouranth, MollyRedWolf)
tez maja 100 procent przypisan ze scrapera
- obsada z kanonu na scenie: backfill 0026 wypelnil tylko sceny jednozrodlowe, wiec
sceny mieszane maja NULL - 1 trafienie na 560 tys.
- udzial nazwy w tytule: u niszowych prawdziwych tez ~100 procent (Amouranth 100,
Clanddi 100)
- obce sceny ze slowem: myli generyczne uzycie z pominieta atrybucja
- stosunek tag/performer >=1: wyklucza 79 pozycji, ale samej Rapture BY NIE ZLAPAL
Zostaje czytanie tytulow. Skrypt robi z tego kilka minut zamiast pol godziny: listuje
komplet z provenance i kontekstem, liczy wskaznik pospolitosci nazwy, przyjmuje liste
prefiksow do odpiecia i DOMYSLNIE nie rusza przypisan potwierdzonych przez kanon.
Bez trybu rankingu wszystkich kandydatow: bez indeksu trigramowego na scenes.title to
skan 3,4 mln tytulow RAZY ~800 kandydatow. Sprobowalem, ubilem po 10 minutach.
Przy okazji przeglad zdemaskowal "Precious" (119 scen, 0 z kanonu) - wszystkie
przypisania to przymiotnik ("precious stepdaughter", "her ass is precious"). Usuniete.
Skala reszty: 1335 kandydatow z >=20 scenami, 539 z >=100. Nie ma sensu przerabiac
wszystkich - narzedzie jest na zglaszane przypadki.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
scene_performers nie zapisywalo, KTO przypisal performera do sceny. Przez to nie dalo
sie odroznic obsady z kanonu od performera doklejonego przez tube-search, ktory
dopasowuje wynik po JEDNYM tokenie zapytania. Stad przypadek "Rapture": 30 z 72 jej
przypisan bylo falszywych (film "The Rapture" z Mimi Rogers, literowka "hymen
raptured", tytuly scen) i trzeba bylo je przegladac recznie, bo nie bylo sygnalu.
Kolumna trzyma NAJBARDZIEJ wiarygodne zrodlo, jakie przypisalo. Regula idzie tylko w
gore: NULL wypelnia cokolwiek, kanon nadpisuje scraper, scraper NIGDY nie zamazuje
kanonu. Inaczej dowolny pozniejszy tube-search zatarlby informacje, ze obsade
potwierdzilo TPDB. To samo przy merge_scenes: przy kolizji przenosimy lepsza
provenance na keepera, zeby scalanie nie degradowalo potwierdzonej obsady.
Backfill wypelnil 4 147 128 wierszy (96,3 procent) wnioskowaniem, ktore jest pewne:
scena z refami z DOKLADNIE jednego zrodla ma cala obsade stamtad. Sceny wielozrodlowe
(67 tys.) zostaja z NULL-em, bo tam zgadywanie zepsuloby sens kolumny. Wsadowo, z
commitem na paczke: pojedynczy UPDATE na 4 mln wierszy trzymalby locki na
scene_performers i zablokowal ingest.
Rozklad: tube-scraper 3 219 677, tpdb 747 540, stashdb 180 355.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>