Skip to content

Commit

Permalink
♻️ refactor: merge mp4&flv&m4s api
Browse files Browse the repository at this point in the history
  • Loading branch information
SigureMo committed Jul 30, 2020
1 parent 0e5b493 commit 01e441c
Show file tree
Hide file tree
Showing 28 changed files with 697 additions and 1,982 deletions.
File renamed without changes.
148 changes: 148 additions & 0 deletions api/acg_video.py
@@ -0,0 +1,148 @@
import re
import os

from tools import spider
from downloader import BililiContainer
from common.base import repair_filename, touch_dir

info_api = "https://api.bilibili.com/x/player/pagelist?aid={avid}&bvid={bvid}&jsonp=jsonp"
parse_api = "https://api.bilibili.com/x/player/playurl?avid={avid}&cid={cid}&bvid={bvid}&qn={qn}&type=&otype=json"


def get_title(home_url):
res = spider.get(home_url)
title = re.search(
r'<title .*>(.*)_哔哩哔哩 \(゜-゜\)つロ 干杯~-bilibili</title>', res.text).group(1)
return title

def get_context(home_url):
context = {
'avid': '',
'bvid': ''
}

if re.match(r"https?://www.bilibili.com/video/av(\d+)", home_url):
context['avid'] = re.match(
r'https?://www.bilibili.com/video/av(\d+)', home_url).group(1)
elif re.match(r"https?://b23.tv/av(\d+)", home_url):
context['avid'] = re.match(r"https?://b23.tv/av(\d+)", home_url).group(1)
elif re.match(r"https?://www.bilibili.com/video/BV(\w+)", home_url):
context['bvid'] = re.match(
r"https?://www.bilibili.com/video/BV(\w+)", home_url).group(1)
elif re.match(r"https?://b23.tv/BV(\w+)", url):
context['bvid'] = re.match(r"https?://b23.tv/BV(\w+)", home_url).group(1)

return context

def get_containers(context, video_dir, format, playlist=None):
avid, bvid = context['avid'], context['bvid']
containers = []
info_url = info_api.format(avid=avid, bvid=bvid)
res = spider.get(info_url)

for i, item in enumerate(res.json()["data"]):
file_path = os.path.join(video_dir, repair_filename(
'{}.mp4'.format(item["part"])))
if playlist is not None:
playlist.write_path(file_path)
containers.append(BililiContainer(
id=i+1,
name=item["part"],
path=file_path,
meta={
"avid": avid,
"bvid": bvid,
"cid": item["cid"]
},
format=format,
))
if playlist is not None:
playlist.flush()
return containers

def parse_segments(container, quality_sequence):
cid, avid, bvid = container.meta["cid"], container.meta["avid"], container.meta["bvid"]

if container.format == "flv":
# 检查是否可以下载,同时搜索支持的清晰度,并匹配最佳清晰度
touch_message = spider.get(parse_api.format(
avid=avid, cid=cid, bvid=bvid, qn=80)).json()
if touch_message["code"] != 0:
print("warn: 无法下载 {} ,原因: {}".format(
container.name, touch_message["message"]))
return

accept_quality = touch_message['data']['accept_quality']
for qn in quality_sequence:
if qn in accept_quality:
break

parse_url = parse_api.format(avid=avid, cid=cid, bvid=bvid, qn=qn)
res = spider.get(parse_url)

for i, segment in enumerate(res.json()['data']['durl']):
container.append_media(
id=i+1,
url=segment["url"],
qn=qn,
type="segment",
)
elif container.format == "m4s":
# 检查是否可以下载,同时搜索支持的清晰度,并匹配最佳清晰度
parse_api_m4s = parse_api + "&fnver=0&fnval=16&fourk=1"
play_info = spider.get(parse_api_m4s.format(
avid=avid, cid=cid, bvid=bvid, qn=quality_sequence[0])).json()
if play_info["code"] != 0:
print("warn: 无法下载 {} ,原因: {}".format(
container.name, play_info["message"]))
return

if play_info['data'].get('dash') is None:
raise Exception('该视频尚不支持 H5 source 哦~')

# accept_quality = play_info['data']['accept_quality']
accept_quality = set([video['id']
for video in play_info['data']['dash']['video']])
for qn in quality_sequence:
if qn in accept_quality:
break

parse_url = parse_api_m4s.format(avid=avid, cid=cid, bvid=bvid, qn=qn)
play_info = spider.get(parse_url).json()

for video in play_info['data']['dash']['video']:
if video['id'] == qn:
container.append_media(
id=1,
url=video['base_url'],
qn=qn,
type="video"
)
break
for audio in play_info['data']['dash']['audio']:
container.append_media(
id=2,
url=audio['base_url'],
qn=qn,
type="audio"
)
break

elif container.format == 'mp4':
# 检查是否可以下载,同时搜索支持的清晰度,并匹配最佳清晰度
parse_api_mp4 = parse_api + "&platform=html5&high_quality=1"
play_info = spider.get(parse_api_mp4.format(
avid=avid, cid=cid, bvid=bvid, qn=120)).json()
if play_info["code"] != 0:
print("warn: 无法下载 {} ,原因: {}".format(
container.name, play_info["message"]))
return

container.append_media(
id=1,
url=play_info['data']['durl'][0]['url'],
qn=play_info['data']['quality'],
type="audio"
)
else:
print("Unknown format {}".format(container.format))
131 changes: 131 additions & 0 deletions api/bangumi.py
@@ -0,0 +1,131 @@
import re
import os

from tools import spider
from downloader import BililiContainer
from common.base import repair_filename, touch_dir

