Spaces:
Running
Running
Upload vtv_api.py
Browse files- vtv_api.py +7 -39
vtv_api.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# VTV Stream — SV2 iframe
|
| 2 |
import re, time, threading, json, requests
|
| 3 |
from fastapi import APIRouter, Query
|
| 4 |
from fastapi.responses import JSONResponse, Response, StreamingResponse
|
|
@@ -18,8 +18,8 @@ HARDCODED_URLS = {"vtv6": "https://live.fptplay53.net/live/media/v6abr/live247-h
|
|
| 18 |
CHANNEL_URLS = {k: (HARDCODED_URLS[k] if k in HARDCODED_URLS else None) for k in ["vtv1","vtv2","vtv3","vtv4","vtv5","vtv6","vtv7","vtv8","vtv9","vtv10"]}
|
| 19 |
CHANNEL_NAMES = {"vtv1":"VTV1","vtv2":"VTV2","vtv3":"VTV3","vtv4":"VTV4","vtv5":"VTV5","vtv6":"VTV6","vtv7":"VTV7","vtv8":"VTV8","vtv9":"VTV9","vtv10":"VTV10","vtvprime":"VTVPrime"}
|
| 20 |
|
| 21 |
-
# SV2 iframe URLs —
|
| 22 |
-
|
| 23 |
"vtv1": "https://sv2.xemtivitop.com/live/hot/vtv1.php",
|
| 24 |
"vtv2": "https://sv2.xemtivitop.com/live/hot/vtv2.php",
|
| 25 |
"vtv3": "https://sv2.xemtivitop.com/live/hot/vtv3.php",
|
|
@@ -88,38 +88,6 @@ def get_channel_url(channel_id):
|
|
| 88 |
_fetch_m3u()
|
| 89 |
with _channel_urls_lock: return CHANNEL_URLS.get(channel_id)
|
| 90 |
|
| 91 |
-
# ===== SV2 PROXY (IFRAME-FRIENDLY) =====
|
| 92 |
-
@router.get("/api/proxy/sv2/iframe")
|
| 93 |
-
def proxy_sv2_iframe(url: str = Query(...)):
|
| 94 |
-
"""Proxy SV2 iframe — rewrite relative URLs, cho phép iframe"""
|
| 95 |
-
try:
|
| 96 |
-
s = requests.Session()
|
| 97 |
-
try: s.get("https://sv2.xemtivitop.com/", headers=UA, timeout=5, verify=False)
|
| 98 |
-
except: pass
|
| 99 |
-
r = s.get(url, headers={**UA, "Referer": "https://sv2.xemtivitop.com/"}, timeout=15, verify=False)
|
| 100 |
-
if r.status_code != 200:
|
| 101 |
-
return Response(content=f"<html><body><p>sv2 error: {r.status_code}</p></body></html>",
|
| 102 |
-
media_type="text/html", headers={"Access-Control-Allow-Origin": "*"})
|
| 103 |
-
html = r.text
|
| 104 |
-
# Rewrite relative URLs
|
| 105 |
-
html = html.replace('src="/', 'src="https://sv2.xemtivitop.com/')
|
| 106 |
-
html = html.replace("src='/", "src='https://sv2.xemtivitop.com/")
|
| 107 |
-
html = html.replace('href="/', 'href="https://sv2.xemtivitop.com/')
|
| 108 |
-
html = html.replace("href='/", "href='https://sv2.xemtivitop.com/")
|
| 109 |
-
# Force fullscreen, hide margins
|
| 110 |
-
html = html.replace('</head>', '''
|
| 111 |
-
<style>
|
| 112 |
-
*{margin:0;padding:0}
|
| 113 |
-
body{background:#000;overflow:hidden;margin:0;padding:0}
|
| 114 |
-
iframe,video,.video-js,#player,.player{width:100%!important;height:100%!important;max-width:100%!important}
|
| 115 |
-
</style>
|
| 116 |
-
</head>''')
|
| 117 |
-
return Response(content=html.encode('utf-8'), media_type="text/html",
|
| 118 |
-
headers={"Access-Control-Allow-Origin": "*", "X-Frame-Options": "ALLOWALL", "Content-Security-Policy": "frame-ancestors *"})
|
| 119 |
-
except Exception as e:
|
| 120 |
-
return Response(content=f"<html><body><p>sv2 proxy error: {str(e)[:100]}</p></body></html>",
|
| 121 |
-
media_type="text/html", headers={"Access-Control-Allow-Origin": "*"})
|
| 122 |
-
|
| 123 |
# ===================== API ENDPOINTS =====================
|
| 124 |
|
| 125 |
@router.get("/api/vtv/streams")
|
|
@@ -128,7 +96,7 @@ def api_vtv_streams():
|
|
| 128 |
result = {}
|
| 129 |
for ch_id in CHANNEL_NAMES:
|
| 130 |
stream_url = urls.get(ch_id)
|
| 131 |
-
sv2_url =
|
| 132 |
is_flv = stream_url and ".flv" in stream_url
|
| 133 |
result[ch_id] = {
|
| 134 |
"name": CHANNEL_NAMES[ch_id],
|
|
@@ -136,7 +104,7 @@ def api_vtv_streams():
|
|
| 136 |
"proxy_url": f"/api/proxy/flv?url={quote(stream_url, safe='')}" if stream_url and is_flv else "",
|
| 137 |
"proxy_url_hls": f"/api/proxy/stream?url={quote(stream_url, safe='')}" if stream_url and not is_flv else "",
|
| 138 |
"is_flv": is_flv,
|
| 139 |
-
"
|
| 140 |
"status": "ok"
|
| 141 |
}
|
| 142 |
return JSONResponse(result)
|
|
@@ -146,7 +114,7 @@ def api_vtv_stream(channel_id: str):
|
|
| 146 |
channel_id = channel_id.lower().strip()
|
| 147 |
if channel_id not in CHANNEL_NAMES: return JSONResponse({"error":"not found"}, status_code=404)
|
| 148 |
stream_url = get_channel_url(channel_id)
|
| 149 |
-
sv2_url =
|
| 150 |
is_flv = stream_url and ".flv" in stream_url
|
| 151 |
return JSONResponse({
|
| 152 |
"name": CHANNEL_NAMES[channel_id],
|
|
@@ -154,7 +122,7 @@ def api_vtv_stream(channel_id: str):
|
|
| 154 |
"proxy_url": f"/api/proxy/flv?url={quote(stream_url, safe='')}" if stream_url and is_flv else "",
|
| 155 |
"proxy_url_hls": f"/api/proxy/stream?url={quote(stream_url, safe='')}" if stream_url and not is_flv else "",
|
| 156 |
"is_flv": is_flv,
|
| 157 |
-
"
|
| 158 |
"status": "ok"
|
| 159 |
})
|
| 160 |
|
|
|
|
| 1 |
+
# VTV Stream — Direct SV2 iframe URLs + M3U fallback + EPG
|
| 2 |
import re, time, threading, json, requests
|
| 3 |
from fastapi import APIRouter, Query
|
| 4 |
from fastapi.responses import JSONResponse, Response, StreamingResponse
|
|
|
|
| 18 |
CHANNEL_URLS = {k: (HARDCODED_URLS[k] if k in HARDCODED_URLS else None) for k in ["vtv1","vtv2","vtv3","vtv4","vtv5","vtv6","vtv7","vtv8","vtv9","vtv10"]}
|
| 19 |
CHANNEL_NAMES = {"vtv1":"VTV1","vtv2":"VTV2","vtv3":"VTV3","vtv4":"VTV4","vtv5":"VTV5","vtv6":"VTV6","vtv7":"VTV7","vtv8":"VTV8","vtv9":"VTV9","vtv10":"VTV10","vtvprime":"VTVPrime"}
|
| 20 |
|
| 21 |
+
# SV2 direct iframe URLs — player thật, hỗ trợ mobile
|
| 22 |
+
SV2_IFRAME_URLS = {
|
| 23 |
"vtv1": "https://sv2.xemtivitop.com/live/hot/vtv1.php",
|
| 24 |
"vtv2": "https://sv2.xemtivitop.com/live/hot/vtv2.php",
|
| 25 |
"vtv3": "https://sv2.xemtivitop.com/live/hot/vtv3.php",
|
|
|
|
| 88 |
_fetch_m3u()
|
| 89 |
with _channel_urls_lock: return CHANNEL_URLS.get(channel_id)
|
| 90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
# ===================== API ENDPOINTS =====================
|
| 92 |
|
| 93 |
@router.get("/api/vtv/streams")
|
|
|
|
| 96 |
result = {}
|
| 97 |
for ch_id in CHANNEL_NAMES:
|
| 98 |
stream_url = urls.get(ch_id)
|
| 99 |
+
sv2_url = SV2_IFRAME_URLS.get(ch_id)
|
| 100 |
is_flv = stream_url and ".flv" in stream_url
|
| 101 |
result[ch_id] = {
|
| 102 |
"name": CHANNEL_NAMES[ch_id],
|
|
|
|
| 104 |
"proxy_url": f"/api/proxy/flv?url={quote(stream_url, safe='')}" if stream_url and is_flv else "",
|
| 105 |
"proxy_url_hls": f"/api/proxy/stream?url={quote(stream_url, safe='')}" if stream_url and not is_flv else "",
|
| 106 |
"is_flv": is_flv,
|
| 107 |
+
"iframe_url": sv2_url,
|
| 108 |
"status": "ok"
|
| 109 |
}
|
| 110 |
return JSONResponse(result)
|
|
|
|
| 114 |
channel_id = channel_id.lower().strip()
|
| 115 |
if channel_id not in CHANNEL_NAMES: return JSONResponse({"error":"not found"}, status_code=404)
|
| 116 |
stream_url = get_channel_url(channel_id)
|
| 117 |
+
sv2_url = SV2_IFRAME_URLS.get(channel_id)
|
| 118 |
is_flv = stream_url and ".flv" in stream_url
|
| 119 |
return JSONResponse({
|
| 120 |
"name": CHANNEL_NAMES[channel_id],
|
|
|
|
| 122 |
"proxy_url": f"/api/proxy/flv?url={quote(stream_url, safe='')}" if stream_url and is_flv else "",
|
| 123 |
"proxy_url_hls": f"/api/proxy/stream?url={quote(stream_url, safe='')}" if stream_url and not is_flv else "",
|
| 124 |
"is_flv": is_flv,
|
| 125 |
+
"iframe_url": sv2_url,
|
| 126 |
"status": "ok"
|
| 127 |
})
|
| 128 |
|