Spaces:
Running
Running
Restore commit e77a637 - main.py
Browse files
main.py
CHANGED
|
@@ -9,8 +9,6 @@ from fastapi import FastAPI, Query, Request
|
|
| 9 |
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse, Response
|
| 10 |
from urllib.parse import quote
|
| 11 |
import requests
|
| 12 |
-
import urllib3
|
| 13 |
-
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
| 14 |
from bs4 import BeautifulSoup
|
| 15 |
|
| 16 |
app = FastAPI()
|
|
@@ -133,81 +131,24 @@ def _parse_match_from_li(li, status_type="live"):
|
|
| 133 |
return {"home":home_el.get_text(strip=True),"away":away_el.get_text(strip=True),"score":score or"VS","minute":minute,"league":league,"time":time_el.get_text(strip=True) if time_el else "","event_id":event_id,"home_logo":home_logo.get("src","") if home_logo else "","away_logo":away_logo.get("src","") if away_logo else "","status":status_type}
|
| 134 |
|
| 135 |
# ===== VIDEO PROXY =====
|
| 136 |
-
def _get_proxy_headers(url):
|
| 137 |
-
"""Get appropriate headers for proxying a URL."""
|
| 138 |
-
headers = dict(HEADERS)
|
| 139 |
-
if "vtvdigital" in url:
|
| 140 |
-
headers["Referer"] = "https://vtv.vn/"
|
| 141 |
-
headers["Origin"] = "https://vtv.vn"
|
| 142 |
-
elif "fptplay" in url:
|
| 143 |
-
headers["Referer"] = "https://fptplay.vn/"
|
| 144 |
-
headers["Origin"] = "https://fptplay.vn"
|
| 145 |
-
elif "canthotv" in url:
|
| 146 |
-
headers["Referer"] = "https://canthotv.vn/"
|
| 147 |
-
elif "xemtv" in url:
|
| 148 |
-
headers["Referer"] = "https://xemtv.us/"
|
| 149 |
-
return headers
|
| 150 |
-
|
| 151 |
@app.get("/api/proxy/m3u8")
|
| 152 |
def proxy_m3u8(url: str = Query(...)):
|
| 153 |
try:
|
| 154 |
-
|
| 155 |
-
verify_ssl = "vtvdigital" not in url
|
| 156 |
-
r = requests.get(url, headers=headers, timeout=15, verify=verify_ssl)
|
| 157 |
if r.status_code != 200: return Response(status_code=502, content="upstream error")
|
| 158 |
lines = r.text.strip().split('\n'); rewritten = []
|
| 159 |
-
base_url = url.rsplit('/', 1)[0] + '/'
|
| 160 |
for line in lines:
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
line_s = re.sub(
|
| 165 |
-
r'URI="([^"]+)"',
|
| 166 |
-
lambda m: 'URI="' + ("/api/proxy/seg?url=" + quote(m.group(1), safe="")
|
| 167 |
-
if not m.group(1).startswith('http')
|
| 168 |
-
else "/api/proxy/seg?url=" + quote(m.group(1), safe="")) + '"',
|
| 169 |
-
line_s
|
| 170 |
-
)
|
| 171 |
-
rewritten.append(line_s)
|
| 172 |
-
else:
|
| 173 |
-
seg_url = line_s
|
| 174 |
-
if not seg_url.startswith('http'):
|
| 175 |
-
seg_url = base_url + seg_url
|
| 176 |
-
rewritten.append("/api/proxy/seg?url=" + quote(seg_url, safe=""))
|
| 177 |
-
return Response(content='\n'.join(rewritten).encode('utf-8'), media_type="application/vnd.apple.mpegurl", headers={"Access-Control-Allow-Origin":"*","Cache-Control":"no-cache"})
|
| 178 |
except: return Response(status_code=502, content="proxy error")
|
| 179 |
|
| 180 |
@app.get("/api/proxy/seg")
|
| 181 |
def proxy_segment(url: str = Query(...)):
|
| 182 |
try:
|
| 183 |
-
|
| 184 |
-
verify_ssl = "vtvdigital" not in url
|
| 185 |
-
r = requests.get(url, headers=headers, timeout=30, verify=verify_ssl)
|
| 186 |
if r.status_code != 200: return Response(status_code=502, content="upstream error")
|
| 187 |
data = r.content
|
| 188 |
-
# Handle sub-playlist
|
| 189 |
-
if b"#EXTM3U" in data[:500] or ".m3u8" in url:
|
| 190 |
-
lines = data.decode("utf-8", errors="replace").split('\n')
|
| 191 |
-
rewritten = []
|
| 192 |
-
base_url = url.rsplit('/', 1)[0] + '/'
|
| 193 |
-
for line in lines:
|
| 194 |
-
line_s = line.strip()
|
| 195 |
-
if not line_s or line_s.startswith('#'):
|
| 196 |
-
if 'URI=' in line_s:
|
| 197 |
-
line_s = re.sub(
|
| 198 |
-
r'URI="([^"]+)"',
|
| 199 |
-
lambda m: 'URI="' + ("/api/proxy/seg?url=" + quote(m.group(1), safe="")
|
| 200 |
-
if not m.group(1).startswith('http')
|
| 201 |
-
else "/api/proxy/seg?url=" + quote(m.group(1), safe="")) + '"',
|
| 202 |
-
line_s
|
| 203 |
-
)
|
| 204 |
-
rewritten.append(line_s)
|
| 205 |
-
else:
|
| 206 |
-
seg_url = line_s
|
| 207 |
-
if not seg_url.startswith('http'):
|
| 208 |
-
seg_url = base_url + seg_url
|
| 209 |
-
rewritten.append("/api/proxy/seg?url=" + quote(seg_url, safe=""))
|
| 210 |
-
return Response(content='\n'.join(rewritten).encode("utf-8"), media_type="application/vnd.apple.mpegurl", headers={"Access-Control-Allow-Origin": "*", "Cache-Control": "no-cache"})
|
| 211 |
if len(data) > 188 and data[0:4] == b'\x89PNG' and data[188] == 0x47: data = data[188:]
|
| 212 |
return Response(content=data, media_type="video/mp2t", headers={"Access-Control-Allow-Origin":"*","Cache-Control":"public, max-age=3600"})
|
| 213 |
except: return Response(status_code=502, content="proxy error")
|
|
@@ -215,7 +156,7 @@ def proxy_segment(url: str = Query(...)):
|
|
| 215 |
@app.get("/api/proxy/video")
|
| 216 |
def proxy_video(url: str = Query(...), request: Request = None):
|
| 217 |
try:
|
| 218 |
-
req_headers =
|
| 219 |
if request and request.headers.get("range"): req_headers["Range"] = request.headers["range"]
|
| 220 |
r = requests.get(url, headers=req_headers, timeout=30, stream=True)
|
| 221 |
resp_headers = {"Access-Control-Allow-Origin":"*","Accept-Ranges":"bytes","Content-Type":r.headers.get("Content-Type","video/mp4")}
|
|
|
|
| 9 |
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse, Response
|
| 10 |
from urllib.parse import quote
|
| 11 |
import requests
|
|
|
|
|
|
|
| 12 |
from bs4 import BeautifulSoup
|
| 13 |
|
| 14 |
app = FastAPI()
|
|
|
|
| 131 |
return {"home":home_el.get_text(strip=True),"away":away_el.get_text(strip=True),"score":score or"VS","minute":minute,"league":league,"time":time_el.get_text(strip=True) if time_el else "","event_id":event_id,"home_logo":home_logo.get("src","") if home_logo else "","away_logo":away_logo.get("src","") if away_logo else "","status":status_type}
|
| 132 |
|
| 133 |
# ===== VIDEO PROXY =====
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
@app.get("/api/proxy/m3u8")
|
| 135 |
def proxy_m3u8(url: str = Query(...)):
|
| 136 |
try:
|
| 137 |
+
r = requests.get(url, headers=HEADERS, timeout=15)
|
|
|
|
|
|
|
| 138 |
if r.status_code != 200: return Response(status_code=502, content="upstream error")
|
| 139 |
lines = r.text.strip().split('\n'); rewritten = []
|
|
|
|
| 140 |
for line in lines:
|
| 141 |
+
if line.startswith('#') or not line.strip(): rewritten.append(line)
|
| 142 |
+
else: rewritten.append("/api/proxy/seg?url=" + quote(line.strip(), safe=""))
|
| 143 |
+
return Response(content='\n'.join(rewritten).encode('utf-8'), media_type="application/vnd.apple.mpegurl", headers={"Access-Control-Allow-Origin":"*","Cache-Control":"public, max-age=300"})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
except: return Response(status_code=502, content="proxy error")
|
| 145 |
|
| 146 |
@app.get("/api/proxy/seg")
|
| 147 |
def proxy_segment(url: str = Query(...)):
|
| 148 |
try:
|
| 149 |
+
r = requests.get(url, headers=HEADERS, timeout=30)
|
|
|
|
|
|
|
| 150 |
if r.status_code != 200: return Response(status_code=502, content="upstream error")
|
| 151 |
data = r.content
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
if len(data) > 188 and data[0:4] == b'\x89PNG' and data[188] == 0x47: data = data[188:]
|
| 153 |
return Response(content=data, media_type="video/mp2t", headers={"Access-Control-Allow-Origin":"*","Cache-Control":"public, max-age=3600"})
|
| 154 |
except: return Response(status_code=502, content="proxy error")
|
|
|
|
| 156 |
@app.get("/api/proxy/video")
|
| 157 |
def proxy_video(url: str = Query(...), request: Request = None):
|
| 158 |
try:
|
| 159 |
+
req_headers = dict(HEADERS)
|
| 160 |
if request and request.headers.get("range"): req_headers["Range"] = request.headers["range"]
|
| 161 |
r = requests.get(url, headers=req_headers, timeout=30, stream=True)
|
| 162 |
resp_headers = {"Access-Control-Allow-Origin":"*","Accept-Ranges":"bytes","Content-Type":r.headers.get("Content-Type","video/mp4")}
|