new.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. import time
  2. import concurrent.futures
  3. import requests
  4. import re
  5. import os
  6. import threading
  7. from queue import Queue
  8. import eventlet
  9. eventlet.monkey_patch()
  10. urls = [
  11. "http://1.196.55.1:9901",
  12. "http://1.197.249.1:9901",
  13. "http://101.65.32.1:9901",
  14. "http://101.66.198.1:9901",
  15. "http://101.66.199.1:9901",
  16. "http://101.72.127.1:808",
  17. "http://106.46.147.1:10443",
  18. "http://106.55.164.1:9901",
  19. "http://111.225.112.1:808",
  20. "http://111.225.114.1:808",
  21. "http://111.33.89.1:9901",
  22. "http://111.78.22.1:9901",
  23. "http://111.8.224.1:8085",
  24. "http://112.132.160.1:9901",
  25. "http://112.234.23.1:9901",
  26. "http://112.26.18.1:9901",
  27. "http://112.5.89.1:9900",
  28. "http://112.5.89.1:9901",
  29. "http://113.116.145.1:8883",
  30. "http://113.116.59.1:8883",
  31. "http://113.124.234.1:9901",
  32. "http://113.195.13.1:9901",
  33. "http://113.195.162.1:9901",
  34. "http://113.195.4.1:9901",
  35. "http://113.195.45.1:9901",
  36. "http://113.200.214.1:9902",
  37. "http://113.201.61.1:9901",
  38. "http://113.205.195.1:9901",
  39. "http://113.205.196.1:9901",
  40. "http://113.206.102.1:9901",
  41. "http://113.218.204.1:8081",
  42. "http://113.220.234.1:9999",
  43. "http://113.220.235.1:9999",
  44. "http://113.57.20.1:9901",
  45. "http://113.57.93.1:9900",
  46. "http://113.92.198.1:8883",
  47. "http://114.254.92.1:88",
  48. "http://115.149.139.1:10001",
  49. "http://115.236.83.1:1111",
  50. "http://115.48.22.1:9901",
  51. "http://115.48.63.1:9901",
  52. "http://116.128.224.1:9901",
  53. "http://116.128.242.1:9901",
  54. "http://116.167.111.1:9901",
  55. "http://116.167.76.1:9901",
  56. "http://116.167.79.1:9901",
  57. "http://116.227.232.1:7777",
  58. "http://116.233.34.1:7777",
  59. "http://116.30.121.1:8883",
  60. "http://116.31.165.1:280",
  61. "http://116.31.165.1:3079",
  62. "http://116.31.165.1:6666",
  63. "http://117.27.190.1:9998",
  64. "http://117.90.196.1:6000",
  65. "http://118.248.168.1:8088",
  66. "http://118.248.169.1:8088",
  67. "http://118.248.216.1:8088",
  68. "http://118.81.106.1:9999",
  69. "http://118.81.107.1:9999",
  70. "http://119.125.134.1:7788",
  71. "http://119.163.228.1:9901",
  72. "http://120.0.52.1:8086",
  73. "http://120.0.8.1:8086",
  74. "http://121.19.134.1:808",
  75. "http://121.232.178.1:5000",
  76. "http://121.232.187.1:6000",
  77. "http://121.33.239.1:9901",
  78. "http://122.188.62.1:8800",
  79. "http://123.129.70.1:9901",
  80. "http://123.130.84.1:8154",
  81. "http://123.138.216.1:9902",
  82. "http://123.138.22.1:9901",
  83. "http://123.139.57.1:9901",
  84. "http://123.154.154.1:9901",
  85. "http://123.182.247.1:4433",
  86. "http://124.126.4.1:9901",
  87. "http://124.128.73.1:9901",
  88. "http://124.231.213.1:9999",
  89. "http://125.106.86.1:9901",
  90. "http://125.107.177.1:9901",
  91. "http://125.125.234.1:9901",
  92. "http://14.106.236.1:9901",
  93. "http://14.106.239.1:9901",
  94. "http://171.8.75.1:8011",
  95. "http://180.113.102.1:5000",
  96. "http://180.117.149.1:9901",
  97. "http://180.124.146.1:60000",
  98. "http://180.175.163.1:7777",
  99. "http://180.213.174.1:9901",
  100. "http://182.113.206.1:9901",
  101. "http://182.117.136.1:9901",
  102. "http://202.100.46.1:9901",
  103. "http://210.22.75.1:9901",
  104. "http://218.74.169.1:9901",
  105. "http://218.76.32.1:9901",
  106. "http://218.87.237.1:9901",
  107. "http://220.161.206.1:9901",
  108. "http://220.179.68.1:9901",
  109. "http://220.180.112.1:9901",
  110. "http://220.249.114.1:9901",
  111. "http://221.2.148.1:8154",
  112. "http://221.205.128.1:9999",
  113. "http://221.205.129.1:9999",
  114. "http://221.205.130.1:9999",
  115. "http://221.205.131.1:9999",
  116. "http://221.233.192.1:1111",
  117. "http://222.134.245.1:9901",
  118. "http://222.243.221.1:9901",
  119. "http://223.166.234.1:7777",
  120. "http://223.241.247.1:9901",
  121. "http://223.68.201.1:9901",
  122. "http://27.14.163.1:9901",
  123. "http://27.14.84.1:9901",
  124. "http://27.8.192.1:9901",
  125. "http://27.8.233.1:9901",
  126. "http://27.8.243.1:9901",
  127. "http://36.249.150.1:9901",
  128. "http://36.249.151.1:9901",
  129. "http://36.40.236.1:9999",
  130. "http://36.44.157.1:9901",
  131. "http://36.99.206.1:9901",
  132. "http://47.104.163.1:9901",
  133. "http://47.116.70.1:9901",
  134. "http://49.232.48.1:9901",
  135. "http://49.234.31.1:7004",
  136. "http://58.17.116.1:9908",
  137. "http://58.19.244.1:1111",
  138. "http://58.209.101.1:9901",
  139. "http://58.216.229.1:9901",
  140. "http://58.220.219.1:9901",
  141. "http://58.23.27.1:9901",
  142. "http://58.243.224.1:9901",
  143. "http://58.243.93.1:9901",
  144. "http://58.48.37.1:1111",
  145. "http://58.48.5.1:1111",
  146. "http://59.173.183.1:9901",
  147. "http://59.63.22.1:8888",
  148. "http://60.169.254.1:9901",
  149. "http://60.172.59.1:9901",
  150. "http://60.174.86.1:9901",
  151. "http://61.136.172.1:9901",
  152. "http://61.136.67.1:50085",
  153. "http://61.156.228.1:8154",
  154. "http://61.173.144.1:9901"
  155. ]
  156. def modify_urls(url):
  157. modified_urls = []
  158. ip_start_index = url.find("//") + 2
  159. ip_end_index = url.find(":", ip_start_index)
  160. base_url = url[:ip_start_index] # http:// or https://
  161. ip_address = url[ip_start_index:ip_end_index]
  162. port = url[ip_end_index:]
  163. ip_end = "/iptv/live/1000.json?key=txiptv"
  164. for i in range(1, 256):
  165. modified_ip = f"{ip_address[:-1]}{i}"
  166. modified_url = f"{base_url}{modified_ip}{port}{ip_end}"
  167. modified_urls.append(modified_url)
  168. return modified_urls
  169. def is_url_accessible(url):
  170. try:
  171. response = requests.get(url, timeout=0.5)
  172. if response.status_code == 200:
  173. return url
  174. except requests.exceptions.RequestException:
  175. pass
  176. return None
  177. results = []
  178. x_urls = []
  179. for url in urls: # 对urls进行处理,ip第四位修改为1,并去重
  180. url = url.strip()
  181. ip_start_index = url.find("//") + 2
  182. ip_end_index = url.find(":", ip_start_index)
  183. ip_dot_start = url.find(".") + 1
  184. ip_dot_second = url.find(".", ip_dot_start) + 1
  185. ip_dot_three = url.find(".", ip_dot_second) + 1
  186. base_url = url[:ip_start_index] # http:// or https://
  187. ip_address = url[ip_start_index:ip_dot_three]
  188. port = url[ip_end_index:]
  189. ip_end = "1"
  190. modified_ip = f"{ip_address}{ip_end}"
  191. x_url = f"{base_url}{modified_ip}{port}"
  192. x_urls.append(x_url)
  193. urls = set(x_urls) # 去重得到唯一的URL列表
  194. valid_urls = []
  195. # 多线程获取可用url
  196. with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
  197. futures = []
  198. for url in urls:
  199. url = url.strip()
  200. modified_urls = modify_urls(url)
  201. for modified_url in modified_urls:
  202. futures.append(executor.submit(is_url_accessible, modified_url))
  203. for future in concurrent.futures.as_completed(futures):
  204. result = future.result()
  205. if result:
  206. valid_urls.append(result)
  207. for url in valid_urls:
  208. print(url)
  209. # 遍历网址列表,获取JSON文件并解析
  210. for url in valid_urls:
  211. try:
  212. # 发送GET请求获取JSON文件,设置超时时间为0.5秒
  213. ip_start_index = url.find("//") + 2
  214. ip_dot_start = url.find(".") + 1
  215. ip_index_second = url.find("/", ip_dot_start)
  216. base_url = url[:ip_start_index] # http:// or https://
  217. ip_address = url[ip_start_index:ip_index_second]
  218. url_x = f"{base_url}{ip_address}"
  219. json_url = f"{url}"
  220. response = requests.get(json_url, timeout=0.5)
  221. json_data = response.json()
  222. try:
  223. # 解析JSON文件,获取name和url字段
  224. for item in json_data['data']:
  225. if isinstance(item, dict):
  226. name = item.get('name')
  227. urlx = item.get('url')
  228. if ',' in urlx:
  229. urlx=f"aaaaaaaa"
  230. #if 'http' in urlx or 'udp' in urlx or 'rtp' in urlx:
  231. if 'http' in urlx:
  232. urld = f"{urlx}"
  233. else:
  234. urld = f"{url_x}{urlx}"
  235. if name and urlx:
  236. # 删除特定文字
  237. name = name.replace("cctv", "CCTV")
  238. name = name.replace("中央", "CCTV")
  239. name = name.replace("央视", "CCTV")
  240. name = name.replace("高清", "")
  241. name = name.replace("超高", "")
  242. name = name.replace("HD", "")
  243. name = name.replace("标清", "")
  244. name = name.replace("频道", "")
  245. name = name.replace("-", "")
  246. name = name.replace(" ", "")
  247. name = name.replace("PLUS", "+")
  248. name = name.replace("+", "+")
  249. name = name.replace("(", "")
  250. name = name.replace(")", "")
  251. name = re.sub(r"CCTV(\d+)台", r"CCTV\1", name)
  252. name = name.replace("CCTV1综合", "CCTV1")
  253. name = name.replace("CCTV2财经", "CCTV2")
  254. name = name.replace("CCTV3综艺", "CCTV3")
  255. name = name.replace("CCTV4国际", "CCTV4")
  256. name = name.replace("CCTV4中文国际", "CCTV4")
  257. name = name.replace("CCTV4欧洲", "CCTV4")
  258. name = name.replace("CCTV5体育", "CCTV5")
  259. name = name.replace("CCTV6电影", "CCTV6")
  260. name = name.replace("CCTV7军事", "CCTV7")
  261. name = name.replace("CCTV7军农", "CCTV7")
  262. name = name.replace("CCTV7农业", "CCTV7")
  263. name = name.replace("CCTV7国防军事", "CCTV7")
  264. name = name.replace("CCTV8电视剧", "CCTV8")
  265. name = name.replace("CCTV9记录", "CCTV9")
  266. name = name.replace("CCTV9纪录", "CCTV9")
  267. name = name.replace("CCTV10科教", "CCTV10")
  268. name = name.replace("CCTV11戏曲", "CCTV11")
  269. name = name.replace("CCTV12社会与法", "CCTV12")
  270. name = name.replace("CCTV13新闻", "CCTV13")
  271. name = name.replace("CCTV新闻", "CCTV13")
  272. name = name.replace("CCTV14少儿", "CCTV14")
  273. name = name.replace("CCTV15音乐", "CCTV15")
  274. name = name.replace("CCTV16奥林匹克", "CCTV16")
  275. name = name.replace("CCTV17农业农村", "CCTV17")
  276. name = name.replace("CCTV17农业", "CCTV17")
  277. name = name.replace("CCTV5+体育赛视", "CCTV5+")
  278. name = name.replace("CCTV5+体育赛事", "CCTV5+")
  279. name = name.replace("CCTV5+体育", "CCTV5+")
  280. results.append(f"{name},{urld}")
  281. except:
  282. continue
  283. except:
  284. continue
  285. channels = []
  286. for result in results:
  287. line = result.strip()
  288. if result:
  289. channel_name, channel_url = result.split(',')
  290. channels.append((channel_name, channel_url))
  291. # 线程安全的队列,用于存储下载任务
  292. task_queue = Queue()
  293. # 线程安全的列表,用于存储结果
  294. results = []
  295. error_channels = []
  296. # 定义工作线程函数
  297. def worker():
  298. while True:
  299. # 从队列中获取一个任务
  300. channel_name, channel_url = task_queue.get()
  301. try:
  302. channel_url_t = channel_url.rstrip(channel_url.split('/')[-1]) # m3u8链接前缀
  303. lines = requests.get(channel_url, timeout = 1).text.strip().split('\n') # 获取m3u8文件内容
  304. ts_lists = [line.split('/')[-1] for line in lines if line.startswith('#') == False] # 获取m3u8文件下视频流后缀
  305. ts_lists_0 = ts_lists[0].rstrip(ts_lists[0].split('.ts')[-1]) # m3u8链接前缀
  306. ts_url = channel_url_t + ts_lists[0] # 拼接单个视频片段下载链接
  307. # 多获取的视频数据进行5秒钟限制
  308. with eventlet.Timeout(5, False):
  309. start_time = time.time()
  310. content = requests.get(ts_url, timeout = 1).content
  311. end_time = time.time()
  312. response_time = (end_time - start_time) * 1
  313. if content:
  314. with open(ts_lists_0, 'ab') as f:
  315. f.write(content) # 写入文件
  316. file_size = len(content)
  317. # print(f"文件大小:{file_size} 字节")
  318. download_speed = file_size / response_time / 1024
  319. # print(f"下载速度:{download_speed:.3f} kB/s")
  320. normalized_speed = min(max(download_speed / 1024, 0.001), 100) # 将速率从kB/s转换为MB/s并限制在1~100之间
  321. #print(f"标准化后的速率:{normalized_speed:.3f} MB/s")
  322. # 删除下载的文件
  323. os.remove(ts_lists_0)
  324. result = channel_name, channel_url, f"{normalized_speed:.3f} MB/s"
  325. results.append(result)
  326. numberx = (len(results) + len(error_channels)) / len(channels) * 100
  327. print(f"可用频道:{len(results)} 个 , 不可用频道:{len(error_channels)} 个 , 总频道:{len(channels)} 个 ,总进度:{numberx:.2f} %。")
  328. except:
  329. error_channel = channel_name, channel_url
  330. error_channels.append(error_channel)
  331. numberx = (len(results) + len(error_channels)) / len(channels) * 100
  332. print(f"可用频道:{len(results)} 个 , 不可用频道:{len(error_channels)} 个 , 总频道:{len(channels)} 个 ,总进度:{numberx:.2f} %。")
  333. # 标记任务完成
  334. task_queue.task_done()
  335. # 创建多个工作线程
  336. num_threads = 10
  337. for _ in range(num_threads):
  338. t = threading.Thread(target=worker, daemon=True) # 将工作线程设置为守护线程
  339. t.start()
  340. # 添加下载任务到队列
  341. for channel in channels:
  342. task_queue.put(channel)
  343. # 等待所有任务完成
  344. task_queue.join()
  345. def channel_key(channel_name):
  346. match = re.search(r'\d+', channel_name)
  347. if match:
  348. return int(match.group())
  349. else:
  350. return float('inf') # 返回一个无穷大的数字作为关键字
  351. # 对频道进行排序
  352. results.sort(key=lambda x: (x[0], -float(x[2].split()[0])))
  353. results.sort(key=lambda x: channel_key(x[0]))
  354. result_counter = 8 # 每个频道需要的个数
  355. with open("itvlist.txt", 'w', encoding='utf-8') as file:
  356. channel_counters = {}
  357. file.write('央视频道,#genre#\n')
  358. for result in results:
  359. channel_name, channel_url, speed = result
  360. if 'CCTV' in channel_name:
  361. if channel_name in channel_counters:
  362. if channel_counters[channel_name] >= result_counter:
  363. continue
  364. else:
  365. file.write(f"{channel_name},{channel_url}\n")
  366. channel_counters[channel_name] += 1
  367. else:
  368. file.write(f"{channel_name},{channel_url}\n")
  369. channel_counters[channel_name] = 1
  370. channel_counters = {}
  371. file.write('卫视频道,#genre#\n')
  372. for result in results:
  373. channel_name, channel_url, speed = result
  374. if '卫视' in channel_name:
  375. if channel_name in channel_counters:
  376. if channel_counters[channel_name] >= result_counter:
  377. continue
  378. else:
  379. file.write(f"{channel_name},{channel_url}\n")
  380. channel_counters[channel_name] += 1
  381. else:
  382. file.write(f"{channel_name},{channel_url}\n")
  383. channel_counters[channel_name] = 1
  384. channel_counters = {}
  385. file.write('其他频道,#genre#\n')
  386. for result in results:
  387. channel_name, channel_url, speed = result
  388. if 'CCTV' not in channel_name and '卫视' not in channel_name and '测试' not in channel_name:
  389. if channel_name in channel_counters:
  390. if channel_counters[channel_name] >= result_counter:
  391. continue
  392. else:
  393. file.write(f"{channel_name},{channel_url}\n")
  394. channel_counters[channel_name] += 1
  395. else:
  396. file.write(f"{channel_name},{channel_url}\n")
  397. channel_counters[channel_name] = 1
  398. with open("itvlist.m3u", 'w', encoding='utf-8') as file:
  399. channel_counters = {}
  400. file.write('#EXTM3U\n')
  401. for result in results:
  402. channel_name, channel_url, speed = result
  403. if 'CCTV' in channel_name:
  404. if channel_name in channel_counters:
  405. if channel_counters[channel_name] >= result_counter:
  406. continue
  407. else:
  408. file.write(f"#EXTINF:-1 group-title=\"央视频道\",{channel_name}\n")
  409. file.write(f"{channel_url}\n")
  410. channel_counters[channel_name] += 1
  411. else:
  412. file.write(f"#EXTINF:-1 group-title=\"央视频道\",{channel_name}\n")
  413. file.write(f"{channel_url}\n")
  414. channel_counters[channel_name] = 1
  415. channel_counters = {}
  416. #file.write('卫视频道,#genre#\n')
  417. for result in results:
  418. channel_name, channel_url, speed = result
  419. if '卫视' in channel_name:
  420. if channel_name in channel_counters:
  421. if channel_counters[channel_name] >= result_counter:
  422. continue
  423. else:
  424. file.write(f"#EXTINF:-1 group-title=\"卫视频道\",{channel_name}\n")
  425. file.write(f"{channel_url}\n")
  426. channel_counters[channel_name] += 1
  427. else:
  428. file.write(f"#EXTINF:-1 group-title=\"卫视频道\",{channel_name}\n")
  429. file.write(f"{channel_url}\n")
  430. channel_counters[channel_name] = 1
  431. channel_counters = {}
  432. #file.write('其他频道,#genre#\n')
  433. for result in results:
  434. channel_name, channel_url, speed = result
  435. if 'CCTV' not in channel_name and '卫视' not in channel_name and '测试' not in channel_name:
  436. if channel_name in channel_counters:
  437. if channel_counters[channel_name] >= result_counter:
  438. continue
  439. else:
  440. file.write(f"#EXTINF:-1 group-title=\"其他频道\",{channel_name}\n")
  441. file.write(f"{channel_url}\n")
  442. channel_counters[channel_name] += 1
  443. else:
  444. file.write(f"#EXTINF:-1 group-title=\"其他频道\",{channel_name}\n")
  445. file.write(f"{channel_url}\n")
  446. channel_counters[channel_name] = 1