info_api = "https://api.bilibili.com/pgc/web/season/section?season_id={season_id}"
parse_api = "https://api.bilibili.com/pgc/player/web/playurl?avid={avid}&cid={cid}&qn={qn}&ep_id={ep_id}"


def get_title(home_url):
""" 获取视频标题 """
res = spider.get(home_url)
title = re.search(
r'<span class="media-info-title-t">(.*?)</span>', res.text).group(1)
return title

def get_context(home_url):
context = {
'season_id': '',
}

season_id = re.search(
r'"param":{"season_id":(\d+),"season_type":\d+}', spider.get(home_url).text).group(1)
context['season_id'] = season_id

return context

def get_containers(context, video_dir, format, playlist=None):
season_id = context['season_id']
containers = []
info_url = info_api.format(season_id=season_id)
res = spider.get(info_url)

for i, item in enumerate(res.json()["result"]["main_section"]["episodes"]):
index = item["title"]
if re.match(r'^\d*\.?\d*$', index):
index = '第{}话'.format(index)
name = repair_filename(' '.join([index, item["long_title"]]))
file_path = os.path.join(video_dir, repair_filename(
'{}.mp4'.format(name)))
if playlist is not None:
playlist.write_path(file_path)
containers.append(BililiContainer(
id=i+1,
name=name,
path=file_path,
meta={
"aid": item["aid"],
"cid": item["cid"],
"epid": item["id"],
"bvid": ''
},
format=format,
))
if playlist is not None:
playlist.flush()

return containers

def parse_segments(container, quality_sequence):
aid, cid, ep_id, bvid = container.meta["aid"], container.meta["cid"], container.meta["epid"], container.meta["bvid"]

if container.format == "flv":
# 检查是否可以下载,同时搜索支持的清晰度,并匹配最佳清晰度
touch_message = spider.get(parse_api.format(
avid=aid, cid=cid, ep_id=ep_id, qn=80)).json()
if touch_message["code"] != 0:
print("warn: 无法下载 {} ,原因: {}".format(
video.name, touch_message["message"]))
return
if touch_message["result"]["is_preview"] == 1:
print("warn: {} 为预览版视频".format(video.name))

accept_quality = touch_message['result']['accept_quality']
for qn in quality_sequence:
if qn in accept_quality:
break

parse_url = parse_api.format(avid=aid, cid=cid, ep_id=ep_id, qn=qn)
res = spider.get(parse_url)

for i, segment in enumerate(res.json()['result']['durl']):
container.append_media(
id=i+1,
url=segment["url"],
qn=qn,
type="segment",
)
elif container.format == "m4s":
# 检查是否可以下载,同时搜索支持的清晰度,并匹配最佳清晰度
parse_api_m4s = parse_api + "&fnver=0&fnval=16&fourk=1"
play_info = spider.get(parse_api_m4s.format(
avid=aid, cid=cid, ep_id=ep_id, qn=quality_sequence[0], bvid=bvid)).json()
if play_info["code"] != 0:
print("warn: 无法下载 {} ,原因: {}".format(
container.name, play_info["message"]))
return
if play_info["result"]["is_preview"] == 1:
print("warn: {} 为预览版视频".format(container.name))

# accept_quality = play_info['result']['accept_quality']
accept_quality = set([video['id']
for video in play_info['result']['dash']['video']])
for qn in quality_sequence:
if qn in accept_quality:
break

for video in play_info['result']['dash']['video']:
if video['id'] == qn:
container.append_media(
id=1,
url=video['base_url'],
qn=qn,
type="video"
)
break
for audio in play_info['result']['dash']['audio']:
container.append_media(
id=2,
url=audio['base_url'],
qn=qn,
type="audio"
)
break

elif container.format == 'mp4':
print("番剧不支持 mp4 format")
else:
print("Unknown format {}".format(container.format))
13 changes: 13 additions & 0 deletions api/danmaku.py
@@ -0,0 +1,13 @@
import os
from tools import spider

danmaku_api = "http://comment.bilibili.com/{cid}.xml"

def get_danmaku(container):
# 下载弹幕
danmaku_url = danmaku_api.format(cid=container.meta['cid'])
res = spider.get(danmaku_url)
res.encoding = "utf-8"
danmaku_path = os.path.splitext(container.path)[0] + ".xml"
with open(danmaku_path, "w", encoding="utf-8") as f:
f.write(res.text)
23 changes: 23 additions & 0 deletions api/subtitle.py
@@ -0,0 +1,23 @@
import json
import re
import os
from common.subtitle import Subtitle
from tools import spider
subtitle_api = "https://api.bilibili.com/x/player.so?id=cid:{cid}&aid={avid}&bvid={bvid}"


def get_subtitle(container):
print(container.meta)
cid, avid, bvid = container.meta["cid"], container.meta["avid"], container.meta["bvid"]
# 检查是否有字幕并下载
subtitle_url = subtitle_api.format(avid=avid, cid=cid, bvid=bvid)
res = spider.get(subtitle_url)
subtitles_info = json.loads(
re.search(r"<subtitle>(.+)</subtitle>", res.text).group(1))
for sub_info in subtitles_info["subtitles"]:
sub_path = os.path.splitext(
container.path)[0] + sub_info["lan_doc"] + ".srt"
subtitle = Subtitle(sub_path)
for sub_line in spider.get("https:"+sub_info["subtitle_url"]).json()["body"]:
subtitle.write_line(
sub_line["content"], sub_line["from"], sub_line["to"])

0 comments on commit 01e441c

Please sign in to comment.