mirror of
https://github.com/UrloMythus/UnHided.git
synced 2026-06-10 09:10:23 +00:00
Update to the newest MFP version, including the Vixcloud PR
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -15,18 +15,18 @@ class VixCloudExtractor(BaseExtractor):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.mediaflow_endpoint = "hls_manifest_proxy"
|
self.mediaflow_endpoint = "hls_manifest_proxy"
|
||||||
|
|
||||||
async def version(self, domain: str) -> str:
|
async def version(self, site_url: str) -> str:
|
||||||
"""Get version of VixCloud Parent Site."""
|
"""Get version of VixCloud Parent Site."""
|
||||||
base_url = f"https://streamingcommunity.{domain}/richiedi-un-titolo"
|
base_url = f"{site_url}/richiedi-un-titolo"
|
||||||
response = await self._make_request(
|
response = await self._make_request(
|
||||||
base_url,
|
base_url,
|
||||||
headers={
|
headers={
|
||||||
"Referer": f"https://streamingcommunity.{domain}/",
|
"Referer": f"{site_url}/",
|
||||||
"Origin": f"https://streamingcommunity.{domain}",
|
"Origin": f"{site_url}",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
raise ExtractorError("Outdated Domain")
|
raise ExtractorError("Outdated Url")
|
||||||
# Soup the response
|
# Soup the response
|
||||||
soup = BeautifulSoup(response.text, "lxml", parse_only=SoupStrainer("div", {"id": "app"}))
|
soup = BeautifulSoup(response.text, "lxml", parse_only=SoupStrainer("div", {"id": "app"}))
|
||||||
if soup:
|
if soup:
|
||||||
@@ -39,8 +39,8 @@ class VixCloudExtractor(BaseExtractor):
|
|||||||
|
|
||||||
async def extract(self, url: str, **kwargs) -> Dict[str, Any]:
|
async def extract(self, url: str, **kwargs) -> Dict[str, Any]:
|
||||||
"""Extract Vixcloud URL."""
|
"""Extract Vixcloud URL."""
|
||||||
domain = url.split("://")[1].split("/")[0].split(".")[1]
|
site_url = url.split("/iframe")[0]
|
||||||
version = await self.version(domain)
|
version = await self.version(site_url)
|
||||||
response = await self._make_request(url, headers={"x-inertia": "true", "x-inertia-version": version})
|
response = await self._make_request(url, headers={"x-inertia": "true", "x-inertia-version": version})
|
||||||
soup = BeautifulSoup(response.text, "lxml", parse_only=SoupStrainer("iframe"))
|
soup = BeautifulSoup(response.text, "lxml", parse_only=SoupStrainer("iframe"))
|
||||||
iframe = soup.find("iframe").get("src")
|
iframe = soup.find("iframe").get("src")
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -67,30 +67,24 @@ class EncryptionMiddleware(BaseHTTPMiddleware):
|
|||||||
encrypted_token = None
|
encrypted_token = None
|
||||||
|
|
||||||
# Check for token in path
|
# Check for token in path
|
||||||
if token_marker in path and self.encryption_handler:
|
if path.startswith(token_marker) and self.encryption_handler:
|
||||||
try:
|
try:
|
||||||
# Extract token from path
|
# Extract token from the beginning of the path
|
||||||
token_start = path.find(token_marker) + len(token_marker)
|
token_start = len(token_marker)
|
||||||
token_end = path.find("/", token_start)
|
token_end = path.find("/", token_start)
|
||||||
|
|
||||||
if token_end == -1: # No trailing slash (no filename after token)
|
if token_end == -1: # No trailing slash
|
||||||
token_end = len(path)
|
encrypted_token = path[token_start:]
|
||||||
filename_part = ""
|
remaining_path = ""
|
||||||
else:
|
else:
|
||||||
# There's something after the token (likely a filename)
|
encrypted_token = path[token_start:token_end]
|
||||||
filename_part = path[token_end:]
|
remaining_path = path[token_end:]
|
||||||
|
|
||||||
# Get the encrypted token
|
# Modify the path to remove the token part
|
||||||
encrypted_token = path[token_start:token_end]
|
request.scope["path"] = remaining_path
|
||||||
|
|
||||||
# Modify the path to remove the token part but preserve the filename
|
|
||||||
original_path = path[: path.find(token_marker)]
|
|
||||||
original_path += filename_part # Add back the filename part
|
|
||||||
|
|
||||||
request.scope["path"] = original_path
|
|
||||||
|
|
||||||
# Update the raw path as well
|
# Update the raw path as well
|
||||||
request.scope["raw_path"] = original_path.encode()
|
request.scope["raw_path"] = remaining_path.encode()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error processing token in path: {str(e)}")
|
logging.error(f"Error processing token in path: {str(e)}")
|
||||||
|
|||||||
@@ -330,15 +330,25 @@ def encode_mediaflow_proxy_url(
|
|||||||
# Handle encryption if needed
|
# Handle encryption if needed
|
||||||
if encryption_handler:
|
if encryption_handler:
|
||||||
encrypted_token = encryption_handler.encrypt_data(query_params, expiration, ip)
|
encrypted_token = encryption_handler.encrypt_data(query_params, expiration, ip)
|
||||||
# Build the URL with token in path
|
|
||||||
path_parts = [base_url, f"_token_{encrypted_token}"]
|
# Parse the base URL to get its components
|
||||||
|
parsed_url = parse.urlparse(base_url)
|
||||||
|
|
||||||
|
# Insert the token at the beginning of the path
|
||||||
|
new_path = f"/_token_{encrypted_token}{parsed_url.path}"
|
||||||
|
|
||||||
|
# Reconstruct the URL with the token at the beginning of the path
|
||||||
|
url_parts = list(parsed_url)
|
||||||
|
url_parts[2] = new_path # Update the path component
|
||||||
|
|
||||||
|
# Build the URL
|
||||||
|
url = parse.urlunparse(url_parts)
|
||||||
|
|
||||||
# Add filename at the end if provided
|
# Add filename at the end if provided
|
||||||
if filename:
|
if filename:
|
||||||
path_parts.append(parse.quote(filename))
|
url = f"{url}/{parse.quote(filename)}"
|
||||||
|
|
||||||
return "/".join(path_parts)
|
|
||||||
|
|
||||||
|
return url
|
||||||
else:
|
else:
|
||||||
# No encryption, use regular query parameters
|
# No encryption, use regular query parameters
|
||||||
url = base_url
|
url = base_url
|
||||||
|
|||||||
@@ -233,8 +233,21 @@ def parse_representation(
|
|||||||
profile["audioSamplingRate"] = representation.get("@audioSamplingRate") or adaptation.get("@audioSamplingRate")
|
profile["audioSamplingRate"] = representation.get("@audioSamplingRate") or adaptation.get("@audioSamplingRate")
|
||||||
profile["channels"] = representation.get("AudioChannelConfiguration", {}).get("@value", "2")
|
profile["channels"] = representation.get("AudioChannelConfiguration", {}).get("@value", "2")
|
||||||
else:
|
else:
|
||||||
profile["width"] = int(representation["@width"])
|
# Handle video-specific attributes, making them optional with sensible defaults
|
||||||
profile["height"] = int(representation["@height"])
|
if "@width" in representation:
|
||||||
|
profile["width"] = int(representation["@width"])
|
||||||
|
elif "@width" in adaptation:
|
||||||
|
profile["width"] = int(adaptation["@width"])
|
||||||
|
else:
|
||||||
|
profile["width"] = 0 # Default if width is missing
|
||||||
|
|
||||||
|
if "@height" in representation:
|
||||||
|
profile["height"] = int(representation["@height"])
|
||||||
|
elif "@height" in adaptation:
|
||||||
|
profile["height"] = int(adaptation["@height"])
|
||||||
|
else:
|
||||||
|
profile["height"] = 0 # Default if height is missing
|
||||||
|
|
||||||
frame_rate = representation.get("@frameRate") or adaptation.get("@maxFrameRate") or "30000/1001"
|
frame_rate = representation.get("@frameRate") or adaptation.get("@maxFrameRate") or "30000/1001"
|
||||||
frame_rate = frame_rate if "/" in frame_rate else f"{frame_rate}/1"
|
frame_rate = frame_rate if "/" in frame_rate else f"{frame_rate}/1"
|
||||||
profile["frameRate"] = round(int(frame_rate.split("/")[0]) / int(frame_rate.split("/")[1]), 3)
|
profile["frameRate"] = round(int(frame_rate.split("/")[0]) / int(frame_rate.split("/")[1]), 3)
|
||||||
@@ -317,7 +330,9 @@ def parse_segment_timeline(parsed_dict: dict, item: dict, profile: dict, source:
|
|||||||
"""
|
"""
|
||||||
timelines = item["SegmentTimeline"]["S"]
|
timelines = item["SegmentTimeline"]["S"]
|
||||||
timelines = timelines if isinstance(timelines, list) else [timelines]
|
timelines = timelines if isinstance(timelines, list) else [timelines]
|
||||||
period_start = parsed_dict.get("availabilityStartTime", datetime.fromtimestamp(0, tz=timezone.utc)) + timedelta(seconds=parsed_dict.get("PeriodStart", 0))
|
period_start = parsed_dict.get("availabilityStartTime", datetime.fromtimestamp(0, tz=timezone.utc)) + timedelta(
|
||||||
|
seconds=parsed_dict.get("PeriodStart", 0)
|
||||||
|
)
|
||||||
presentation_time_offset = int(item.get("@presentationTimeOffset", 0))
|
presentation_time_offset = int(item.get("@presentationTimeOffset", 0))
|
||||||
start_number = int(item.get("@startNumber", 1))
|
start_number = int(item.get("@startNumber", 1))
|
||||||
|
|
||||||
@@ -354,13 +369,14 @@ def preprocess_timeline(
|
|||||||
for _ in range(repeat + 1):
|
for _ in range(repeat + 1):
|
||||||
segment_start_time = period_start + timedelta(seconds=(start_time - presentation_time_offset) / timescale)
|
segment_start_time = period_start + timedelta(seconds=(start_time - presentation_time_offset) / timescale)
|
||||||
segment_end_time = segment_start_time + timedelta(seconds=duration / timescale)
|
segment_end_time = segment_start_time + timedelta(seconds=duration / timescale)
|
||||||
|
presentation_time = start_time - presentation_time_offset
|
||||||
processed_data.append(
|
processed_data.append(
|
||||||
{
|
{
|
||||||
"number": start_number,
|
"number": start_number,
|
||||||
"start_time": segment_start_time,
|
"start_time": segment_start_time,
|
||||||
"end_time": segment_end_time,
|
"end_time": segment_end_time,
|
||||||
"duration": duration,
|
"duration": duration,
|
||||||
"time": start_time,
|
"time": presentation_time,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
start_time += duration
|
start_time += duration
|
||||||
@@ -475,7 +491,7 @@ def create_segment_data(segment: Dict, item: dict, profile: dict, source: str, t
|
|||||||
media = media.replace("$Bandwidth$", str(profile["bandwidth"]))
|
media = media.replace("$Bandwidth$", str(profile["bandwidth"]))
|
||||||
|
|
||||||
if "time" in segment and timescale is not None:
|
if "time" in segment and timescale is not None:
|
||||||
media = media.replace("$Time$", str(int(segment["time"] * timescale)))
|
media = media.replace("$Time$", str(int(segment["time"])))
|
||||||
|
|
||||||
if not media.startswith("http"):
|
if not media.startswith("http"):
|
||||||
media = f"{source}/{media}"
|
media = f"{source}/{media}"
|
||||||
@@ -496,16 +512,20 @@ def create_segment_data(segment: Dict, item: dict, profile: dict, source: str, t
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
elif "start_time" in segment and "duration" in segment:
|
elif "start_time" in segment and "duration" in segment:
|
||||||
duration = segment["duration"]
|
duration_seconds = segment["duration"] / timescale
|
||||||
segment_data.update(
|
segment_data.update(
|
||||||
{
|
{
|
||||||
"start_time": segment["start_time"],
|
"start_time": segment["start_time"],
|
||||||
"end_time": segment["start_time"] + timedelta(seconds=duration),
|
"end_time": segment["start_time"] + timedelta(seconds=duration_seconds),
|
||||||
"extinf": duration,
|
"extinf": duration_seconds,
|
||||||
"program_date_time": segment["start_time"].isoformat() + "Z",
|
"program_date_time": segment["start_time"].isoformat() + "Z",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
elif "duration" in segment and timescale is not None:
|
||||||
|
# Convert duration from timescale units to seconds
|
||||||
|
segment_data["extinf"] = segment["duration"] / timescale
|
||||||
elif "duration" in segment:
|
elif "duration" in segment:
|
||||||
|
# If no timescale is provided, assume duration is already in seconds
|
||||||
segment_data["extinf"] = segment["duration"]
|
segment_data["extinf"] = segment["duration"]
|
||||||
|
|
||||||
return segment_data
|
return segment_data
|
||||||
|
|||||||
Reference in New Issue
Block a user