Skip to content
This repository has been archived by the owner on Oct 26, 2024. It is now read-only.

✨ add uploader video download support #39

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions bilili/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ def reslove_negetive(value):
return episodes


def main():
def cmdparser():
""" 解析命令行参数并调用相关模块进行下载 """

parser = argparse.ArgumentParser(description="bilili B 站视频、弹幕下载器")
parser.add_argument("url", help="视频主页地址")
parser.add_argument(
Expand Down Expand Up @@ -108,10 +107,13 @@ def main():
parser.add_argument("--use-mirrors", action="store_true", help="启用从多个镜像下载功能")
parser.add_argument("--disable-proxy", action="store_true", help="禁用系统代理")
parser.add_argument("--debug", action="store_true", help="debug 模式")
return parser.parse_args()

args = parser.parse_args()
cookies = {"SESSDATA": args.sess_data}

def main():

args = cmdparser()
cookies = {"SESSDATA": args.sess_data}
config = {
"url": args.url,
"dir": args.dir,
Expand All @@ -131,6 +133,7 @@ def main():
resource_id = {
"avid": "",
"bvid": "",
"spaceid": "",
"episode_id": "",
"season_id": "",
} >> AttrDict()
Expand Down Expand Up @@ -164,6 +167,10 @@ def main():
(season_id_match := regex.bangumi.ss.short.match(args.url)):
season_id = season_id_match.group("season_id")
resource_id.season_id = season_id
elif space_match := regex.acg_video.space.origin.match(args.url):
# from bilili.api.acg_video import get_video_info
spaceid = space_match.group("space_id")
resource_id.spaceid = spaceid
else:
print("视频地址有误!")
sys.exit(1)
Expand All @@ -174,6 +181,12 @@ def main():
elif resource_id.season_id or resource_id.episode_id:
from bilili.parser.bangumi import get_title, get_list, get_playurl
bili_type = "bangumi"
elif resource_id.spaceid:
from bilili.parser.space import get_title,get_list
from bilili.parser.acg_video import get_playurl
bili_type = "acg_space"

print(bili_type)

# 获取标题
spider.set_cookies(config["cookies"])
Expand All @@ -185,10 +198,10 @@ def main():
# 创建所需目录结构
base_dir = touch_dir(os.path.join(config["dir"], repair_filename(title + " - bilibili")))
video_dir = touch_dir(os.path.join(base_dir, "Videos"))

# 获取需要的信息
containers = [BililiContainer(video_dir=video_dir, type=args.type, **video) for video in get_list(resource_id)]

# 解析并过滤不需要的选集
episodes = parse_episodes(config["episodes"], len(containers))
containers, containers_need_filter = [], containers
Expand Down
138 changes: 81 additions & 57 deletions bilili/api/acg_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,25 @@
from bilili.api.exports import export_api


@export_api(route="/space_info")
def get_space_info(spaceid: str = ""):
if not (spaceid):
raise ArgumentsError("spaceid")
info_api = "http://api.bilibili.com/x/space/acc/info?mid={spaceid}&jsonp={jsonp}"
res = spider.get(info_api.format(spaceid=spaceid))
res_json_data = res.json()["data"]
episode_id = ""
if res_json_data.get("redirect_url") and regex_bangumi_ep.match(res_json_data["redirect_url"]):
episode_id = regex_bangumi_ep.match(res_json_data["redirect_url"]).group("episode_id")
return {
"avid": str(res_json_data["aid"]),
"bvid": res_json_data["bvid"],
"picture": res_json_data["pic"],
"episode_id": episode_id,
}



@export_api(route="/video_info")
def get_video_info(avid: str = "", bvid: str = ""):
if not (avid or bvid):
Expand Down Expand Up @@ -49,33 +68,36 @@ def get_acg_video_title(avid: str = "", bvid: str = "") -> str:


@export_api(route="/acg_video/list")
def get_acg_video_list(avid: str = "", bvid: str = ""):
def get_acg_video_list(avid: str = "", bvid: str = "",video_name : str = ""):
if not (avid or bvid):
raise ArgumentsError("avid", "bvid")
list_api = "https://api.bilibili.com/x/player/pagelist?aid={avid}&bvid={bvid}&jsonp=jsonp"
res = spider.get(list_api.format(avid=avid, bvid=bvid))
# print(res.text)
return [
# fmt: off
{
'id': i + 1,
'name': item['part'],
'cid': str(item['cid'])
'video_name': video_name,
"avid": avid,
"bvid": bvid,
'cid': str(item['cid']),
}
for i, item in enumerate(res.json()['data'])
]


@export_api(route="/acg_video/playurl")
def get_acg_video_playurl(
avid: str = "", bvid: str = "", cid: str = "", quality: int = 120, audio_quality: int = 30280, type: str = "dash"
):
avid: str = "", bvid: str = "", cid: str = "", quality: int = 120, audio_quality: int = 30280,
type: str = "dash"):
if not (avid or bvid):
raise ArgumentsError("avid", "bvid")
video_quality_sequence = gen_quality_sequence(quality, type=Media.VIDEO)
audio_quality_sequence = gen_quality_sequence(audio_quality, type=Media.AUDIO)
play_api = (
"https://api.bilibili.com/x/player/playurl?avid={avid}&bvid={bvid}&cid={cid}&qn={quality}&type=&otype=json"
)
"https://api.bilibili.com/x/player/playurl?avid={avid}&bvid={bvid}&cid={cid}&qn={quality}&type=&otype=json")
if type == "flv":
touch_message = spider.get(play_api.format(avid=avid, bvid=bvid, cid=cid, quality=80)).json()
if touch_message["code"] != 0:
Expand Down Expand Up @@ -111,60 +133,62 @@ def get_acg_video_playurl(

if touch_message["code"] != 0:
raise CannotDownloadError(touch_message["code"], touch_message["message"])
if touch_message["data"].get("dash") is None:
raise UnsupportTypeError("dash")

video_accept_quality = set([video["id"] for video in touch_message["data"]["dash"]["video"]])
for video_quality in video_quality_sequence:
if video_quality in video_accept_quality:
break
else:
video_quality = 120

audio_accept_quality = set([audio["id"] for audio in touch_message["data"]["dash"]["audio"]])
for audio_quality in audio_quality_sequence:
if audio_quality in audio_accept_quality:
break
else:
audio_quality = 30280

res = spider.get(play_api_dash.format(avid=avid, bvid=bvid, cid=cid, quality=quality))

if res.json()["data"]["dash"]["video"]:
videos = res.json()["data"]["dash"]["video"]
for video in videos:
if video["id"] == video_quality:
result.append(
{
"id": 1,
"url": video["base_url"],
"mirrors": video["backup_url"],
"quality": video_quality,
"height": video["height"],
"width": video["width"],
"size": touch_url(video["base_url"], spider)[0],
"type": "dash_video",
}
)
if touch_message["data"].get("dash") is not None:
video_accept_quality = set([video["id"] for video in touch_message["data"]["dash"]["video"]])
for video_quality in video_quality_sequence:
if video_quality in video_accept_quality:
break
if res.json()["data"]["dash"]["audio"]:
audios = res.json()["data"]["dash"]["audio"]
for audio in audios:
if audio["id"] == audio_quality:
result.append(
{
"id": 2,
"url": audio["base_url"],
"mirrors": audio["backup_url"],
"quality": audio_quality,
"height": None,
"width": None,
"size": touch_url(audio["base_url"], spider)[0],
"type": "dash_audio",
}
)
else:
video_quality = 120

audio_accept_quality = set([audio["id"] for audio in touch_message["data"]["dash"]["audio"]])
for audio_quality in audio_quality_sequence:
if audio_quality in audio_accept_quality:
break
return result
else:
audio_quality = 30280

res = spider.get(play_api_dash.format(avid=avid, bvid=bvid, cid=cid, quality=quality))

if res.json()["data"]["dash"]["video"]:
videos = res.json()["data"]["dash"]["video"]
for video in videos:
if video["id"] == video_quality:
result.append(
{
"id": 1,
"url": video["base_url"],
"mirrors": video["backup_url"],
"quality": video_quality,
"height": video["height"],
"width": video["width"],
"size": touch_url(video["base_url"], spider)[0],
"type": "dash_video",
}
)
break
if res.json()["data"]["dash"]["audio"]:
audios = res.json()["data"]["dash"]["audio"]
for audio in audios:
if audio["id"] == audio_quality:
result.append(
{
"id": 2,
"url": audio["base_url"],
"mirrors": audio["backup_url"],
"quality": audio_quality,
"height": None,
"width": None,
"size": touch_url(audio["base_url"], spider)[0],
"type": "dash_audio",
}
)
break
return result
else:
get_acg_video_playurl(avid=avid, bvid=bvid, cid=cid, quality=quality, audio_quality=audio_quality,
type="flv")
elif type == "mp4":
play_api_mp4 = play_api + "&platform=html5&high_quality=1"
play_info = spider.get(play_api_mp4.format(avid=avid, bvid=bvid, cid=cid, quality=120)).json()
Expand Down
52 changes: 52 additions & 0 deletions bilili/api/space.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import re,time

from bilili.tools import spider
from bilili.quality import gen_quality_sequence, video_quality_map, Media
from bilili.utils.base import touch_url

from bilili.api.exports import export_api


@export_api(route="/space/title")
def get_space_title(spaceid: str = "") -> str:
if not (spaceid):
raise Exception(spaceid +"不存在")
home_url = (
"https://space.bilibili.com/{spaceid}/".format(spaceid=spaceid)
)
res = spider.get(home_url)
regex_title = re.compile(r"<title>(.*)的个人空间.*?</title>")
if regex_title.search(res.text):
title = regex_title.search(res.text).group(1)
else:
title = "呐,我也不知道是什么标题呢~"
return title

@export_api(route="/space/title")
def get_space_video(mid: str = "" ,pn=1) -> str:
if not (mid):
raise Exception(mid +"不存在")
list_api = "https://api.bilibili.com/x/space/arc/search?mid={mid}&pn={pn}&ps=100&jsonp=jsonp"
album_list = []
while True:
res = spider.get(list_api.format(mid=mid, pn=pn))
# 循环获取列表
album_list.extend(
[
{
"id": i + 1,
"name": re.sub(r"[\/\\\:\*\?\"\<\>\|]", "", item["title"]),
"avid": str(item["aid"]),
"bvid": item["bvid"],
}
for i,item in enumerate(res.json()["data"]["list"]["vlist"])
]
)
if len(album_list) < int(res.json()['data']["page"]['count']):
pn += 1
else:
break


# 返回视频列表
return album_list
1 change: 1 addition & 0 deletions bilili/parser/acg_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def get_title(resource_id):

def get_list(resource_id):
video_list = get_acg_video_list(avid=resource_id.avid, bvid=resource_id.bvid)

return [
{
"id": video["id"],
Expand Down
32 changes: 32 additions & 0 deletions bilili/parser/space.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import os
from bilili.api.space import get_space_title,get_space_video
from bilili.api.acg_video import get_acg_video_list


def get_title(resource_id):
return get_space_title(spaceid=resource_id.spaceid)


def get_list(resource_id):
space_video_list = get_space_video(mid=resource_id.spaceid)
video_list=[]
for video in space_video_list:
for list in get_acg_video_list(avid=video["avid"], bvid=video["bvid"],video_name =video["name"]):
video_list.append(list)

# print(video_list)

return [
{
"id": video["id"],
"name": video["name"],
"video_name": video["video_name"],
# fmt: off
"meta": {
"avid": video["avid"],
"bvid": video["bvid"],
"cid": video["cid"]
},
}
for video in video_list
]
16 changes: 11 additions & 5 deletions bilili/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,27 @@


# avid
regex_acg_video_av = re.compile(r"https?://(www\.|m\.)?bilibili\.com/video/av(?P<avid>\d+)")
regex_acg_video_av = re.compile(r".*?av(?P<avid>\d+)")
regex_acg_video_av_short = re.compile(r"https?://b23\.tv/av(?P<avid>\d+)")

# bvid
regex_acg_video_bv = re.compile(r"https?://(www\.|m\.)?bilibili\.com/video/(?P<bvid>(bv|BV)\w+)")
regex_acg_video_bv = re.compile(r".*?(?P<bvid>(bv|BV)\w+)")
regex_acg_video_bv_short = re.compile(r"https?://b23\.tv/(?P<bvid>(bv|BV)\w+)")

# media id
regex_bangumi_md = re.compile(r"https?://(www\.|m\.)?bilibili\.com/bangumi/media/md(?P<media_id>\d+)")
regex_bangumi_md = re.compile(r".*?/bangumi/media/md(?P<media_id>\d+)")

# episode id
regex_bangumi_ep = re.compile(r"https?://(www\.|m\.)?bilibili\.com/bangumi/play/ep(?P<episode_id>\d+)")
regex_bangumi_ep = re.compile(r".*?/bangumi/play/ep(?P<episode_id>\d+)")
regex_bangumi_ep_short = re.compile(r"https?://b23\.tv/ep(?P<episode_id>\d+)")

# season id
regex_bangumi_ss = re.compile(r"https?://(www\.|m\.)?bilibili\.com/bangumi/play/ss(?P<season_id>\d+)")
regex_bangumi_ss = re.compile(r".*?/bangumi/play/ss(?P<season_id>\d+)")
regex_bangumi_ss_short = re.compile(r"https?://b23\.tv/ss(?P<season_id>\d+)")

#space ID
regex_sapce = re.compile(r".*?space\.bilibili\.com/(?P<space_id>\d+)")


spider = BililiCrawler()
ass = ASS()
Expand All @@ -40,6 +43,9 @@
"origin": regex_acg_video_bv,
"short": regex_acg_video_bv_short,
},
"space":{
"origin": regex_sapce,
},
},
"bangumi": {
"md": {
Expand Down
Loading