bep40 commited on
Commit
db38b97
·
verified ·
1 Parent(s): 65d2b75

Upload vtv_scraper.py

Browse files
Files changed (1) hide show
  1. vtv_scraper.py +36 -130
vtv_scraper.py CHANGED
@@ -1,130 +1,36 @@
1
- """
2
- VTV Channels Scraper
3
- Fetches stream URLs from hd.xemtv.net PHP endpoints for VTV1-VTV10 + VTV Cần Thơ
4
- import requests, re, time, threading
5
-
6
- UA = {
7
- "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",
8
- "Accept-Language": "vi-VN,vi;q=0.9",
9
- "Referer": "https://hd.xemtv.net/",
10
- }
11
-
12
- XEMTV_PHP_ENDPOINTS = {
13
- "vtv1": "https://hd.xemtv.net/kenh/vtv1.php",
14
- "vtv2": "https://hd.xemtv.net/kenh/vtv2.php",
15
- "vtv3": "https://hd.xemtv.net/kenh/vtv3.php",
16
- "vtv4": "https://hd.xemtv.net/kenh/vtv4.php",
17
- "vtv5": "https://hd.xemtv.net/kenh/vtv5.php",
18
- "vtv6": "https://hd.xemtv.net/kenh/vtv6.php",
19
- "vtv7": "https://hd.xemtv.net/kenh/vtv7.php",
20
- "vtv8": "https://hd.xemtv.net/kenh/vtv8.php",
21
- "vtv9": "https://hd.xemtv.net/kenh/vtv9.php",
22
- "vtv10": "https://hd.xemtv.net/kenh/vtv10.php",
23
- }
24
-
25
- CHANNEL_NAMES = {
26
- "vtv1": "VTV1", "vtv2": "VTV2", "vtv3": "VTV3", "vtv4": "VTV4",
27
- "vtv5": "VTV5", "vtv6": "VTV6", "vtv7": "VTV7", "vtv8": "VTV8",
28
- "vtv9": "VTV9", "vtv10": "VTV Cần Thơ",
29
- }
30
-
31
- CDN_FALLBACK = {
32
- "vtv1": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv1-manifest.m3u8",
33
- "vtv2": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv2-manifest.m3u8",
34
- "vtv3": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv3-manifest.m3u8",
35
- "vtv4": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv4-manifest.m3u8",
36
- "vtv5": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv5-manifest.m3u8",
37
- "vtv6": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv6-manifest.m3u8",
38
- "vtv7": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv7-manifest.m3u8",
39
- "vtv8": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv8-manifest.m3u8",
40
- "vtv9": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv9-manifest.m3u8",
41
- "vtv10": "https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv10-manifest.m3u8",
42
- "_fpt_vtv1": "https://live.fptplay53.net/fnxch2/vtv1hd_abr.smil/chunklist.m3u8",
43
- "_fpt_vtv2": "https://live.fptplay53.net/fnxch2/vtv2hd_abr.smil/chunklist.m3u8",
44
- "_fpt_vtv3": "https://live.fptplay53.net/fnxch2/vtv3hd_abr.smil/chunklist.m3u8",
45
- "_fpt_vtv4": "https://live.fptplay53.net/fnxch2/vtv4hd_abr.smil/chunklist.m3u8",
46
- "_fpt_vtv5": "https://live-a.fptplay53.net/live/media/VTV5HD/live_hls_avc/index.m3u8",
47
- "_fpt_vtv6": "https://live.fptplay53.net/fnxch2/vtv6hd_abr.smil/chunklist.m3u8",
48
- "_fpt_vtv7": "https://live.fptplay53.net/fnxhd1/vtv7hd_vhls.smil/chunklist_b5000000.m3u8",
49
- "_fpt_vtv8": "https://live.fptplay53.net/epzhd1/vtv8hd_vhls.smil/chunklist.m3u8",
50
- "_fpt_vtv9": "https://live.fptplay53.net/fnxhd1/vtv9hd_vhls.smil/chunklist.m3u8",
51
- "_fpt_vtv10": "https://live.fptplay53.net/fnxch2/vtvcantho_abr.smil/chunklist.m3u8",
52
- }
53
-
54
- _vtv_cache = {}
55
- _vtv_lock = threading.Lock()
56
- _CACHE_TTL = 180
57
-
58
- def _cached(key):
59
- with _vtv_lock:
60
- if key in _vtv_cache and time.time() - _vtv_cache[key]['t'] < _CACHE_TTL:
61
- return _vtv_cache[key]['d']
62
- return None
63
-
64
- def _set_cache(key, data):
65
- with _vtv_lock:
66
- _vtv_cache[key] = {'t': time.time(), 'd': data}
67
-
68
- def extract_m3u8_from_html(html):
69
- if not html:
70
- return None
71
- m = re.search(r"file\s*:\s*['\"]([^'\"]*\.m3u8[^'\"]*)['\"]", html, re.IGNORECASE)
72
- if m:
73
- url = m.group(1).strip()
74
- if len(url) > 20:
75
- return url
76
- m = re.search(r"(https?://[^\s\"'<>\\]+\.m3u8[^\s\"'<>\\]*)", html, re.IGNORECASE)
77
- if m:
78
- url = m.group(1).strip()
79
- if len(url) > 20:
80
- return url
81
- return None
82
-
83
- def fetch_vtv_stream(channel_id):
84
- channel_id = channel_id.lower().strip()
85
- name_map = {
86
- 'vtvct': 'vtv10', 'vtv-can-tho': 'vtv10', 'vtv can tho': 'vtv10',
87
- 'vtv_can_tho': 'vtv10', 'cantho': 'vtv10', 'cần thơ': 'vtv10',
88
- 'vietnam_vtv1': 'vtv1', 'vietnam_vtv2': 'vtv2', 'vietnam_vtv3': 'vtv3',
89
- 'vietnam_vtv4': 'vtv4', 'vietnam_vtv5': 'vtv5', 'vietnam_vtv6': 'vtv6',
90
- 'vietnam_vtv7': 'vtv7', 'vietnam_vtv8': 'vtv8', 'vietnam_vtv9': 'vtv9',
91
- }
92
- channel_id = name_map.get(channel_id, channel_id)
93
- cached = _cached(channel_id)
94
- if cached:
95
- return cached
96
- vtvgourl = CDN_FALLBACK.get(channel_id)
97
- if vtvgourl:
98
- _set_cache(channel_id, vtvgourl)
99
- return vtvgourl
100
- php_url = XEMTV_PHP_ENDPOINTS.get(channel_id)
101
- if php_url:
102
- try:
103
- r = requests.get(php_url, headers=UA, timeout=15, allow_redirects=True, verify=False)
104
- if r.status_code == 200:
105
- m3u8 = extract_m3u8_from_html(r.text)
106
- if m3u8:
107
- _set_cache(channel_id, m3u8)
108
- return m3u8
109
- except:
110
- pass
111
- fpt_key = f"_fpt_{channel_id}"
112
- fpt_url = CDN_FALLBACK.get(fpt_key)
113
- if fpt_url:
114
- _set_cache(channel_id, fpt_url)
115
- return fpt_url
116
- return None
117
-
118
- def get_all_vtv_streams():
119
- channels = []
120
- for ch_id, php_url in XEMTV_PHP_ENDPOINTS.items():
121
- stream_url = fetch_vtv_stream(ch_id)
122
- channels.append({
123
- 'id': ch_id,
124
- 'name': CHANNEL_NAMES.get(ch_id, ch_id.upper()),
125
- 'stream_url': stream_url,
126
- })
127
- return channels
128
-
129
- XEMTV_CHANNELS = {v: k for k, v in CHANNEL_NAMES.items()}
130
- CDN_STREAMS = {v: k for k, v in CDN_FALLBACK.items()}
 
1
+ """VTV Scraper - xemtv.us + FPTPlay + VTVGo + canthotv"""
2
+ import re, json, os, time
3
+ import requests
4
+ from bs4 import BeautifulSoup
5
+
6
+ HEADERS = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","Accept-Language":"vi-VN,vi;q=0.9,en;q=0.8"}
7
+
8
+ def get_vtv_streams():
9
+ """Get all VTV channel streams"""
10
+ from vtv_api import CHANNELS, get_stream
11
+ results = []
12
+ for ch in CHANNELS:
13
+ stream = get_stream(ch["id"])
14
+ if stream:
15
+ results.append({"channel": ch, "stream": stream})
16
+ return results
17
+
18
+ def get_vtvnambo_videos():
19
+ """Get VTV Nam Bo videos"""
20
+ try:
21
+ url = "https://xemtv.us/vtv-nam-bo.html"
22
+ r = requests.get(url, headers=HEADERS, timeout=15)
23
+ if r.status_code != 200: return []
24
+ r.encoding = "utf-8"
25
+ soup = BeautifulSoup(r.text, "lxml")
26
+ videos = []
27
+ for a in soup.find_all("a", href=True):
28
+ href = a.get("href", "")
29
+ if "/video/" in href:
30
+ title = a.get_text(strip=True)
31
+ if title and len(title) > 5:
32
+ if not href.startswith("http"):
33
+ href = "https://xemtv.us" + href
34
+ videos.append({"title": title, "link": href, "source": "xemtv"})
35
+ return videos[:20]
36
+ except: return []