diff --git a/README.md b/README.md index 14f2c43b..4d40879a 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ ## 依赖环境 Environment 1. Python 相关依赖(需要python3.8及以上) ```shell -pip install 'httpx[http2]' rich json5 +pip install 'httpx[http2]' rich json5 protobuf ``` 2. [FFmpeg](https://ffmpeg.org/contact.html#MailingLists) :一个命令行视频工具,用于合成下载的音频和视频 @@ -127,7 +127,7 @@ asyncio.run(main()) - [x] 下载视频封面 - [ ] 每日测试(GitHub Action),但目前Github Action不能正常访问b站? - [x] 支持下载字幕,目前已支持下载json,以及转换成srt格式 -- [ ] 支持弹幕下载 +- [ ] 支持弹幕下载,目前已支持下载protobuf的的弹幕文件,各位可以在[issue](https://github.com/HFrost0/Lighting-bilibili-download/issues/7)中讨论这个问题 - [ ] 支持直播录播,在`live.py`中有获取m3u8的例子,但已考虑废弃,因为有更多专精的优质仓库解决此问题 ### 已知的bug 🤡 * 出现未被正常捕捉的异常后断点重连可能导致视频画面或者音频部分缺失(例如突然拉闸😅) diff --git a/all_test.py b/all_test.py deleted file mode 100644 index 521d7798..00000000 --- a/all_test.py +++ /dev/null @@ -1,25 +0,0 @@ -import pytest -from lighting_downloader import Downloader - - -@pytest.mark.asyncio -async def test_get_series(): - d = Downloader() - await d.get_series('https://www.bilibili.com/video/BV1sa411b786') - await d.aclose() - - -@pytest.mark.asyncio -async def test_get_up(): - d = Downloader() - await d.get_up_videos('436482484', total=1) - await d.aclose() - - -@pytest.mark.asyncio -async def test_get_cate(): - d = Downloader() - await d.get_cate_videos('宅舞', num=1) - await d.aclose() - - diff --git a/bili_cmd.py b/bili_cmd.py index d5a12541..42c4c819 100644 --- a/bili_cmd.py +++ b/bili_cmd.py @@ -6,10 +6,10 @@ async def main(args): d = Downloader(videos_dir=args.dir, video_concurrency=args.max_con, sess_data=args.cookie) if args.method == 'get_series': - await d.get_series(args.key, quality=args.q, image=args.image, subtitle=args.subtitle, + await d.get_series(args.key, quality=args.q, image=args.image, subtitle=args.subtitle, dm=args.dm, only_audio=args.only_audio) elif args.method == 'get_video': - await d.get_video(args.key, quality=args.q, image=args.image, subtitle=args.subtitle, + await d.get_video(args.key, quality=args.q, image=args.image, subtitle=args.subtitle, dm=args.dm, only_audio=args.only_audio) elif args.method == 'get_up': await d.get_up_videos( @@ -57,6 +57,7 @@ async def main(args): # todo support in search parser.add_argument('--image', action='store_true', default=False, help='下载视频封面,暂时仅get_series,get_video时生效') parser.add_argument('--subtitle', action='store_true', default=False, help='下载srt字幕,暂时仅get_series,get_video时生效') + parser.add_argument('--dm', action='store_true', default=False, help='下载弹幕,暂时仅get_series,get_video时生效') parser.add_argument('--only_audio', action='store_true', default=False, help='仅下载音频,下载的音质固定为最高音质,暂时仅get_series,get_video时生效') diff --git a/dm/__init__.py b/dm/__init__.py new file mode 100644 index 00000000..970d118d --- /dev/null +++ b/dm/__init__.py @@ -0,0 +1,18 @@ +import json +from google.protobuf.json_format import MessageToJson +from .reply_pb2 import DmSegMobileReply +from .view_pb2 import DmWebViewReply + + +def parse_view(content): + dm_view = DmWebViewReply() + dm_view.ParseFromString(content) + dm_view = json.loads(MessageToJson(dm_view)) + return dm_view + + +def parse_seg(content): + seg = DmSegMobileReply() + seg.ParseFromString(content) + seg = json.loads(MessageToJson(seg)) + return seg diff --git a/dm/reply.proto b/dm/reply.proto new file mode 100644 index 00000000..9423ebba --- /dev/null +++ b/dm/reply.proto @@ -0,0 +1,462 @@ +// from https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/danmaku +syntax = "proto3"; + +package bilibili.community.service.dm.v1; + +//弹幕 +service DM { + // 获取分段弹幕 + rpc DmSegMobile (DmSegMobileReq) returns (DmSegMobileReply); + // 客户端弹幕元数据 字幕、分段、防挡蒙版等 + rpc DmView (DmViewReq) returns (DmViewReply); + // 修改弹幕配置 + rpc DmPlayerConfig (DmPlayerConfigReq) returns (Response); + // ott弹幕列表 + rpc DmSegOtt(DmSegOttReq) returns(DmSegOttReply); + // SDK弹幕列表 + rpc DmSegSDK(DmSegSDKReq) returns(DmSegSDKReply); +} + +// 弹幕SDK-请求 +message DmSegSDKReq { + // 稿件avid/漫画epid + int64 pid = 1; + // 视频cid/漫画cid + int64 oid = 2; + // 弹幕类型 + // 1:视频 2:漫画 + int32 type = 3; + // 分段(6min) + int64 segment_index = 4; +} + +// 弹幕SDK-响应 +message DmSegSDKReply { + // 是否已关闭弹幕 + // 0:未关闭 1:已关闭 + bool closed = 1; + // 弹幕列表 + repeated DanmakuElem elems = 2; +} + +// ott弹幕列表-请求 +message DmSegOttReq { + // 稿件avid/漫画epid + int64 pid = 1; + // 视频cid/漫画cid + int64 oid = 2; + // 弹幕类型 + // 1:视频 2:漫画 + int32 type = 3; + // 分段(6min) + int64 segment_index = 4; +} + +// ott弹幕列表-响应 +message DmSegOttReply { + // 是否已关闭弹幕 + // 0:未关闭 1:已关闭 + bool closed = 1; + // 弹幕列表 + repeated DanmakuElem elems = 2; +} + +// 获取弹幕-请求 +message DmSegMobileReq { + // 稿件avid/漫画epid + int64 pid = 1; + // 视频cid/漫画cid + int64 oid = 2; + // 弹幕类型 + // 1:视频 2:漫画 + int32 type = 3; + // 分段(6min) + int64 segment_index = 4; + // 是否青少年模式 + int32 teenagers_mode = 5; +} + +// 获取弹幕-响应 +message DmSegMobileReply { + // 弹幕列表 + repeated DanmakuElem elems = 1; + // 是否已关闭弹幕 + // 0:未关闭 1:已关闭 + int32 state = 2; + // 弹幕云屏蔽ai评分值 + DanmakuAIFlag ai_flag = 3; +} + +// 客户端弹幕元数据-请求 +message DmViewReq { + // 稿件avid/漫画epid + int64 pid = 1; + // 视频cid/漫画cid + int64 oid = 2; + // 弹幕类型 + // 1:视频 2:漫画 + int32 type = 3; + // 页面spm + string spmid = 4; + // 是否冷启 + int32 is_hard_boot = 5; +} + +// 客户端弹幕元数据-响应 +message DmViewReply { + // 是否已关闭弹幕 + // 0:未关闭 1:已关闭 + bool closed = 1; + // 智能防挡弹幕蒙版信息 + VideoMask mask = 2; + // 视频字幕 + VideoSubtitle subtitle = 3; + // 高级弹幕专包url(bfs) + repeated string special_dms = 4; + // 云屏蔽配置信息 + DanmakuFlagConfig ai_flag = 5; + // 弹幕配置信息 + DanmuPlayerViewConfig player_config = 6; + // 弹幕发送框样式 + int32 send_box_style = 7; + // 是否允许 + bool allow = 8; + // check box 是否展示 + string check_box = 9; + // check box 展示文本 + string check_box_show_msg = 10; + // 展示文案 + string text_placeholder = 11; + // 弹幕输入框文案 + string input_placeholder = 12; + // 用户举报弹幕 cid维度屏蔽的正则规则 + repeated string report_filter_content = 13; +} + +// web端弹幕元数据-响应 +message DmWebViewReply { + // 是否已关闭弹幕 + // 0:未关闭 1:已关闭 + int32 state = 1; + // + string text = 2; + // + string text_side = 3; + // 分段弹幕配置 + DmSegConfig dm_sge = 4; + // 云屏蔽配置信息 + DanmakuFlagConfig flag = 5; + // 高级弹幕专包url(bfs) + repeated string special_dms = 6; + // check box 是否展示 + bool check_box = 7; + // 弹幕数 + int64 count = 8; + // 互动弹幕 + repeated CommandDm commandDms = 9; + // 用户弹幕配置 + DanmuWebPlayerConfig player_config = 10; + // 用户举报弹幕 cid维度屏蔽 + repeated string report_filter_content = 11; +} + +// 互动弹幕条目信息 +message CommandDm { + // 弹幕id + int64 id = 1; + // 对象视频cid + int64 oid = 2; + // 发送者mid + string mid = 3; + // 互动弹幕指令 + string command = 4; + // 互动弹幕正文 + string content = 5; + // 出现时间 + int32 progress = 6; + // 创建时间 + string ctime = 7; + // 发布时间 + string mtime = 8; + // 扩展json数据 + string extra = 9; + // 弹幕id str类型 + string idStr = 10; +} + +// +message DmSegConfig { + // + int64 page_size = 1; + // + int64 total = 2; +} + +// 智能防挡弹幕蒙版信息 +message VideoMask { + // 视频cid + int64 cid = 1; + // 平台 + // 0:web端 1:客户端 + int32 plat = 2; + // 帧率 + int32 fps = 3; + // 间隔时间 + int64 time = 4; + // 蒙版url + string mask_url = 5; +} + +// 视频字幕信息 +message VideoSubtitle { + // 视频原语言代码 + string lan = 1; + // 视频原语言 + string lanDoc = 2; + // 视频字幕列表 + repeated SubtitleItem subtitles = 3; +} + +// web端用户弹幕配置 +message DanmuWebPlayerConfig { + bool dm_switch = 1; // 是否开启弹幕 + bool ai_switch = 2; // 是否开启智能云屏蔽 + int32 ai_level = 3; // 智能云屏蔽等级 + bool blocktop = 4; // 是否屏蔽顶端弹幕 + bool blockscroll = 5; // 是否屏蔽滚动弹幕 + bool blockbottom = 6; // 是否屏蔽底端弹幕 + bool blockcolor = 7; // 是否屏蔽彩色弹幕 + bool blockspecial = 8; // 是否屏蔽重复弹幕 + bool preventshade = 9; // + bool dmask = 10; // + float opacity = 11; // + int32 dmarea = 12; // + float speedplus = 13; // + float fontsize = 14; // 弹幕字号 + bool screensync = 15; // + bool speedsync = 16; // + string fontfamily = 17; // + bool bold = 18; // 是否使用加粗 + int32 fontborder = 19; // + string draw_type = 20; // 弹幕渲染类型 +} + +// 单个字幕信息 +message SubtitleItem { + // 字幕id + int64 id = 1; + // 字幕id str + string id_str = 2; + // 字幕语言代码 + string lan = 3; + // 字幕语言 + string lan_doc = 4; + // 字幕文件url + string subtitle_url = 5; + // 字幕作者信息 + UserInfo author = 6; +} + +// 字幕作者信息 +message UserInfo { + // 用户mid + int64 mid = 1; + // 用户昵称 + string name = 2; + // 用户性别 + string sex = 3; + // 用户头像url + string face = 4; + // 用户签名 + string sign = 5; + // 用户等级 + int32 rank = 6; +} + +// 弹幕条目 +message DanmakuElem { + // 弹幕dmid + int64 id = 1; + // 弹幕出现位置(单位ms) + int32 progress = 2; + // 弹幕类型 + int32 mode = 3; + // 弹幕字号 + int32 fontsize = 4; + // 弹幕颜色 + uint32 color = 5; + // 发送着mid hash + string midHash = 6; + // 弹幕正文 + string content = 7; + // 发送时间 + int64 ctime = 8; + // 权重 区间:[1,10] + int32 weight = 9; + // 动作 + string action = 10; + // 弹幕池 + int32 pool = 11; + // 弹幕dmid str + string idStr = 12; + // 弹幕属性位(bin求AND) + // bit0:保护 bit1:直播 bit2:高赞 + int32 attr = 13; +} + +// 弹幕属性位值 +enum DMAttrBit { + // 保护弹幕 + DMAttrBitProtect = 0; + // 直播弹幕 + DMAttrBitFromLive = 1; + // 高赞弹幕 + DMAttrHighLike = 2; +} + +// 修改弹幕配置-请求 +message DmPlayerConfigReq { + int64 ts = 1; // + PlayerDanmakuSwitch switch = 2; // 是否开启弹幕 + PlayerDanmakuSwitchSave switch_save = 3; // 是否记录弹幕开关设置 + PlayerDanmakuUseDefaultConfig use_default_config = 4; // 是否使用推荐弹幕设置 + PlayerDanmakuAiRecommendedSwitch ai_recommended_switch = 5; // 是否开启智能云屏蔽 + PlayerDanmakuAiRecommendedLevel ai_recommended_level = 6; // 智能云屏蔽等级 + PlayerDanmakuBlocktop blocktop = 7; // 是否屏蔽顶端弹幕 + PlayerDanmakuBlockscroll blockscroll = 8; // 是否屏蔽滚动弹幕 + PlayerDanmakuBlockbottom blockbottom = 9; // 是否屏蔽底端弹幕 + PlayerDanmakuBlockcolorful blockcolorful = 10; // 是否屏蔽彩色弹幕 + PlayerDanmakuBlockrepeat blockrepeat = 11; // 是否屏蔽重复弹幕 + PlayerDanmakuBlockspecial blockspecial = 12; // 是否屏蔽高级弹幕 + PlayerDanmakuOpacity opacity = 13; // 弹幕不透明度 + PlayerDanmakuScalingfactor scalingfactor = 14; // 弹幕缩放比例 + PlayerDanmakuDomain domain = 15; // 弹幕显示区域 + PlayerDanmakuSpeed speed = 16; // 弹幕速度 + PlayerDanmakuEnableblocklist enableblocklist = 17; // 是否开启屏蔽列表 + InlinePlayerDanmakuSwitch inlinePlayerDanmakuSwitch = 18; // 是否开启弹幕 +} + +// 修改弹幕配置-响应 +message Response { + // + int32 code = 1; + // + string message = 2; +} + +// 弹幕ai云屏蔽条目 +message DanmakuFlag { + // 弹幕dmid + int64 dmid = 1; + // 评分 + uint32 flag = 2; +} + +// 云屏蔽配置信息 +message DanmakuFlagConfig { + // 云屏蔽等级 + int32 rec_flag = 1; + // 云屏蔽文案 + string rec_text = 2; + // 云屏蔽开关 + int32 rec_switch = 3; +} + +// 弹幕ai云屏蔽列表 +message DanmakuAIFlag { + // 弹幕ai云屏蔽条目 + repeated DanmakuFlag dm_flags = 1; +} + +// 弹幕配置信息 +message DanmuPlayerViewConfig { + // 弹幕默认配置 + DanmuDefaultPlayerConfig danmuku_default_player_config = 1; + // 弹幕用户配置 + DanmuPlayerConfig danmuku_player_config = 2; + // 弹幕显示区域自动配置列表 + repeated DanmuPlayerDynamicConfig danmuku_player_dynamic_config = 3; +} + +// 弹幕默认配置 +message DanmuDefaultPlayerConfig { + bool player_danmaku_use_default_config = 1; // 是否使用推荐弹幕设置 + bool player_danmaku_ai_recommended_switch = 4; // 是否开启智能云屏蔽 + int32 player_danmaku_ai_recommended_level = 5; // 智能云屏蔽等级 + bool player_danmaku_blocktop = 6; // 是否屏蔽顶端弹幕 + bool player_danmaku_blockscroll = 7; // 是否屏蔽滚动弹幕 + bool player_danmaku_blockbottom = 8; // 是否屏蔽底端弹幕 + bool player_danmaku_blockcolorful = 9; // 是否屏蔽彩色弹幕 + bool player_danmaku_blockrepeat = 10; // 是否屏蔽重复弹幕 + bool player_danmaku_blockspecial = 11; // 是否屏蔽高级弹幕 + float player_danmaku_opacity = 12; // 弹幕不透明度 + float player_danmaku_scalingfactor = 13; // 弹幕缩放比例 + float player_danmaku_domain = 14; // 弹幕显示区域 + int32 player_danmaku_speed = 15; // 弹幕速度 + bool inline_player_danmaku_switch = 16; // 是否开启弹幕 +} + +// 弹幕配置 +message DanmuPlayerConfig { + bool player_danmaku_switch = 1; // 是否开启弹幕 + bool player_danmaku_switch_save = 2; // 是否记录弹幕开关设置 + bool player_danmaku_use_default_config = 3; // 是否使用推荐弹幕设置 + bool player_danmaku_ai_recommended_switch = 4; // 是否开启智能云屏蔽 + int32 player_danmaku_ai_recommended_level = 5; // 智能云屏蔽等级 + bool player_danmaku_blocktop = 6; // 是否屏蔽顶端弹幕 + bool player_danmaku_blockscroll = 7; // 是否屏蔽滚动弹幕 + bool player_danmaku_blockbottom = 8; // 是否屏蔽底端弹幕 + bool player_danmaku_blockcolorful = 9; // 是否屏蔽彩色弹幕 + bool player_danmaku_blockrepeat = 10; // 是否屏蔽重复弹幕 + bool player_danmaku_blockspecial = 11; // 是否屏蔽高级弹幕 + float player_danmaku_opacity = 12; // 弹幕不透明度 + float player_danmaku_scalingfactor = 13; // 弹幕缩放比例 + float player_danmaku_domain = 14; // 弹幕显示区域 + int32 player_danmaku_speed = 15; // 弹幕速度 + bool player_danmaku_enableblocklist = 16; // 是否开启屏蔽列表 + bool inline_player_danmaku_switch = 17; // 是否开启弹幕 + int32 inline_player_danmaku_config = 18; // +} + +// 弹幕显示区域自动配置 +message DanmuPlayerDynamicConfig { + // 时间 + int32 progress = 1; + // 弹幕显示区域 + float player_danmaku_domain = 2; +} + +// 是否开启弹幕 +message PlayerDanmakuSwitch {bool value = 1;bool canIgnore = 2;} +// 是否记录弹幕开关设置 +message PlayerDanmakuSwitchSave {bool value = 1;} +// 是否使用推荐弹幕设置 +message PlayerDanmakuUseDefaultConfig {bool value = 1;} +// 是否开启智能云屏蔽 +message PlayerDanmakuAiRecommendedSwitch {bool value = 1;} +// 智能云屏蔽等级 +message PlayerDanmakuAiRecommendedLevel {bool value = 1;} +// 是否屏蔽顶端弹幕 +message PlayerDanmakuBlocktop {bool value = 1;} +// 是否屏蔽滚动弹幕 +message PlayerDanmakuBlockscroll {bool value = 1;} +// 是否屏蔽底端弹幕 +message PlayerDanmakuBlockbottom {bool value = 1;} +// 是否屏蔽彩色弹幕 +message PlayerDanmakuBlockcolorful {bool value = 1;} +// 是否屏蔽重复弹幕 +message PlayerDanmakuBlockrepeat {bool value = 1;} +// 是否屏蔽高级弹幕 +message PlayerDanmakuBlockspecial {bool value = 1;} +// 弹幕不透明度 +message PlayerDanmakuOpacity {float value = 1;} +// 弹幕缩放比例 +message PlayerDanmakuScalingfactor {float value = 1;} +// 弹幕显示区域 +message PlayerDanmakuDomain {float value = 1;} +// 弹幕速度 +message PlayerDanmakuSpeed {int32 value = 1;} +// 是否开启屏蔽列表 +message PlayerDanmakuEnableblocklist {bool value = 1;} +// 是否开启弹幕 +message InlinePlayerDanmakuSwitch {bool value = 1;} \ No newline at end of file diff --git a/dm/reply_pb2.py b/dm/reply_pb2.py new file mode 100644 index 00000000..955fcdac --- /dev/null +++ b/dm/reply_pb2.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: reply.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='reply.proto', + package='dm', + syntax='proto3', + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\x0breply.proto\x12\x02\x64m\"2\n\x10\x44mSegMobileReply\x12\x1e\n\x05\x65lems\x18\x01 \x03(\x0b\x32\x0f.dm.DanmakuElem\"\xc8\x01\n\x0b\x44\x61nmakuElem\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08progress\x18\x02 \x01(\x05\x12\x0c\n\x04mode\x18\x03 \x01(\x05\x12\x10\n\x08\x66ontsize\x18\x04 \x01(\x05\x12\r\n\x05\x63olor\x18\x05 \x01(\r\x12\x0f\n\x07midHash\x18\x06 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x07 \x01(\t\x12\r\n\x05\x63time\x18\x08 \x01(\x03\x12\x0e\n\x06weight\x18\t \x01(\x05\x12\x0e\n\x06\x61\x63tion\x18\n \x01(\t\x12\x0c\n\x04pool\x18\x0b \x01(\x05\x12\r\n\x05idStr\x18\x0c \x01(\tb\x06proto3' +) + + + + +_DMSEGMOBILEREPLY = _descriptor.Descriptor( + name='DmSegMobileReply', + full_name='dm.DmSegMobileReply', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='elems', full_name='dm.DmSegMobileReply.elems', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=19, + serialized_end=69, +) + + +_DANMAKUELEM = _descriptor.Descriptor( + name='DanmakuElem', + full_name='dm.DanmakuElem', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='id', full_name='dm.DanmakuElem.id', index=0, + number=1, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='progress', full_name='dm.DanmakuElem.progress', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='mode', full_name='dm.DanmakuElem.mode', index=2, + number=3, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='fontsize', full_name='dm.DanmakuElem.fontsize', index=3, + number=4, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='color', full_name='dm.DanmakuElem.color', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='midHash', full_name='dm.DanmakuElem.midHash', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='content', full_name='dm.DanmakuElem.content', index=6, + number=7, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='ctime', full_name='dm.DanmakuElem.ctime', index=7, + number=8, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='weight', full_name='dm.DanmakuElem.weight', index=8, + number=9, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='action', full_name='dm.DanmakuElem.action', index=9, + number=10, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='pool', full_name='dm.DanmakuElem.pool', index=10, + number=11, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='idStr', full_name='dm.DanmakuElem.idStr', index=11, + number=12, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=72, + serialized_end=272, +) + +_DMSEGMOBILEREPLY.fields_by_name['elems'].message_type = _DANMAKUELEM +DESCRIPTOR.message_types_by_name['DmSegMobileReply'] = _DMSEGMOBILEREPLY +DESCRIPTOR.message_types_by_name['DanmakuElem'] = _DANMAKUELEM +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +DmSegMobileReply = _reflection.GeneratedProtocolMessageType('DmSegMobileReply', (_message.Message,), { + 'DESCRIPTOR' : _DMSEGMOBILEREPLY, + '__module__' : 'reply_pb2' + # @@protoc_insertion_point(class_scope:dm.DmSegMobileReply) + }) +_sym_db.RegisterMessage(DmSegMobileReply) + +DanmakuElem = _reflection.GeneratedProtocolMessageType('DanmakuElem', (_message.Message,), { + 'DESCRIPTOR' : _DANMAKUELEM, + '__module__' : 'reply_pb2' + # @@protoc_insertion_point(class_scope:dm.DanmakuElem) + }) +_sym_db.RegisterMessage(DanmakuElem) + + +# @@protoc_insertion_point(module_scope) diff --git a/dm/view.proto b/dm/view.proto new file mode 100644 index 00000000..ccbff6be --- /dev/null +++ b/dm/view.proto @@ -0,0 +1,66 @@ +// from https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/danmaku +syntax = "proto3"; + +//分段弹幕包信息? +message DmSegConfig { + int64 pageSize = 1; //分段时间? + int64 total = 2; //最大分页数? +} + +// +message DanmakuFlagConfig { + int32 recFlag = 1; // + string recText = 2; // + int32 recSwitch = 3; // +} + +// 互动弹幕条目 +message CommandDm { + int64 id = 1; //弹幕dmid + int64 oid = 2; //视频cid + int64 mid = 3; //发送者mid + string command = 4; //弹幕指令 + string content = 5; //弹幕文字 + int32 progress = 6; //弹幕出现时间 + string ctime = 7; // + string mtime = 8; // + string extra = 9; //弹幕负载数据 + string idStr = 10; //弹幕dmid(字串形式) +} + +//弹幕个人配置 +message DanmuWebPlayerConfig{ + bool dmSwitch=1; //弹幕开关 + bool aiSwitch=2; //智能云屏蔽 + int32 aiLevel=3; //智能云屏蔽级别 + bool blocktop=4; //屏蔽类型-顶部 + bool blockscroll=5; //屏蔽类型-滚动 + bool blockbottom=6; //屏蔽类型-底部 + bool blockcolor=7; //屏蔽类型-彩色 + bool blockspecial=8; //屏蔽类型-特殊 + bool preventshade=9; //防挡弹幕(底部15%) + bool dmask=10; //智能防挡弹幕(人像蒙版) + float opacity=11; //弹幕不透明度 + int32 dmarea=12; //弹幕显示区域 + float speedplus=13; //弹幕速度 + float fontsize=14; //字体大小 + bool screensync=15; //跟随屏幕缩放比例 + bool speedsync=16; //根据播放倍速调整速度 + string fontfamily=17; //字体类型? + bool bold=18; //粗体? + int32 fontborder=19; //描边类型 + string drawType=20; //渲染类型? +} + +message DmWebViewReply { + int32 state = 1; //弹幕开放状态 + string text = 2; // + string textSide = 3; // + DmSegConfig dmSge = 4; //分段弹幕包信息? + DanmakuFlagConfig flag = 5; // + repeated string specialDms = 6; //BAS(代码)弹幕专包url + bool checkBox = 7; // + int64 count = 8; //实际弹幕总数 + repeated CommandDm commandDms = 9; //互动弹幕条目 + DanmuWebPlayerConfig dmSetting = 10; //弹幕个人配置 +} \ No newline at end of file diff --git a/dm/view_pb2.py b/dm/view_pb2.py new file mode 100644 index 00000000..6ed79304 --- /dev/null +++ b/dm/view_pb2.py @@ -0,0 +1,514 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: view.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='view.proto', + package='', + syntax='proto3', + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\nview.proto\".\n\x0b\x44mSegConfig\x12\x10\n\x08pageSize\x18\x01 \x01(\x03\x12\r\n\x05total\x18\x02 \x01(\x03\"H\n\x11\x44\x61nmakuFlagConfig\x12\x0f\n\x07recFlag\x18\x01 \x01(\x05\x12\x0f\n\x07recText\x18\x02 \x01(\t\x12\x11\n\trecSwitch\x18\x03 \x01(\x05\"\xa1\x01\n\tCommandDm\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0b\n\x03oid\x18\x02 \x01(\x03\x12\x0b\n\x03mid\x18\x03 \x01(\x03\x12\x0f\n\x07\x63ommand\x18\x04 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x05 \x01(\t\x12\x10\n\x08progress\x18\x06 \x01(\x05\x12\r\n\x05\x63time\x18\x07 \x01(\t\x12\r\n\x05mtime\x18\x08 \x01(\t\x12\r\n\x05\x65xtra\x18\t \x01(\t\x12\r\n\x05idStr\x18\n \x01(\t\"\x8b\x03\n\x14\x44\x61nmuWebPlayerConfig\x12\x10\n\x08\x64mSwitch\x18\x01 \x01(\x08\x12\x10\n\x08\x61iSwitch\x18\x02 \x01(\x08\x12\x0f\n\x07\x61iLevel\x18\x03 \x01(\x05\x12\x10\n\x08\x62locktop\x18\x04 \x01(\x08\x12\x13\n\x0b\x62lockscroll\x18\x05 \x01(\x08\x12\x13\n\x0b\x62lockbottom\x18\x06 \x01(\x08\x12\x12\n\nblockcolor\x18\x07 \x01(\x08\x12\x14\n\x0c\x62lockspecial\x18\x08 \x01(\x08\x12\x14\n\x0cpreventshade\x18\t \x01(\x08\x12\r\n\x05\x64mask\x18\n \x01(\x08\x12\x0f\n\x07opacity\x18\x0b \x01(\x02\x12\x0e\n\x06\x64marea\x18\x0c \x01(\x05\x12\x11\n\tspeedplus\x18\r \x01(\x02\x12\x10\n\x08\x66ontsize\x18\x0e \x01(\x02\x12\x12\n\nscreensync\x18\x0f \x01(\x08\x12\x11\n\tspeedsync\x18\x10 \x01(\x08\x12\x12\n\nfontfamily\x18\x11 \x01(\t\x12\x0c\n\x04\x62old\x18\x12 \x01(\x08\x12\x12\n\nfontborder\x18\x13 \x01(\x05\x12\x10\n\x08\x64rawType\x18\x14 \x01(\t\"\xfd\x01\n\x0e\x44mWebViewReply\x12\r\n\x05state\x18\x01 \x01(\x05\x12\x0c\n\x04text\x18\x02 \x01(\t\x12\x10\n\x08textSide\x18\x03 \x01(\t\x12\x1b\n\x05\x64mSge\x18\x04 \x01(\x0b\x32\x0c.DmSegConfig\x12 \n\x04\x66lag\x18\x05 \x01(\x0b\x32\x12.DanmakuFlagConfig\x12\x12\n\nspecialDms\x18\x06 \x03(\t\x12\x10\n\x08\x63heckBox\x18\x07 \x01(\x08\x12\r\n\x05\x63ount\x18\x08 \x01(\x03\x12\x1e\n\ncommandDms\x18\t \x03(\x0b\x32\n.CommandDm\x12(\n\tdmSetting\x18\n \x01(\x0b\x32\x15.DanmuWebPlayerConfigb\x06proto3' +) + + + + +_DMSEGCONFIG = _descriptor.Descriptor( + name='DmSegConfig', + full_name='DmSegConfig', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='pageSize', full_name='DmSegConfig.pageSize', index=0, + number=1, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='total', full_name='DmSegConfig.total', index=1, + number=2, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=14, + serialized_end=60, +) + + +_DANMAKUFLAGCONFIG = _descriptor.Descriptor( + name='DanmakuFlagConfig', + full_name='DanmakuFlagConfig', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='recFlag', full_name='DanmakuFlagConfig.recFlag', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='recText', full_name='DanmakuFlagConfig.recText', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='recSwitch', full_name='DanmakuFlagConfig.recSwitch', index=2, + number=3, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=62, + serialized_end=134, +) + + +_COMMANDDM = _descriptor.Descriptor( + name='CommandDm', + full_name='CommandDm', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='id', full_name='CommandDm.id', index=0, + number=1, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='oid', full_name='CommandDm.oid', index=1, + number=2, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='mid', full_name='CommandDm.mid', index=2, + number=3, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='command', full_name='CommandDm.command', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='content', full_name='CommandDm.content', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='progress', full_name='CommandDm.progress', index=5, + number=6, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='ctime', full_name='CommandDm.ctime', index=6, + number=7, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='mtime', full_name='CommandDm.mtime', index=7, + number=8, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='extra', full_name='CommandDm.extra', index=8, + number=9, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='idStr', full_name='CommandDm.idStr', index=9, + number=10, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=137, + serialized_end=298, +) + + +_DANMUWEBPLAYERCONFIG = _descriptor.Descriptor( + name='DanmuWebPlayerConfig', + full_name='DanmuWebPlayerConfig', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='dmSwitch', full_name='DanmuWebPlayerConfig.dmSwitch', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='aiSwitch', full_name='DanmuWebPlayerConfig.aiSwitch', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='aiLevel', full_name='DanmuWebPlayerConfig.aiLevel', index=2, + number=3, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='blocktop', full_name='DanmuWebPlayerConfig.blocktop', index=3, + number=4, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='blockscroll', full_name='DanmuWebPlayerConfig.blockscroll', index=4, + number=5, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='blockbottom', full_name='DanmuWebPlayerConfig.blockbottom', index=5, + number=6, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='blockcolor', full_name='DanmuWebPlayerConfig.blockcolor', index=6, + number=7, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='blockspecial', full_name='DanmuWebPlayerConfig.blockspecial', index=7, + number=8, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='preventshade', full_name='DanmuWebPlayerConfig.preventshade', index=8, + number=9, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='dmask', full_name='DanmuWebPlayerConfig.dmask', index=9, + number=10, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='opacity', full_name='DanmuWebPlayerConfig.opacity', index=10, + number=11, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='dmarea', full_name='DanmuWebPlayerConfig.dmarea', index=11, + number=12, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='speedplus', full_name='DanmuWebPlayerConfig.speedplus', index=12, + number=13, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='fontsize', full_name='DanmuWebPlayerConfig.fontsize', index=13, + number=14, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='screensync', full_name='DanmuWebPlayerConfig.screensync', index=14, + number=15, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='speedsync', full_name='DanmuWebPlayerConfig.speedsync', index=15, + number=16, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='fontfamily', full_name='DanmuWebPlayerConfig.fontfamily', index=16, + number=17, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='bold', full_name='DanmuWebPlayerConfig.bold', index=17, + number=18, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='fontborder', full_name='DanmuWebPlayerConfig.fontborder', index=18, + number=19, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='drawType', full_name='DanmuWebPlayerConfig.drawType', index=19, + number=20, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=301, + serialized_end=696, +) + + +_DMWEBVIEWREPLY = _descriptor.Descriptor( + name='DmWebViewReply', + full_name='DmWebViewReply', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='state', full_name='DmWebViewReply.state', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='text', full_name='DmWebViewReply.text', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='textSide', full_name='DmWebViewReply.textSide', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='dmSge', full_name='DmWebViewReply.dmSge', index=3, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='flag', full_name='DmWebViewReply.flag', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='specialDms', full_name='DmWebViewReply.specialDms', index=5, + number=6, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='checkBox', full_name='DmWebViewReply.checkBox', index=6, + number=7, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='count', full_name='DmWebViewReply.count', index=7, + number=8, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='commandDms', full_name='DmWebViewReply.commandDms', index=8, + number=9, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='dmSetting', full_name='DmWebViewReply.dmSetting', index=9, + number=10, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=699, + serialized_end=952, +) + +_DMWEBVIEWREPLY.fields_by_name['dmSge'].message_type = _DMSEGCONFIG +_DMWEBVIEWREPLY.fields_by_name['flag'].message_type = _DANMAKUFLAGCONFIG +_DMWEBVIEWREPLY.fields_by_name['commandDms'].message_type = _COMMANDDM +_DMWEBVIEWREPLY.fields_by_name['dmSetting'].message_type = _DANMUWEBPLAYERCONFIG +DESCRIPTOR.message_types_by_name['DmSegConfig'] = _DMSEGCONFIG +DESCRIPTOR.message_types_by_name['DanmakuFlagConfig'] = _DANMAKUFLAGCONFIG +DESCRIPTOR.message_types_by_name['CommandDm'] = _COMMANDDM +DESCRIPTOR.message_types_by_name['DanmuWebPlayerConfig'] = _DANMUWEBPLAYERCONFIG +DESCRIPTOR.message_types_by_name['DmWebViewReply'] = _DMWEBVIEWREPLY +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +DmSegConfig = _reflection.GeneratedProtocolMessageType('DmSegConfig', (_message.Message,), { + 'DESCRIPTOR' : _DMSEGCONFIG, + '__module__' : 'view_pb2' + # @@protoc_insertion_point(class_scope:DmSegConfig) + }) +_sym_db.RegisterMessage(DmSegConfig) + +DanmakuFlagConfig = _reflection.GeneratedProtocolMessageType('DanmakuFlagConfig', (_message.Message,), { + 'DESCRIPTOR' : _DANMAKUFLAGCONFIG, + '__module__' : 'view_pb2' + # @@protoc_insertion_point(class_scope:DanmakuFlagConfig) + }) +_sym_db.RegisterMessage(DanmakuFlagConfig) + +CommandDm = _reflection.GeneratedProtocolMessageType('CommandDm', (_message.Message,), { + 'DESCRIPTOR' : _COMMANDDM, + '__module__' : 'view_pb2' + # @@protoc_insertion_point(class_scope:CommandDm) + }) +_sym_db.RegisterMessage(CommandDm) + +DanmuWebPlayerConfig = _reflection.GeneratedProtocolMessageType('DanmuWebPlayerConfig', (_message.Message,), { + 'DESCRIPTOR' : _DANMUWEBPLAYERCONFIG, + '__module__' : 'view_pb2' + # @@protoc_insertion_point(class_scope:DanmuWebPlayerConfig) + }) +_sym_db.RegisterMessage(DanmuWebPlayerConfig) + +DmWebViewReply = _reflection.GeneratedProtocolMessageType('DmWebViewReply', (_message.Message,), { + 'DESCRIPTOR' : _DMWEBVIEWREPLY, + '__module__' : 'view_pb2' + # @@protoc_insertion_point(class_scope:DmWebViewReply) + }) +_sym_db.RegisterMessage(DmWebViewReply) + + +# @@protoc_insertion_point(module_scope) diff --git a/lighting_downloader.py b/lighting_downloader.py index 144da439..47e6605f 100644 --- a/lighting_downloader.py +++ b/lighting_downloader.py @@ -11,7 +11,8 @@ from rich import print as rprint from rich.progress import Progress, BarColumn, DownloadColumn, TransferSpeedColumn, TimeRemainingColumn from itertools import groupby -from subtitle_convert import json2srt +from subtitle import json2srt +from dm import parse_view class Downloader: @@ -27,6 +28,8 @@ def __init__(self, videos_dir='videos', sess_data='', video_concurrency=3, part_ self.videos_dir = videos_dir if not os.path.exists(self.videos_dir): os.makedirs(videos_dir) + if not os.path.exists(f'{self.videos_dir}/extra'): + os.makedirs(f'{self.videos_dir}/extra') cookies = {'SESSDATA': sess_data} headers = {'user-agent': 'PostmanRuntime/7.29.0', 'referer': 'https://www.bilibili.com'} self.client = httpx.AsyncClient(headers=headers, cookies=cookies, http2=http2) @@ -41,6 +44,7 @@ def __init__(self, videos_dir='videos', sess_data='', video_concurrency=3, part_ self.progress.start() self.sema = asyncio.Semaphore(video_concurrency) self.part_concurrency = part_concurrency + # todo re compile async def aclose(self): self.progress.stop() @@ -228,7 +232,7 @@ async def get_up_videos_by_page(self, mid, pn=1, num=30, order='pubdate', keywor for bv in bv_ids] ) - async def get_series(self, url: str, quality: int = 0, image=False, subtitle=False, only_audio=False): + async def get_series(self, url: str, quality: int = 0, image=False, subtitle=False, dm=False, only_audio=False): """ 下载某个系列(包括up发布的多p投稿,动画,电视剧,电影等)的所有视频。只有一个视频的情况下仍然可用该方法 @@ -236,6 +240,7 @@ async def get_series(self, url: str, quality: int = 0, image=False, subtitle=Fal :param quality: 下载视频画面的质量,默认0为可下载的最高画质,数字越大质量越低,数值超过范围时默认选取最低画质 :param image: 是否下载封面 :param subtitle: 是否下载字幕 + :param dm: 是否下载弹幕 :param only_audio: 是否仅下载音频 :return: """ @@ -250,18 +255,20 @@ async def get_series(self, url: str, quality: int = 0, image=False, subtitle=Fal add_name = f"P{idx + 1}-{i['part']}" if len(initial_state['videoData']['pages']) > 1 else '' cors.append(self.get_video(p_url, quality, add_name, image=True if idx == 0 and image else False, - subtitle=subtitle, only_audio=only_audio)) + subtitle=subtitle, dm=dm, only_audio=only_audio)) elif 'initEpList' in initial_state: # 动漫,电视剧,电影 for idx, i in enumerate(initial_state['initEpList']): p_url = i['link'] add_name = i['title'] - cors.append(self.get_video(p_url, quality, add_name, image, subtitle, only_audio)) + cors.append(self.get_video(p_url, quality, add_name, image=image, + subtitle=subtitle, dm=dm, only_audio=only_audio)) else: rprint(f'[red]未知类型 {url}') return await asyncio.gather(*cors) - async def get_video(self, url, quality: int = 0, add_name='', image=False, subtitle=False, only_audio=False): + async def get_video(self, url, quality: int = 0, add_name='', image=False, subtitle=False, dm=False, + only_audio=False): """ 下载单个视频 @@ -270,16 +277,18 @@ async def get_video(self, url, quality: int = 0, add_name='', image=False, subti :param add_name: 给文件的额外添加名,用户请直接保持默认 :param image: 是否下载封面 :param subtitle: 是否下载字幕 + :param dm: 是否下载弹幕 :param only_audio: 是否仅下载音频 :return: """ await self.sema.acquire() - res = await self._get_front(url) + res = await self._req_front(url) title = re.search(']*title="([^"]*)"', res.text).groups()[0].strip() if add_name: title = f'{title}-{add_name.strip()}' title = html.unescape(title) # handel & "... - title = re.sub(r"[/\\:*?\"<>|]", '', title) # replace windows illegal character in title + title = re.sub(r"[/\\:*?\"<>|]", '', title) + # replace windows illegal character in title try: # find video and audio url play_info = re.search('