Linux使用的m3u8下载器,为了下载剧集方便写了批量命名。
.\run.py
import downloader
import requests
import json
cfg = {
"maxPoolsize": 32,
"workDir": '/home/huxiaohong/webdl/',
"tempDir": '/home/huxiaohong/webdl/temp/',
}
if __name__ == "__main__":
mod = input("请输入工作模式(剧集E/单集S/腾讯超前点播C):")
if mod == "E":
title = input("请输入剧集通名,用*代替集数(无需后缀):")
while True:
url = input("请输入m3u8地址:\n")
epi = input("请输入集数:\n")
name = title.replace("*", epi)
dl = downloader.Downloader(cfg["maxPoolsize"])
dl.run(url, cfg["tempDir"], cfg["workDir"], name)
elif mod == "S":
while True:
url = input("请输入m3u8地址:\n")
title = input("请输入要保存的文件名(无需后缀):\n")
dl = downloader.Downloader(cfg["maxPoolsize"])
dl.run(url, cfg["tempDir"], cfg["workDir"], title)
elif mod == "C":
title = input("请输入剧集通名,用*代替集数(无需后缀):")
while True:
url = input("请输入视频播放页地址:\n")
epi = input("请输入集数:\n")
vid = url.split("/")[-1].split(".")[0]
body = main(vid)
name = title.replace("*", epi)
dl = downloader.Downloader(cfg["maxPoolsize"])
dl.crun(body, cfg["tempDir"], cfg["workDir"], name)
else:
print("输入有误,退出脚本。")
downloader.py
#coding: utf-8
from gevent import monkey
monkey.patch_all()
from gevent.pool import Pool
import gevent
import requests
from urllib.parse import urlparse, urljoin
import os
import time
class Downloader:
def __init__(self, pool_size, retry=3):
self.pool = Pool(pool_size)
self.session = self._get_http_session(pool_size, pool_size, retry)
self.retry = retry
self.wdir = ''
self.tdir = ''
self.succed = {}
self.failed = []
self.ts_total = 0
def _get_http_session(self, pool_connections, pool_maxsize, max_retries):
session = requests.Session()
adapter = requests.adapters.HTTPAdapter(pool_connections=pool_connections, pool_maxsize=pool_maxsize, max_retries=max_retries)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session
def run(self, m3u8_url, tempdir='', workdir='', fname='test'):
self.wdir = workdir
self.tdir = tempdir
self.fname = fname+ '.mp4'
if self.wdir and not os.path.isdir(self.wdir):
os.makedirs(self.wdir)
if self.tdir and not os.path.isdir(self.tdir):
os.makedirs(self.tdir)
r = self.session.get(m3u8_url, timeout=10)
if r.ok:
body = r.text
if body:
ts_list = [urljoin(m3u8_url, n.strip()) for n in body.split('\n') if n and not n.startswith("#")]
total_sum = len(ts_list)
ts_list = zip(ts_list, [n for n in range(len(ts_list))])
if ts_list:
self.ts_total = total_sum
self._download(ts_list)
else:
print(r.status_code)
self._muxing()
def crun(self, m3u8, tempdir='', workdir='', fname='test'):
self.wdir = workdir
self.tdir = tempdir
self.fname = fname+ '.mp4'
if self.wdir and not os.path.isdir(self.wdir):
os.makedirs(self.wdir)
if self.tdir and not os.path.isdir(self.tdir):
os.makedirs(self.tdir)
body = m3u8
if body:
ts_list = [n.strip() for n in body.split('\n') if n and not n.startswith("#")]
total_sum = len(ts_list)
ts_list = zip(ts_list, [n for n in range(len(ts_list))])
if ts_list:
self.ts_total = total_sum
self._download(ts_list)
else:
print("Crun Error!")
self._muxing()
def _muxing(self):
os.chdir(self.tdir)
concat_li = ""
for i in range(self.ts_total):
concat_li += str(i) + ".ts|"
cmd= "ffmpeg -i concat:\""+ concat_li.rstrip("|")+ "\" -c copy \""+ os.path.join(self.wdir, self.fname)+ "\""
os.system(cmd)
os.system("rm ./*")
os.system("ffmpeg -i \""+ os.path.join(self.wdir, self.fname)+ "\"")
def _download(self, ts_list):
self.pool.map(self._worker, ts_list)
if self.failed:
ts_list = self.failed
self.failed = []
self._download(ts_list)
def _worker(self, ts_tuple):
url = ts_tuple[0]
index = ts_tuple[1]
retry = self.retry
while retry:
try:
r = self.session.get(url, timeout=20)
if r.ok:
file_name = str(index)+ ".ts"
print("Downloading:%d/%d " % (index, self.ts_total)+ file_name)
with open(os.path.join(self.tdir, file_name), 'wb') as f:
f.write(r.content)
self.succed[index] = file_name
return
except:
retry -= 1
print('[FAIL]%s' % url)
self.failed.append((url, index))
if __name__ == '__main__':
downloader = Downloader(32)
downloader.run('http://cache.m.iqiyi.com/mus/text/239741901/3f9cd3606562f0f28e8a7897cc4f9a0d/afbe8fd3d73448c9/1402186353/20200320/af/ec/5defd99d5813b899b49754f0d46114e3.m3u8?qd_originate=tmts_py&tvid=14152064500&bossStatus=0&qd_vip=0&px=d63lRWMeJM9dTe7ncU0507bsGFwTXqJhTbN5qHjZctYDqIh4bhJpWBVuwDLQiLY33ua9&src=02022001010000000000&prv=&previewType=&previewTime=&from=&qd_time=1585195697126&qd_p=3cffa0e6&qd_asc=1371879cfc0d1f4a80b552a59d792ade&qypid=14152064500_04000000001000000000_96&qd_k=0bab9b8397d2fcb91a2d694d34ae478f&isdol=0&code=2&ff=f4v&iswb=0&vf=79c02fa5c7b17bfaf8e5935aa015f294&np_tag=nginx_part_tag', 'E:/N_m3u8DL-CLI/temp/', 'E:/N_m3u8DL-CLI/', "123456")
运行
python3 run.py
目前使用时,爱奇艺合并完成后有时会出现帧率不对,所以最后用ffmpeg输出了一下视频信息,如果不一致的话需要重新下载,腾讯视频不存在这个问题。优酷aes-cbc加密的有空再继续写。