예제 #1
0
def get_bangumi_title(media_id: str = "",
                      season_id: str = "",
                      episode_id: str = "") -> str:
    if not (media_id or season_id or episode_id):
        raise ArgumentsError("media_id", "season_id", "episode_id")
    if media_id:
        home_url = "https://www.bilibili.com/bangumi/media/md{media_id}".format(
            media_id=media_id)
        res = spider.get(home_url)
        regex_title = re.compile(
            r'<span class="media-info-title-t">(.*?)</span>')
        if regex_title.search(res.text):
            title = regex_title.search(res.text).group(1)
        else:
            title = "呐,我也不知道是什么标题呢~"
    elif season_id or episode_id:
        if season_id:
            play_url = "https://www.bilibili.com/bangumi/play/ss{season_id}".format(
                season_id=season_id)
        else:
            play_url = "https://www.bilibili.com/bangumi/play/ep{episode_id}".format(
                episode_id=episode_id)
        res = spider.get(play_url)
        regex_title = re.compile(
            r'<a href=".+" target="_blank" title="(.*?)" class="media-title">(?P<title>.*?)</a>'
        )
        if regex_title.search(res.text):
            title = regex_title.search(res.text).group("title")
        else:
            title = "呐,我也不知道是什么标题呢~"
    return title
예제 #2
0
def get_season_id(media_id: str) -> str:
    home_url = "https://www.bilibili.com/bangumi/media/md{media_id}".format(
        media_id=media_id)
    season_id = ""
    regex_season_id = re.compile(
        r'"param":{"season_id":(\d+),"season_type":\d+}')
    if regex_season_id.search(spider.get(home_url).text):
        season_id = regex_season_id.search(spider.get(home_url).text).group(1)
    return str(season_id)
예제 #3
0
def get_subtitle(avid: str = "", bvid: str = "", cid: str = ""):
    if not (avid or bvid):
        raise ArgumentsError("avid", "bvid")
    subtitle_api = "https://api.bilibili.com/x/player.so?id=cid:{cid}&aid={avid}&bvid={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))
    return [
        # fmt: off
        {
            "lang": sub_info["lan_doc"],
            "lines": spider.get("https:" + sub_info["subtitle_url"]).json()["body"]
        }
        for sub_info in subtitles_info["subtitles"]
    ]
예제 #4
0
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
예제 #5
0
def get_bangumi_subtitle(avid: str = "", bvid: str = "", cid: str = ""):
    if not (avid or bvid):
        raise ArgumentsError("avid", "bvid")
    subtitle_api = (
        "https://api.bilibili.com/x/player/v2?cid={cid}&aid={avid}&bvid={bvid}"
    )
    subtitle_url = subtitle_api.format(avid=avid, bvid=bvid, cid=cid)
    subtitles_info = spider.get(subtitle_url).json()["data"]["subtitle"]
    return [
        # fmt: off
        {
            "lang": sub_info["lan_doc"],
            "lines":
            spider.get("https:" + sub_info["subtitle_url"]).json()["body"]
        } for sub_info in subtitles_info["subtitles"]
    ]
예제 #6
0
def get_subtitle(container):
    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"])
예제 #7
0
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
예제 #8
0
파일: danmaku.py 프로젝트: Liqiun/bilili
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)
예제 #9
0
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
예제 #10
0
def get_acg_video_list(avid: str = "", bvid: 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))
    return [
        # fmt: off
        {
            'id': i + 1,
            'name': item['part'],
            'cid': str(item['cid'])
        } for i, item in enumerate(res.json()['data'])
    ]
예제 #11
0
def get_acg_video_title(avid: str = "", bvid: str = "") -> str:
    if not (avid or bvid):
        raise ArgumentsError("avid", "bvid")
    home_url = ("https://www.bilibili.com/video/{bvid}".format(bvid=bvid)
                if bvid else "https://www.bilibili.com/video/av{avid}".format(
                    avid=avid))
    res = spider.get(home_url)
    regex_title = re.compile(
        r"<title .*>(.*)_哔哩哔哩 \(゜-゜\)つロ 干杯~-bilibili</title>")
    if regex_title.search(res.text):
        title = regex_title.search(res.text).group(1)
    else:
        title = "呐,我也不知道是什么标题呢~"
    return title
예제 #12
0
def get_video_info(avid: str = "", bvid: str = ""):
    if not (avid or bvid):
        raise ArgumentsError("avid", "bvid")
    info_api = "http://api.bilibili.com/x/web-interface/view?aid={avid}&bvid={bvid}"
    res = spider.get(info_api.format(avid=avid, bvid=bvid))
    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,
    }
예제 #13
0
def get_bangumi_list(episode_id: str = "", season_id: str = ""):
    if not (season_id or episode_id):
        raise ArgumentsError("season_id", "episode_id")
    list_api = "http://api.bilibili.com/pgc/view/web/season?season_id={season_id}&ep_id={episode_id}"
    res = spider.get(
        list_api.format(episode_id=episode_id, season_id=season_id))
    return [{
        "id":
        i + 1,
        "name":
        " ".join([
            "第{}话".format(item["title"])
            if re.match(r"^\d*\.?\d*$", item["title"]) else item["title"],
            item["long_title"],
        ]),
        "cid":
        str(item["cid"]),
        "episode_id":
        str(item["id"]),
        "avid":
        str(item["aid"]),
        "bvid":
        item["bvid"],
    } for i, item in enumerate(res.json()["result"]["episodes"])]
예제 #14
0
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()
예제 #15
0
def get_danmaku(cid: str) -> str:
    danmaku_api = "http://comment.bilibili.com/{cid}.xml"
    res = spider.get(danmaku_api.format(cid=cid))
    res.encoding = "utf-8"
    return res.text
예제 #16
0
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
예제 #17
0
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))
예제 #18
0
def get_title(home_url):
    res = spider.get(home_url)
    title = re.search(
        r'<title .*>(.*)_哔哩哔哩 \(゜-゜\)つロ 干杯~-bilibili</title>', res.text).group(1)
    return title
예제 #19
0
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)
예제 #20
0
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))