chore(seekplayer): wygaszona cala rodzina dla filmow + reaper zgodny z resolverem
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.
This commit is contained in:
parent
38eee03902
commit
1fd1a750e3
1 changed files with 33 additions and 46 deletions
|
|
@ -7,14 +7,12 @@ w odpowiedzi nie ma pola `source`. Ich własny player w tej sytuacji pisze wpros
|
||||||
„Video is not ready yet", co potwierdziłem w przeglądarce z łącza domowego, i to samo
|
„Video is not ready yet", co potwierdziłem w przeglądarce z łącza domowego, i to samo
|
||||||
widać z VPS oraz z brytyjskiego proxy, więc nie chodzi o blokadę po IP ani po kraju.
|
widać z VPS oraz z brytyjskiego proxy, więc nie chodzi o blokadę po IP ani po kraju.
|
||||||
|
|
||||||
Skala (próbka 45 losowych źródeł, 2026-08-24): 26 razy HTTP 404, 18 razy odpowiedź bez
|
Skala (próbka 45 źródeł, 2026-08-24): 26 razy HTTP 404, 18 razy odpowiedź bez strumienia,
|
||||||
strumienia, 1 raz działający strumień. Czyli około 2% katalogu na tym silniku jeszcze
|
1 raz działający strumień. Powtórka 2026-08-27 na sześciu markach: 0 grających na 36.
|
||||||
gra, reszty hoster już nie ma. Sam protokół jest bez zmian, dlatego NIE kasujemy tych
|
|
||||||
źródeł hurtem, tylko pytamy o każde z osobna i zostawiamy te, które odpowiadają.
|
|
||||||
|
|
||||||
Bezpieczeństwo: filmów zależnych WYŁĄCZNIE od tej rodziny jest w bazie dokładnie
|
Bezpieczeństwo: filmów zależnych WYŁĄCZNIE od tej rodziny jest w bazie jeden, pozostałe
|
||||||
jeden, pozostałe 26 223 mają inne źródło. Sprzątanie nie chowa więc katalogu, tylko
|
mają inne źródło. Sprzątanie nie chowa więc katalogu, tylko przestaje podsuwać wybór,
|
||||||
przestaje podsuwać wybór, który i tak kończy się czarnym ekranem.
|
który i tak kończy się czarnym ekranem.
|
||||||
|
|
||||||
Oszczędność: domeny bliźniacze (`p.` i `vip.easyvidplayer.com`, `my.` i
|
Oszczędność: domeny bliźniacze (`p.` i `vip.easyvidplayer.com`, `my.` i
|
||||||
`vip.player4me`) trzymają ten sam identyfikator wideo, więc pytamy raz na parę
|
`vip.player4me`) trzymają ten sam identyfikator wideo, więc pytamy raz na parę
|
||||||
|
|
@ -23,6 +21,13 @@ Oszczędność: domeny bliźniacze (`p.` i `vip.easyvidplayer.com`, `my.` i
|
||||||
Wznawianie za darmo: bierzemy tylko żywe źródła, więc kolejne odpalenie samo pomija
|
Wznawianie za darmo: bierzemy tylko żywe źródła, więc kolejne odpalenie samo pomija
|
||||||
to, co już oznaczone. Żadnego pliku stanu.
|
to, co już oznaczone. Żadnego pliku stanu.
|
||||||
|
|
||||||
|
STAN NA 2026-08-27: cała rodzina została wygaszona hurtowo dla FILMÓW (338 904 źródeł),
|
||||||
|
bo dowody były jednoznaczne: świeże identyfikatory prosto ze strony serwisu też nic nie
|
||||||
|
zwracają, 0 grających na 36 próbek w sześciu markach, a ich własny player kończy
|
||||||
|
komunikatem „Media source is not playable", który pada dopiero po wyczerpaniu WSZYSTKICH
|
||||||
|
czterech ścieżek CDN. Zostawiono 4 źródła jednego filmu, który nie miał nic innego, żeby
|
||||||
|
nic nie zniknęło z katalogu. Ten skrypt zostaje do punktowego sprawdzania i do scen.
|
||||||
|
|
||||||
Użycie (w kontenerze workera):
|
Użycie (w kontenerze workera):
|
||||||
python3 /srv/scripts/seekplayer_reap.py --limit 300 --dry-run
|
python3 /srv/scripts/seekplayer_reap.py --limit 300 --dry-run
|
||||||
python3 /srv/scripts/seekplayer_reap.py
|
python3 /srv/scripts/seekplayer_reap.py
|
||||||
|
|
@ -31,7 +36,6 @@ from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import collections
|
import collections
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -42,8 +46,7 @@ from urllib.parse import urlparse
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
|
|
||||||
from app.db import session_scope
|
from app.db import session_scope
|
||||||
from app.extractors._fetch import _DEFAULT_UA, browser_get
|
from app.extractors.hosters.seekplayer_engine import _HOST_RE
|
||||||
from app.extractors.hosters.seekplayer_engine import _HOST_RE, _decrypt
|
|
||||||
|
|
||||||
log = logging.getLogger("seekplayer-reap")
|
log = logging.getLogger("seekplayer-reap")
|
||||||
|
|
||||||
|
|
@ -52,12 +55,6 @@ _FAMILY_SQL = (
|
||||||
"easyvidplayer|embedseek|seekplayer|upns|player4me|rpmplay"
|
"easyvidplayer|embedseek|seekplayer|upns|player4me|rpmplay"
|
||||||
"|4meplayer|seekplays|ezplayer|seeks"
|
"|4meplayer|seekplays|ezplayer|seeks"
|
||||||
)
|
)
|
||||||
# Pola, w których silnik podaje adres strumienia. Nazwy wzięte z ich własnego bundla
|
|
||||||
# (`{Cloudflare: cf, Tiktok: hlsVideoTiktok, Google: hlsVideoGoogle, "In-House": source}`),
|
|
||||||
# a warunek „nie ma żadnego z nich" to dokładnie ten sam warunek, po którym ich player
|
|
||||||
# pokazuje „Video is not ready yet".
|
|
||||||
_STREAM_FIELDS = ("source", "cf", "hlsVideoGoogle", "hlsVideoTiktok", "cfNative", "p2pStream")
|
|
||||||
|
|
||||||
_CONCURRENCY = 3
|
_CONCURRENCY = 3
|
||||||
# Odstęp przed każdym pobraniem. Bez niego przy pięciu wątkach 38% odpowiedzi to było
|
# Odstęp przed każdym pobraniem. Bez niego przy pięciu wątkach 38% odpowiedzi to było
|
||||||
# HTTP 429, a limit nie jest dowodem na nic, więc takie źródło trzeba zostawić i wrócić
|
# HTTP 429, a limit nie jest dowodem na nic, więc takie źródło trzeba zostawić i wrócić
|
||||||
|
|
@ -75,38 +72,28 @@ def _brand(hostname: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def _probe(item: tuple) -> tuple:
|
def _probe(item: tuple) -> tuple:
|
||||||
"""((brand, hash), verdict, detail). Sieć i parsowanie, bez dotykania bazy."""
|
"""((brand, hash), verdict, detail). Sieć i parsowanie, bez dotykania bazy.
|
||||||
|
|
||||||
|
Deleguje do `seekplayer_engine.extract`, ŻEBY WERDYKT BYŁ TEN SAM co u resolvera,
|
||||||
|
z którego korzysta aplikacja. Wcześniej skrypt miał własną, luźniejszą regułę
|
||||||
|
(są pola = żywe), przez co uznawał za żywe źródła z adresem do usuniętego pliku,
|
||||||
|
na których CDN oddaje 502. Silnik sprawdza teraz każdą ścieżkę naprawdę.
|
||||||
|
"""
|
||||||
key, url = item
|
key, url = item
|
||||||
time.sleep(_SPACING_SEC)
|
time.sleep(_SPACING_SEC)
|
||||||
p = urlparse(url)
|
from app.extractors._models import HosterDead
|
||||||
host = f"{p.scheme}://{p.hostname}"
|
from app.extractors.hosters import seekplayer_engine
|
||||||
api = f"{host}/api/v1/video?id={p.fragment}&w=1920&h=1080&r="
|
|
||||||
headers = {"User-Agent": _DEFAULT_UA, "Accept": "*/*", "Referer": host + "/"}
|
try:
|
||||||
for attempt in (1, 2):
|
out = seekplayer_engine.extract(url, timeout=_TIMEOUT)
|
||||||
try:
|
except HosterDead as e:
|
||||||
r = browser_get(api, headers=headers, timeout=_TIMEOUT)
|
return (key, _DEAD, str(e)[-80:])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return (key, _UNKNOWN, f"{type(e).__name__}")
|
# Rate limit i błędy sieci NIE są dowodem na nic: zostawiamy nietknięte.
|
||||||
if r.status_code in (404, 410):
|
return (key, _UNKNOWN, type(e).__name__)
|
||||||
return (key, _DEAD, f"HTTP {r.status_code}")
|
if out:
|
||||||
if r.status_code == 429:
|
return (key, _ALIVE, (out[0].raw or {}).get("sciezka") or "")
|
||||||
# Rate limit nie jest dowodem na cokolwiek, więc jedna przerwa i koniec.
|
return (key, _UNKNOWN, "brak zrodla bez wyjatku")
|
||||||
if attempt == 1:
|
|
||||||
time.sleep(5)
|
|
||||||
continue
|
|
||||||
return (key, _UNKNOWN, "HTTP 429")
|
|
||||||
if r.status_code != 200 or not r.text:
|
|
||||||
return (key, _UNKNOWN, f"HTTP {r.status_code}")
|
|
||||||
try:
|
|
||||||
data = json.loads(_decrypt(r.text))
|
|
||||||
except Exception as e:
|
|
||||||
return (key, _UNKNOWN, f"dekod {type(e).__name__}")
|
|
||||||
if data.get("error"):
|
|
||||||
return (key, _DEAD, str(data["error"])[:80])
|
|
||||||
if any(data.get(k) for k in _STREAM_FIELDS):
|
|
||||||
return (key, _ALIVE, "")
|
|
||||||
return (key, _DEAD, "brak pola source (Video is not ready yet)")
|
|
||||||
return (key, _UNKNOWN, "429")
|
|
||||||
|
|
||||||
|
|
||||||
def _load_work() -> tuple[dict, dict, dict]:
|
def _load_work() -> tuple[dict, dict, dict]:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue