v0.1.0 — Réécriture complète de OhmStreaming
Nouvelle version réécrite de zéro : recherche multi-sources (Vostfree, French-Manga), extraction 2 niveaux, proxy vidéo intégré, streaming/téléchargement HLS, métadonnées Kitsu, bibliothèque locale, comptes JWT + administration, découverte fusionnée, indexeur Torznab (Sonarr/Prowlarr).
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
"""Extracteur Sibnet (video.sibnet.ru) — page shell/watch → mp4 direct.
|
||||
|
||||
La page embed `shell.php?videoid=N` (ou la page publique `/videoN`) contient
|
||||
une config jwplayer du type `player.src([{src: "/v/<hash>/<id>.mp4"}])`.
|
||||
`shell.php` répond 403 depuis certains réseaux : on retombe alors sur la page
|
||||
publique de la vidéo, qui expose la même config.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from app.scrapers.base import HosterExtractor, ScrapeError, VideoLink, register_hoster
|
||||
from app.scrapers.http import fetch
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_BASE = "https://video.sibnet.ru"
|
||||
_VIDEO_ID_RE = re.compile(r"(?:videoid=|/video)(\d+)")
|
||||
_MP4_PATTERNS = (
|
||||
re.compile(r'player\.src\(\[\{src:\s*"(?P<url>/v/[^"]+?\.mp4)"'),
|
||||
re.compile(r'["\'](?P<url>/v/[0-9a-f]{32}/\d+\.mp4)["\']'),
|
||||
re.compile(r'["\'](?P<url>https?://[^"\']*?/v/[^"\']+?\.mp4)["\']'),
|
||||
)
|
||||
|
||||
|
||||
@register_hoster
|
||||
class SibnetExtractor(HosterExtractor):
|
||||
name = "sibnet"
|
||||
domains = ("video.sibnet.ru",)
|
||||
|
||||
async def extract(self, embed_url: str) -> VideoLink:
|
||||
match = _VIDEO_ID_RE.search(embed_url)
|
||||
if not match:
|
||||
raise ScrapeError(f"sibnet : identifiant vidéo introuvable dans {embed_url}")
|
||||
video_id = match.group(1)
|
||||
watch_url = f"{_BASE}/video{video_id}"
|
||||
|
||||
pages: list[tuple[str, str]] = []
|
||||
try:
|
||||
pages.append(("embed", await fetch(embed_url, retries=0)))
|
||||
except ScrapeError as exc:
|
||||
logger.info(
|
||||
"sibnet : page embed %s inaccessible (%s), essai page publique", embed_url, exc
|
||||
)
|
||||
try:
|
||||
pages.append(("watch", await fetch(watch_url, retries=1)))
|
||||
except ScrapeError as exc:
|
||||
logger.error("sibnet : page publique %s inaccessible : %s", watch_url, exc)
|
||||
|
||||
for source, html in pages:
|
||||
url = self._find_mp4(html, source)
|
||||
if url:
|
||||
return VideoLink(
|
||||
url=url,
|
||||
hoster=self.name,
|
||||
headers={"Referer": watch_url},
|
||||
is_hls=False,
|
||||
)
|
||||
raise ScrapeError(f"sibnet : URL mp4 introuvable pour la vidéo {video_id}")
|
||||
|
||||
def _find_mp4(self, html: str, source: str) -> str | None:
|
||||
for pattern in _MP4_PATTERNS:
|
||||
match = pattern.search(html)
|
||||
if match:
|
||||
url = urljoin(_BASE + "/", match.group("url"))
|
||||
logger.debug("sibnet : mp4 trouvé via %s → %s", source, url)
|
||||
return url
|
||||
return None
|
||||
Reference in New Issue
Block a user