Spaces:
Running
Running
Fix VTV1-VTV10 stream URLs: add VTVGo failover (200 OK), replace broken fptplay CDN (403), fix VTV10 Can Tho source
Browse files- vtv_api.py +36 -2
vtv_api.py
CHANGED
|
@@ -45,7 +45,25 @@ CHANNEL_NAMES = {
|
|
| 45 |
"vtvprime": "VTVPrime",
|
| 46 |
}
|
| 47 |
|
| 48 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
CDN_FALLBACK = {
|
| 50 |
"vtv1": "https://live.fptplay53.net/fnxch2/vtv1hd_abr.smil/chunklist.m3u8",
|
| 51 |
"vtv2": "https://live.fptplay53.net/fnxch2/vtv2hd_abr.smil/chunklist.m3u8",
|
|
@@ -114,6 +132,22 @@ def fetch_vtv_stream(channel_id):
|
|
| 114 |
if cached:
|
| 115 |
return cached
|
| 116 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
php_url = XEMTV_PHP_ENDPOINTS.get(channel_id)
|
| 118 |
if php_url:
|
| 119 |
try:
|
|
@@ -126,7 +160,7 @@ def fetch_vtv_stream(channel_id):
|
|
| 126 |
except:
|
| 127 |
pass
|
| 128 |
|
| 129 |
-
#
|
| 130 |
fallback = CDN_FALLBACK.get(channel_id)
|
| 131 |
if fallback:
|
| 132 |
_set_cache(channel_id, fallback)
|
|
|
|
| 45 |
"vtvprime": "VTVPrime",
|
| 46 |
}
|
| 47 |
|
| 48 |
+
# Primary working stream URLs (verified 2025-2026)
|
| 49 |
+
# VTVGo failover CDN - Official VTV sources that return 200 OK
|
| 50 |
+
VTVGO_FAILOVER = {
|
| 51 |
+
"vtv1": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv1-manifest.m3u8",
|
| 52 |
+
"vtv2": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv2-manifest.m3u8",
|
| 53 |
+
"vtv3": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv3-manifest.m3u8",
|
| 54 |
+
"vtv4": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv4-manifest.m3u8",
|
| 55 |
+
"vtv5": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv5-manifest.m3u8",
|
| 56 |
+
"vtv6": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv6-manifest.m3u8",
|
| 57 |
+
"vtv7": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv7-manifest.m3u8",
|
| 58 |
+
"vtv8": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv8-manifest.m3u8",
|
| 59 |
+
"vtv9": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv9-manifest.m3u8",
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
# VTV10/Can Tho - uses different stream source (not available on VTVGo failover)
|
| 63 |
+
VTV10_STREAM = "https://live.canthotv.vn/live/tv/chunklist.m3u8"
|
| 64 |
+
|
| 65 |
+
# Legacy CDN fallback (fptplay) - returns 403 due to hotlink protection
|
| 66 |
+
# Kept as last resort only
|
| 67 |
CDN_FALLBACK = {
|
| 68 |
"vtv1": "https://live.fptplay53.net/fnxch2/vtv1hd_abr.smil/chunklist.m3u8",
|
| 69 |
"vtv2": "https://live.fptplay53.net/fnxch2/vtv2hd_abr.smil/chunklist.m3u8",
|
|
|
|
| 132 |
if cached:
|
| 133 |
return cached
|
| 134 |
|
| 135 |
+
# Special case: VTVPrime is a paid service, no free stream available on xemtv.net
|
| 136 |
+
if channel_id == 'vtvprime':
|
| 137 |
+
return None
|
| 138 |
+
|
| 139 |
+
# Special case: VTV10/Can Tho uses a different stream source
|
| 140 |
+
if channel_id == 'vtv10':
|
| 141 |
+
_set_cache(channel_id, VTV10_STREAM)
|
| 142 |
+
return VTV10_STREAM
|
| 143 |
+
|
| 144 |
+
# For VTV1-VTV9: Use VTVGo failover URLs (most reliable, verified working)
|
| 145 |
+
vtvgo_url = VTVGO_FAILOVER.get(channel_id)
|
| 146 |
+
if vtvgo_url:
|
| 147 |
+
_set_cache(channel_id, vtvgo_url)
|
| 148 |
+
return vtvgo_url
|
| 149 |
+
|
| 150 |
+
# Fallback to xemtv.net scraping if needed
|
| 151 |
php_url = XEMTV_PHP_ENDPOINTS.get(channel_id)
|
| 152 |
if php_url:
|
| 153 |
try:
|
|
|
|
| 160 |
except:
|
| 161 |
pass
|
| 162 |
|
| 163 |
+
# Last resort: CDN fallback
|
| 164 |
fallback = CDN_FALLBACK.get(channel_id)
|
| 165 |
if fallback:
|
| 166 |
_set_cache(channel_id, fallback)
|