Spaces:
Paused
Paused
Merge pull request #10 from UrloMythus/main
Browse filesAdd support for extracting clean links from IP-Locked / Cloudfare-Blocked Players
mediaflow_proxy/extractors/doodstream.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import httpx
|
| 2 |
+
import time
|
| 3 |
+
import re
|
| 4 |
+
from mediaflow_proxy.configs import settings
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
async def doodstream_url(d: str, use_request_proxy: bool):
|
| 8 |
+
async with httpx.AsyncClient(proxy=settings.proxy_url if use_request_proxy else None) as client:
|
| 9 |
+
headers = {
|
| 10 |
+
"Range": "bytes=0-",
|
| 11 |
+
"Referer": "https://d000d.com/",
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
response = await client.get(d, follow_redirects=True)
|
| 15 |
+
if response.status_code == 200:
|
| 16 |
+
# Get unique timestamp for the request
|
| 17 |
+
real_time = str(int(time.time()))
|
| 18 |
+
pattern = r"(\/pass_md5\/.*?)'.*(\?token=.*?expiry=)"
|
| 19 |
+
match = re.search(pattern, response.text, re.DOTALL)
|
| 20 |
+
if match:
|
| 21 |
+
url = f"https://d000d.com{match[1]}"
|
| 22 |
+
rebobo = await client.get(url, headers=headers, follow_redirects=True)
|
| 23 |
+
final_url = f"{rebobo.text}123456789{match[2]}{real_time}"
|
| 24 |
+
doodstream_dict = {"Referer": "https://d000d.com/"}
|
| 25 |
+
return final_url, doodstream_dict
|
mediaflow_proxy/extractors/mixdrop.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import httpx
|
| 2 |
+
import re
|
| 3 |
+
import string
|
| 4 |
+
from mediaflow_proxy.configs import settings
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
async def mixdrop_url(d: str, use_request_proxy: bool):
|
| 8 |
+
headers = {
|
| 9 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.10; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
|
| 10 |
+
"Accept-Language": "en-US,en;q=0.5",
|
| 11 |
+
}
|
| 12 |
+
async with httpx.AsyncClient(proxy=settings.proxy_url if use_request_proxy else None) as client:
|
| 13 |
+
response = await client.get(d, headers=headers, follow_redirects=True, timeout=30)
|
| 14 |
+
[s1, s2] = re.search(r"\}\('(.+)',.+,'(.+)'\.split", response.text).group(1, 2)
|
| 15 |
+
schema = s1.split(";")[2][5:-1]
|
| 16 |
+
terms = s2.split("|")
|
| 17 |
+
charset = string.digits + string.ascii_letters
|
| 18 |
+
d = dict()
|
| 19 |
+
for i in range(len(terms)):
|
| 20 |
+
d[charset[i]] = terms[i] or charset[i]
|
| 21 |
+
final_url = "https:"
|
| 22 |
+
for c in schema:
|
| 23 |
+
final_url += d[c] if c in d else c
|
| 24 |
+
headers_dict = {
|
| 25 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.10; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
|
| 26 |
+
}
|
| 27 |
+
return final_url, headers_dict
|
mediaflow_proxy/extractors/uqload.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import httpx
|
| 2 |
+
import re
|
| 3 |
+
from mediaflow_proxy.configs import settings
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
async def uqload_url(d: str, use_request_proxy: bool):
|
| 7 |
+
async with httpx.AsyncClient(proxy=settings.proxy_url if use_request_proxy else None) as client:
|
| 8 |
+
|
| 9 |
+
response = await client.get(d, follow_redirects=True)
|
| 10 |
+
video_url_match = re.search(r'sources: \["(.*?)"\]', response.text)
|
| 11 |
+
if video_url_match:
|
| 12 |
+
final_url = video_url_match.group(1)
|
| 13 |
+
uqload_dict = {"Referer": "https://uqload.to/"}
|
| 14 |
+
return final_url, uqload_dict
|
mediaflow_proxy/extractors_routes.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, Query
|
| 2 |
+
from fastapi.responses import JSONResponse, RedirectResponse
|
| 3 |
+
from .extractors.doodstream import doodstream_url
|
| 4 |
+
from .extractors.uqload import uqload_url
|
| 5 |
+
from .extractors.mixdrop import mixdrop_url
|
| 6 |
+
from mediaflow_proxy.configs import settings
|
| 7 |
+
|
| 8 |
+
extractor_router = APIRouter()
|
| 9 |
+
host_map = {"Doodstream": doodstream_url, "Mixdrop": mixdrop_url, "Uqload": uqload_url}
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
@extractor_router.get("/extractor")
|
| 13 |
+
async def doodstream_extractor(
|
| 14 |
+
d: str = Query(..., description="Extract Clean Link from various Hosts"),
|
| 15 |
+
use_request_proxy: bool = Query(False, description="Whether to use the MediaFlow proxy configuration."),
|
| 16 |
+
host: str = Query(
|
| 17 |
+
..., description='From which Host the URL comes from, here avaiable ones: "Doodstream","Mixdrop","Uqload"'
|
| 18 |
+
),
|
| 19 |
+
redirect_stream: bool = Query(
|
| 20 |
+
False,
|
| 21 |
+
description="If enabled the response will be redirected to stream endpoint automatically and the stream will be proxied",
|
| 22 |
+
),
|
| 23 |
+
):
|
| 24 |
+
"""
|
| 25 |
+
Extract a clean link from DoodStream,Mixdrop,Uqload
|
| 26 |
+
|
| 27 |
+
Args: request (Request): The incoming HTTP request
|
| 28 |
+
|
| 29 |
+
Returns: The clean link (url) and the headers needed to access the url
|
| 30 |
+
|
| 31 |
+
N.B. You can't use a rotating proxy if type is set to "Doodstream"
|
| 32 |
+
"""
|
| 33 |
+
try:
|
| 34 |
+
final_url, headers_dict = await host_map[host](d, use_request_proxy)
|
| 35 |
+
except Exception as e:
|
| 36 |
+
return JSONResponse(content={"error": str(e)})
|
| 37 |
+
if redirect_stream == True:
|
| 38 |
+
formatted_headers = format_headers(headers_dict)
|
| 39 |
+
redirected_stream = f"/proxy/stream?api_password={settings.api_password}&d={final_url}&{formatted_headers}"
|
| 40 |
+
return RedirectResponse(url=redirected_stream)
|
| 41 |
+
elif redirect_stream == False:
|
| 42 |
+
return JSONResponse(content={"url": final_url, "headers": headers_dict})
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def format_headers(headers):
|
| 46 |
+
"""
|
| 47 |
+
Format the headers dictionary into a query string format with 'h_' prefix.
|
| 48 |
+
|
| 49 |
+
Args:
|
| 50 |
+
- headers: A dictionary of headers.
|
| 51 |
+
|
| 52 |
+
Returns:
|
| 53 |
+
- A query string formatted string of headers.
|
| 54 |
+
"""
|
| 55 |
+
return "&".join(f"h_{key}={value}" for key, value in headers.items())
|
mediaflow_proxy/main.py
CHANGED
|
@@ -10,6 +10,7 @@ from starlette.staticfiles import StaticFiles
|
|
| 10 |
|
| 11 |
from mediaflow_proxy.configs import settings
|
| 12 |
from mediaflow_proxy.routes import proxy_router
|
|
|
|
| 13 |
from mediaflow_proxy.schemas import GenerateUrlRequest
|
| 14 |
from mediaflow_proxy.utils.crypto_utils import EncryptionHandler, EncryptionMiddleware
|
| 15 |
from mediaflow_proxy.utils.rd_speedtest import run_speedtest, prune_task, results
|
|
@@ -96,6 +97,8 @@ async def generate_encrypted_or_encoded_url(request: GenerateUrlRequest):
|
|
| 96 |
|
| 97 |
|
| 98 |
app.include_router(proxy_router, prefix="/proxy", tags=["proxy"], dependencies=[Depends(verify_api_key)])
|
|
|
|
|
|
|
| 99 |
|
| 100 |
static_path = resources.files("mediaflow_proxy").joinpath("static")
|
| 101 |
app.mount("/", StaticFiles(directory=str(static_path), html=True), name="static")
|
|
|
|
| 10 |
|
| 11 |
from mediaflow_proxy.configs import settings
|
| 12 |
from mediaflow_proxy.routes import proxy_router
|
| 13 |
+
from mediaflow_proxy.extractors_routes import extractor_router
|
| 14 |
from mediaflow_proxy.schemas import GenerateUrlRequest
|
| 15 |
from mediaflow_proxy.utils.crypto_utils import EncryptionHandler, EncryptionMiddleware
|
| 16 |
from mediaflow_proxy.utils.rd_speedtest import run_speedtest, prune_task, results
|
|
|
|
| 97 |
|
| 98 |
|
| 99 |
app.include_router(proxy_router, prefix="/proxy", tags=["proxy"], dependencies=[Depends(verify_api_key)])
|
| 100 |
+
app.include_router(extractor_router, tags=["extractors"], dependencies=[Depends(verify_api_key)])
|
| 101 |
+
|
| 102 |
|
| 103 |
static_path = resources.files("mediaflow_proxy").joinpath("static")
|
| 104 |
app.mount("/", StaticFiles(directory=str(static_path), html=True), name="static")
|