mirror of
https://github.com/UrloMythus/UnHided.git
synced 2026-04-11 11:50:51 +00:00
update
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import logging
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from mediaflow_proxy.extractors.base import BaseExtractor, ExtractorError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -8,6 +9,11 @@ logger = logging.getLogger(__name__)
|
||||
class VavooExtractor(BaseExtractor):
|
||||
"""Vavoo URL extractor for resolving vavoo.to links.
|
||||
|
||||
Supports two URL formats:
|
||||
1. Web-VOD API links: https://vavoo.to/web-vod/api/get?link=...
|
||||
These redirect (302) to external video hosts (Doodstream, etc.)
|
||||
2. Legacy mediahubmx format (currently broken on Vavoo's end)
|
||||
|
||||
Features:
|
||||
- Uses BaseExtractor's retry/timeouts
|
||||
- Improved headers to mimic Android okhttp client
|
||||
@@ -18,6 +24,40 @@ class VavooExtractor(BaseExtractor):
|
||||
super().__init__(request_headers)
|
||||
self.mediaflow_endpoint = "proxy_stream_endpoint"
|
||||
|
||||
async def _resolve_web_vod_link(self, url: str) -> str:
|
||||
"""Resolve a web-vod API link by getting the redirect Location header."""
|
||||
import aiohttp
|
||||
|
||||
try:
|
||||
# Use aiohttp directly with allow_redirects=False to get the Location header
|
||||
timeout = aiohttp.ClientTimeout(total=10)
|
||||
async with aiohttp.ClientSession(timeout=timeout) as session:
|
||||
async with session.get(
|
||||
url,
|
||||
headers={"Accept": "application/json"},
|
||||
allow_redirects=False,
|
||||
) as resp:
|
||||
# Check for redirect
|
||||
if resp.status in (301, 302, 303, 307, 308):
|
||||
location = resp.headers.get("Location") or resp.headers.get("location")
|
||||
if location:
|
||||
logger.info(f"Vavoo web-vod redirected to: {location}")
|
||||
return location
|
||||
|
||||
# If we got a 200, the response might contain the URL
|
||||
if resp.status == 200:
|
||||
text = await resp.text()
|
||||
if text and text.startswith("http"):
|
||||
logger.info(f"Vavoo web-vod resolved to: {text.strip()}")
|
||||
return text.strip()
|
||||
|
||||
raise ExtractorError(f"Vavoo web-vod API returned unexpected status {resp.status}")
|
||||
|
||||
except ExtractorError:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise ExtractorError(f"Failed to resolve Vavoo web-vod link: {e}")
|
||||
|
||||
async def get_auth_signature(self) -> Optional[str]:
|
||||
"""Get authentication signature for Vavoo API (async)."""
|
||||
headers = {
|
||||
@@ -27,10 +67,11 @@ class VavooExtractor(BaseExtractor):
|
||||
"accept-encoding": "gzip",
|
||||
}
|
||||
import time
|
||||
|
||||
current_time = int(time.time() * 1000)
|
||||
|
||||
data = {
|
||||
"token": "tosFwQCJMS8qrW_AjLoHPQ41646J5dRNha6ZWHnijoYQQQoADQoXYSo7ki7O5-CsgN4CH0uRk6EEoJ0728ar9scCRQW3ZkbfrPfeCXW2VgopSW2FWDqPOoVYIuVPAOnXCZ5g",
|
||||
"token": "",
|
||||
"reason": "app-blur",
|
||||
"locale": "de",
|
||||
"theme": "dark",
|
||||
@@ -40,21 +81,11 @@ class VavooExtractor(BaseExtractor):
|
||||
"brand": "google",
|
||||
"model": "Pixel",
|
||||
"name": "sdk_gphone64_arm64",
|
||||
"uniqueId": "d10e5d99ab665233"
|
||||
},
|
||||
"os": {
|
||||
"name": "android",
|
||||
"version": "13"
|
||||
},
|
||||
"app": {
|
||||
"platform": "android",
|
||||
"version": "3.1.21"
|
||||
},
|
||||
"version": {
|
||||
"package": "tv.vavoo.app",
|
||||
"binary": "3.1.21",
|
||||
"js": "3.1.21"
|
||||
"uniqueId": "d10e5d99ab665233",
|
||||
},
|
||||
"os": {"name": "android", "version": "13"},
|
||||
"app": {"platform": "android", "version": "3.1.21"},
|
||||
"version": {"package": "tv.vavoo.app", "binary": "3.1.21", "js": "3.1.21"},
|
||||
},
|
||||
"appFocusTime": 0,
|
||||
"playerActive": False,
|
||||
@@ -75,11 +106,9 @@ class VavooExtractor(BaseExtractor):
|
||||
"ssVersion": 1,
|
||||
"enabled": True,
|
||||
"autoServer": True,
|
||||
"id": "de-fra"
|
||||
"id": "de-fra",
|
||||
},
|
||||
"iap": {
|
||||
"supported": False
|
||||
}
|
||||
"iap": {"supported": False},
|
||||
}
|
||||
|
||||
try:
|
||||
@@ -94,7 +123,7 @@ class VavooExtractor(BaseExtractor):
|
||||
try:
|
||||
result = resp.json()
|
||||
except Exception:
|
||||
logger.warning("Vavoo ping returned non-json response (status=%s).", resp.status_code)
|
||||
logger.warning("Vavoo ping returned non-json response (status=%s).", resp.status)
|
||||
return None
|
||||
|
||||
addon_sig = result.get("addonSig") if isinstance(result, dict) else None
|
||||
@@ -109,10 +138,48 @@ class VavooExtractor(BaseExtractor):
|
||||
return None
|
||||
|
||||
async def extract(self, url: str, **kwargs) -> Dict[str, Any]:
|
||||
"""Extract Vavoo stream URL (async)."""
|
||||
"""Extract Vavoo stream URL (async).
|
||||
|
||||
Supports:
|
||||
- Direct play URLs: https://vavoo.to/play/{id}/index.m3u8 (Live TV)
|
||||
- Web-VOD API links: https://vavoo.to/web-vod/api/get?link=...
|
||||
- Legacy mediahubmx links (may not work due to Vavoo API changes)
|
||||
"""
|
||||
if "vavoo.to" not in url:
|
||||
raise ExtractorError("Not a valid Vavoo URL")
|
||||
|
||||
# Check if this is a direct play URL (Live TV)
|
||||
# These URLs are already m3u8 streams but need auth signature
|
||||
if "/play/" in url and url.endswith(".m3u8"):
|
||||
signature = await self.get_auth_signature()
|
||||
if not signature:
|
||||
raise ExtractorError("Failed to get Vavoo authentication signature for Live TV")
|
||||
|
||||
stream_headers = {
|
||||
"user-agent": "okhttp/4.11.0",
|
||||
"referer": "https://vavoo.to/",
|
||||
"mediahubmx-signature": signature,
|
||||
}
|
||||
return {
|
||||
"destination_url": url,
|
||||
"request_headers": stream_headers,
|
||||
"mediaflow_endpoint": "hls_manifest_proxy",
|
||||
}
|
||||
|
||||
# Check if this is a web-vod API link (new format)
|
||||
if "/web-vod/api/get" in url:
|
||||
resolved_url = await self._resolve_web_vod_link(url)
|
||||
stream_headers = {
|
||||
"user-agent": self.base_headers.get("user-agent", "Mozilla/5.0"),
|
||||
"referer": "https://vavoo.to/",
|
||||
}
|
||||
return {
|
||||
"destination_url": resolved_url,
|
||||
"request_headers": stream_headers,
|
||||
"mediaflow_endpoint": self.mediaflow_endpoint,
|
||||
}
|
||||
|
||||
# Legacy mediahubmx flow
|
||||
signature = await self.get_auth_signature()
|
||||
if not signature:
|
||||
raise ExtractorError("Failed to get Vavoo authentication signature")
|
||||
@@ -139,14 +206,9 @@ class VavooExtractor(BaseExtractor):
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"accept-encoding": "gzip",
|
||||
"mediahubmx-signature": signature
|
||||
}
|
||||
data = {
|
||||
"language": "de",
|
||||
"region": "AT",
|
||||
"url": link,
|
||||
"clientVersion": "3.1.21"
|
||||
"mediahubmx-signature": signature,
|
||||
}
|
||||
data = {"language": "de", "region": "AT", "url": link, "clientVersion": "3.1.21"}
|
||||
try:
|
||||
logger.info(f"Attempting to resolve Vavoo URL: {link}")
|
||||
resp = await self._make_request(
|
||||
@@ -161,7 +223,11 @@ class VavooExtractor(BaseExtractor):
|
||||
try:
|
||||
result = resp.json()
|
||||
except Exception:
|
||||
logger.warning("Vavoo resolve returned non-json response (status=%s). Body preview: %s", resp.status_code, getattr(resp, "text", "")[:500])
|
||||
logger.warning(
|
||||
"Vavoo resolve returned non-json response (status=%s). Body preview: %s",
|
||||
resp.status,
|
||||
getattr(resp, "text", "")[:500],
|
||||
)
|
||||
return None
|
||||
|
||||
logger.debug("Vavoo API response: %s", result)
|
||||
|
||||
Reference in New Issue
Block a user