def get_acg_video_playurl( 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" if type == "flv": touch_message = spider.get( play_api.format(avid=avid, bvid=bvid, cid=cid, quality=80)).json() if touch_message["code"] != 0: raise CannotDownloadError(touch_message["code"], touch_message["message"]) accept_quality = touch_message["data"]["accept_quality"] for quality in video_quality_sequence: if quality in accept_quality: break play_url = play_api.format(avid=avid, bvid=bvid, cid=cid, quality=quality) res = spider.get(play_url) return [{ "id": i + 1, "url": segment["url"], "mirrors": segment["backup_url"], "quality": quality, "height": video_quality_map[quality]["height"], "width": video_quality_map[quality]["width"], "size": segment["size"], "type": "flv_segment", } for i, segment in enumerate(res.json()["data"]["durl"])] elif type == "dash": result = [] play_api_dash = play_api + "&fnver=0&fnval=16&fourk=1" touch_message = spider.get( play_api_dash.format(avid=avid, bvid=bvid, cid=cid, quality=video_quality_sequence[0])).json() 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", }) 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 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() if play_info["code"] != 0: raise CannotDownloadError(play_info["code"], play_info["message"]) return [{ "id": 1, "url": play_info["data"]["durl"][0]["url"], "mirrors": [], "quality": play_info["data"]["quality"], "height": video_quality_map[play_info["data"]["quality"]]["height"], "width": video_quality_map[play_info["data"]["quality"]]["width"], "size": play_info["data"]["durl"][0]["size"], "type": "mp4_container", }] else: raise UnknownTypeError(type)
def parse_segments(container, quality_sequence, block_size): 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( container.name, touch_message["message"])) return if touch_message["result"]["is_preview"] == 1: print("warn: {} 为预览版视频".format(container.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, height=quality_map[qn]['height'], width=quality_map[qn]['width'], size=segment["size"], type="segment", block_size=block_size, ) 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, height=video['height'], width=video['width'], size=touch_url(video['base_url'], spider)[0], type="video", block_size=block_size, ) break for audio in play_info['result']['dash']['audio']: container.append_media( id=2, url=audio['base_url'], height=None, width=None, size=touch_url(audio['base_url'], spider)[0], qn=qn, type="audio", block_size=block_size, ) break elif container.format == 'mp4': print("番剧不支持 mp4 format") else: print("Unknown format {}".format(container.format))
def get_bangumi_playurl( avid: str = "", bvid: str = "", episode_id: str = "", cid: str = "", quality: int = 120, audio_quality: int = 30280, type: str = "dash", ): 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/pgc/player/web/playurl?avid={avid}&bvid={bvid}&ep_id={episode_id}&cid={cid}&qn={quality}" if type == "flv": touch_message = spider.get( play_api.format(avid=avid, bvid=bvid, episode_id=episode_id, cid=cid, quality=80)).json() if touch_message["code"] != 0: raise CannotDownloadError(touch_message["code"], touch_message["message"]) if touch_message["result"]["is_preview"] == 1: raise IsPreviewError() accept_quality = touch_message["result"]["accept_quality"] for quality in video_quality_sequence: if quality in accept_quality: break play_url = play_api.format(avid=avid, bvid=bvid, episode_id=episode_id, cid=cid, quality=quality) res = spider.get(play_url) return [{ "id": i + 1, "url": segment["url"], "mirrors": segment["backup_url"], "quality": quality, "height": video_quality_map[quality]["height"], "width": video_quality_map[quality]["width"], "size": segment["size"], "type": "flv_segment", } for i, segment in enumerate(res.json()["result"]["durl"])] elif type == "dash": result = [] play_api_dash = play_api + "&fnver=0&fnval=16&fourk=1" play_info = spider.get( play_api_dash.format(avid=avid, bvid=bvid, episode_id=episode_id, cid=cid, quality=video_quality_sequence[0])).json() if play_info["code"] != 0: raise CannotDownloadError(play_info["code"], play_info["message"]) if play_info["result"].get("dash") is None: raise UnsupportTypeError("dash") if play_info["result"]["is_preview"] == 1: raise IsPreviewError() accept_video_quality = set( [video["id"] for video in play_info["result"]["dash"]["video"]]) for video_quality in video_quality_sequence: if video_quality in accept_video_quality: break else: video_quality = 120 accept_audio_quality = set( [audio["id"] for audio in play_info["result"]["dash"]["audio"]]) for audio_quality in audio_quality_sequence: if audio_quality in accept_audio_quality: break else: audio_quality = 30280 if play_info["result"]["dash"]["video"]: videos = play_info["result"]["dash"]["video"] for video in videos: if video["id"] == video_quality: result.append({ "id": 1, "url": video["base_url"], "mirrors": video["backup_url"], "quality": quality, "height": video["height"], "width": video["width"], "size": touch_url(video["base_url"], spider)[0], "type": "dash_video", }) break if play_info["result"]["dash"]["audio"]: audios = play_info["result"]["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 elif type == "mp4": raise UnsupportTypeError("mp4") else: raise UnknownTypeError()
def parse_segments(container, quality_sequence, block_size): 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, height=quality_map[qn]['height'], width=quality_map[qn]['width'], size=segment["size"], type="segment", block_size=block_size, ) 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('该视频尚不支持 M4S format 哦~') # 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, height=video['height'], width=video['width'], size=touch_url(video['base_url'], spider)[0], type="video", block_size=block_size, ) break for audio in play_info['data']['dash']['audio']: container.append_media( id=2, url=audio['base_url'], height=None, width=None, size=touch_url(audio['base_url'], spider)[0], qn=qn, type="audio", block_size=block_size, ) 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'], height=quality_map[play_info['data']['quality']]['height'], width=quality_map[play_info['data']['quality']]['width'], size=play_info['data']['durl'][0]['size'], type="container", block_size=block_size, ) else: print("Unknown format {}".format(container.format))