bep40 commited on
Commit
ca43247
·
verified ·
1 Parent(s): 92e3da9

Upload vtv_api.py

Browse files
Files changed (1) hide show
  1. vtv_api.py +34 -48
vtv_api.py CHANGED
@@ -1,4 +1,4 @@
1
- # VTV Stream — VTVGo iframe (player thật) + SV2 fallback + M3U + EPG
2
  import re, time, threading, json, requests
3
  from fastapi import APIRouter, Query
4
  from fastapi.responses import JSONResponse, Response, StreamingResponse
@@ -18,18 +18,18 @@ 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
- # VTVGo channel page URLs — player thật, iframe-friendly (no X-Frame-Options)
22
- VTVGO_URLS = {
23
- "vtv1": "https://vtvgo.vn/channel/vtv1-1,1.html",
24
- "vtv2": "https://vtvgo.vn/channel/vtv2-2,2.html",
25
- "vtv3": "https://vtvgo.vn/channel/vtv3-3,3.html",
26
- "vtv4": "https://vtvgo.vn/channel/vtv4htc-4,4.html",
27
- "vtv5": "https://vtvgo.vn/channel/vtv5-12,12.html",
28
- "vtv6": "https://vtvgo.vn/channel/vtv6-1,13.html",
29
- "vtv7": "https://vtvgo.vn/channel/vtv7-7,7.html",
30
- "vtv8": "https://vtvgo.vn/channel/vtv8-8,8.html",
31
- "vtv9": "https://vtvgo.vn/channel/vtv9-9,9.html",
32
- "vtv10": "https://vtvgo.vn/channel/vtvcantho-10,10.html",
33
  }
34
 
