Machinima i animacje SFM/Blender. Kanon nie istnieje tak samo jak przy hentai i rule34video, wiec kazda pozycja jest orphanem i to poprawne. Najzdrowsza jednostka tresci calego wertykalu 3D: mediana 289 s, ZERO pozycji ponizej minuty, 18/25 powyzej progu potoku. Dla porownania rule34video ma mediane 68 s i traci ~70% katalogu. Playback najprostszy z serii: jawne <source> w trzech jakosciach, bez tokenu, bez AJAX-a, bez CF. Zweryfikowane z VPS: 206, ftypisom, 140 MB, dziala bez Referera, wiec mobile_direct_ok i zero pracy po stronie apki (inaczej niz rule34video, gdzie token byl IP-bound). Szosty niezalezny host wertykalu (videos.naughtymachinima.com), zadna z szesciu stron nie re-hostuje pozostalych. Odsiewamy pusty <source src=""> (placeholder playera) i preroll /images/preroll/NMintro.mp4, ktory pasuje do naiwnego \.mp4. Bramka dlugosci zestrojona z min_ingest_duration_sec, jak przy rule34video. Pilot 3 strony: seen 48, new 48, skipped 0, errors 0.
67 lines
2.5 KiB
Python
67 lines
2.5 KiB
Python
"""naughtymachinima.com — jawne `<source>` bez tokenu. Dodany 2026-08-13.
|
|
|
|
Najprostszy playback z całego wertykału animacji. Trzy rendycje wprost w HTML, bez
|
|
AJAX-a, bez tokenu, bez Cloudflare:
|
|
|
|
<source src="https://videos.naughtymachinima.com/media/videos/h264/121144_1080p.mp4"
|
|
default type='video/mp4' label='1080p' res='1080'/>
|
|
|
|
Kontrast z [[rule34video]] (drugie źródło 3D): tam też był KVS z gotowymi URL-ami, ale
|
|
`v-acctoken` był ZWIĄZANY Z IP i telefon musiał resolwować sam. Tutaj URL nie ma żadnego
|
|
tokenu, więc nie ma czego wiązać.
|
|
|
|
Zweryfikowane z VPS-a: 206 na Range, `ftypisom` w pierwszym KB (faststart), 140 MB,
|
|
działa BEZ Referera. Stąd `mobile_direct_ok`.
|
|
|
|
**Dwie pułapki, obie odsiewane jawnie:**
|
|
|
|
1. **Pusty `<source src="">`** na końcu listy (placeholder playera). Bez sprawdzenia
|
|
pustego src trafiłby na listę jako link do niczego.
|
|
2. **`/images/preroll/NMintro.mp4`** to intro serwisu, nie treść. Leży w tym samym HTML
|
|
i pasuje do naiwnego `\\.mp4`, a jako jedyny mp4 na `www.` zamiast `videos.`.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import re
|
|
|
|
from app.extractors._fetch import fetch_tube_html
|
|
from app.extractors._models import StreamSource
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
_BASE = "https://www.naughtymachinima.com"
|
|
#: Tylko host plików, co samo w sobie odcina preroll z `www.naughtymachinima.com`.
|
|
_SOURCE_RE = re.compile(
|
|
r"<source[^>]+src=[\"'](https?://videos\.naughtymachinima\.com/[^\"']+\.mp4)[\"'][^>]*?"
|
|
r"label=[\"']([^\"']{1,10})[\"']",
|
|
re.IGNORECASE,
|
|
)
|
|
_QUALITY_RANK = {"1080p": 0, "720p": 1, "480p": 2, "360p": 3}
|
|
|
|
|
|
def extract(page_url: str, *, timeout: float = 60.0) -> list[StreamSource] | None:
|
|
html_text = fetch_tube_html(page_url, timeout=timeout)
|
|
|
|
out: list[StreamSource] = []
|
|
seen: set[str] = set()
|
|
for link, label in _SOURCE_RE.findall(html_text):
|
|
if not link or link in seen or "/preroll/" in link:
|
|
continue
|
|
seen.add(link)
|
|
out.append(
|
|
StreamSource(
|
|
link=link,
|
|
type="mp4",
|
|
quality=label.strip() or None,
|
|
referer=_BASE + "/",
|
|
# Zweryfikowane: 206 bez Referera, bez tokenu, faststart.
|
|
raw={"mobile_direct_ok": True},
|
|
)
|
|
)
|
|
if not out:
|
|
log.info("naughtymachinima: brak <source> mp4 na %s", page_url)
|
|
return None
|
|
|
|
out.sort(key=lambda s: _QUALITY_RANK.get((s.quality or "").lower(), 99))
|
|
return out
|