35
  M3U_URLS = [
@@ -88,50 +88,36 @@ def get_channel_url(channel_id):
88
  _fetch_m3u()
89
  with _channel_urls_lock: return CHANNEL_URLS.get(channel_id)
90
 
91
- # ===== VTVGo PROXY (IFRAME-FRIENDLY) =====
92
- @router.get("/api/proxy/vtvgo")
93
- def proxy_vtvgo(url: str = Query(...)):
94
- """Proxy VTVGo channelplayer thật, không X-Frame-Options, vừa khung"""
95
  try:
96
- r = requests.get(url, headers={
97
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
98
- "Accept-Language": "vi-VN,vi;q=0.9",
99
- "Referer": "https://vtvgo.vn/",
100
- }, timeout=15)
101
  if r.status_code != 200:
102
- return Response(content=f"<html><body><p>VTVgo error: {r.status_code}</p></body></html>",
103
  media_type="text/html", headers={"Access-Control-Allow-Origin": "*"})
104
  html = r.text
105
  # Rewrite relative URLs
106
- html = html.replace('src="/', 'src="https://vtvgo.vn/')
107
- html = html.replace("src='/", "src='https://vtvgo.vn/")
108
- html = html.replace('href="/', 'href="https://vtvgo.vn/')
109
- html = html.replace("href='/", "href='https://vtvgo.vn/")
110
- # Remove any X-Frame-Options meta
111
- html = re.sub(r'<meta[^>]*http-equiv=["\']X-Frame-Options["\'][^>]*>', '', html, flags=re.IGNORECASE)
112
- # Inject CSS: force player fullscreen, hide chrome
113
  html = html.replace('</head>', '''
114
  <style>
115
- *{margin:0;padding:0;box-sizing:border-box}
116
  body{background:#000;overflow:hidden;margin:0;padding:0}
117
- .app,.app-wrapper,.player-wrapper,.video-player,.video-js,.channel-player,.channel-wrapper,
118
- #app,#root,.player,.container,.streaming-dimensions,#videojs,#player,#my-player,
119
- .player-container,.video-container,.channel-container,.live-player,
120
- [class*="player"],[class*="video"],[class*="stream"],[class*="channel"],
121
- video,iframe,object,embed{
122
- width:100%!important;height:100%!important;max-width:100%!important;min-height:0!important;
123
- position:relative;
124
- }
125
- .app,.app-wrapper,#app,#root{position:fixed;inset:0;width:100vw;height:100vh}
126
- header,nav,footer,.header,.footer,.nav,.sidebar,.menu,.top-bar,.bottom-bar,
127
- [class*="header"],[class*="nav"],[class*="footer"],[class*="sidebar"],[class*="menu"],
128
- [class*="top"],[class*="bottom"],[data-testid*="header"],[data-testid*="footer"]{display:none!important}
129
  </style>
130
  </head>''')
131
  return Response(content=html.encode('utf-8'), media_type="text/html",
132
  headers={"Access-Control-Allow-Origin": "*", "X-Frame-Options": "ALLOWALL", "Content-Security-Policy": "frame-ancestors *"})
133
  except Exception as e:
134
- return Response(content=f"<html><body><p>vtvgo proxy error: {str(e)[:100]}</p></body></html>",
135
  media_type="text/html", headers={"Access-Control-Allow-Origin": "*"})
136
 
137
  # ===================== API ENDPOINTS =====================
@@ -142,7 +128,7 @@ def api_vtv_streams():
142
  result = {}
143
  for ch_id in CHANNEL_NAMES:
144
  stream_url = urls.get(ch_id)
145
- vtvgo_url = VTVGO_URLS.get(ch_id)
146
  is_flv = stream_url and ".flv" in stream_url
147
  result[ch_id] = {
148
  "name": CHANNEL_NAMES[ch_id],
@@ -150,7 +136,7 @@ def api_vtv_streams():
150
  "proxy_url": f"/api/proxy/flv?url={quote(stream_url, safe='')}" if stream_url and is_flv else "",
151
  "proxy_url_hls": f"/api/proxy/stream?url={quote(stream_url, safe='')}" if stream_url and not is_flv else "",
152
  "is_flv": is_flv,
153
- "proxy_iframe_url": f"/api/proxy/vtvgo?url={quote(vtvgo_url, safe='')}" if vtvgo_url else "",
154
  "status": "ok"
155
  }
156
  return JSONResponse(result)
@@ -160,7 +146,7 @@ def api_vtv_stream(channel_id: str):
160
  channel_id = channel_id.lower().strip()
161
  if channel_id not in CHANNEL_NAMES: return JSONResponse({"error":"not found"}, status_code=404)
162
  stream_url = get_channel_url(channel_id)
163
- vtvgo_url = VTVGO_URLS.get(channel_id)
164
  is_flv = stream_url and ".flv" in stream_url
165
  return JSONResponse({
166
  "name": CHANNEL_NAMES[channel_id],
@@ -168,7 +154,7 @@ def api_vtv_stream(channel_id: str):
168
  "proxy_url": f"/api/proxy/flv?url={quote(stream_url, safe='')}" if stream_url and is_flv else "",
169
  "proxy_url_hls": f"/api/proxy/stream?url={quote(stream_url, safe='')}" if stream_url and not is_flv else "",
170
  "is_flv": is_flv,
171
- "proxy_iframe_url": f"/api/proxy/vtvgo?url={quote(vtvgo_url, safe='')}" if vtvgo_url else "",
172
  "status": "ok"
173
  })
174
 
 
1
+ # VTV Stream — SV2 iframe cho tất cả kênh + 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 iframe URLs — player thật, hỗ trợ mobile
22
+ SV2_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",
26
+ "vtv4": "https://sv2.xemtivitop.com/live/hot/vtv4.php",
27
+ "vtv5": "https://sv2.xemtivitop.com/live/hot/vtv5.php",
28
+ "vtv6": "https://sv2.xemtivitop.com/live/hot/vtv6.php",
29
+ "vtv7": "https://sv2.xemtivitop.com/live/hot/vtv7.php",
30
+ "vtv8": "https://sv2.xemtivitop.com/live/hot/vtv8.php",
31
+ "vtv9": "https://sv2.xemtivitop.com/live/hot/vtv9.php",
32
+ "vtv10": "https://sv2.xemtivitop.com/live/hot/vtv10.php",
33
  }
34
 
35
  M3U_URLS = [
 
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 iframerewrite 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 =====================
 
128
  result = {}
129
  for ch_id in CHANNEL_NAMES:
130
  stream_url = urls.get(ch_id)
131
+ sv2_url = SV2_URLS.get(ch_id)
132
  is_flv = stream_url and ".flv" in stream_url
133
  result[ch_id] = {
134
  "name": CHANNEL_NAMES[ch_id],
 
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
+ "proxy_iframe_url": f"/api/proxy/sv2/iframe?url={quote(sv2_url, safe='')}" if sv2_url else "",
140
  "status": "ok"
141
  }
142
  return JSONResponse(result)
 
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 = SV2_URLS.get(channel_id)
150
  is_flv = stream_url and ".flv" in stream_url
151
  return JSONResponse({
152
  "name": CHANNEL_NAMES[channel_id],
 
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
+ "proxy_iframe_url": f"/api/proxy/sv2/iframe?url={quote(sv2_url, safe='')}" if sv2_url else "",
158
  "status": "ok"
159
  })
160