diff --git a/packages/biliass/rust/build.rs b/packages/biliass/rust/build.rs index c216c86ff..aec239049 100644 --- a/packages/biliass/rust/build.rs +++ b/packages/biliass/rust/build.rs @@ -1,7 +1,10 @@ use std::io::Result; fn main() -> Result<()> { - let file_descriptors = - protox::compile(["proto/danmaku.proto"], ["proto/"]).expect("Failed to compile proto file"); + let file_descriptors = protox::compile( + ["proto/danmaku.proto", "proto/danmaku_view.proto"], + ["proto/"], + ) + .expect("Failed to compile proto file"); prost_build::compile_fds(file_descriptors)?; println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=proto/danmaku.proto"); diff --git a/packages/biliass/rust/proto/danmaku_view.proto b/packages/biliass/rust/proto/danmaku_view.proto new file mode 100644 index 000000000..3842da101 --- /dev/null +++ b/packages/biliass/rust/proto/danmaku_view.proto @@ -0,0 +1,69 @@ +// From https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/danmaku_view_proto.md + +syntax = "proto3"; + +package danmaku_view; + +//分段弹幕包信息? +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; //弹幕个人配置 +} diff --git a/packages/biliass/rust/src/proto.rs b/packages/biliass/rust/src/proto/danmaku.rs similarity index 100% rename from packages/biliass/rust/src/proto.rs rename to packages/biliass/rust/src/proto/danmaku.rs diff --git a/packages/biliass/rust/src/proto/danmaku_view.rs b/packages/biliass/rust/src/proto/danmaku_view.rs new file mode 100644 index 000000000..18d79a064 --- /dev/null +++ b/packages/biliass/rust/src/proto/danmaku_view.rs @@ -0,0 +1,2 @@ +#![allow(clippy::all)] +include!(concat!(env!("OUT_DIR"), "/danmaku_view.rs")); diff --git a/packages/biliass/rust/src/proto/mod.rs b/packages/biliass/rust/src/proto/mod.rs new file mode 100644 index 000000000..2f818ad8a --- /dev/null +++ b/packages/biliass/rust/src/proto/mod.rs @@ -0,0 +1,2 @@ +pub mod danmaku; +pub mod danmaku_view; diff --git a/packages/biliass/rust/src/python/proto.rs b/packages/biliass/rust/src/python/proto.rs index 354a8d4f9..b4665f6aa 100644 --- a/packages/biliass/rust/src/python/proto.rs +++ b/packages/biliass/rust/src/python/proto.rs @@ -6,11 +6,11 @@ use std::io::Cursor; #[pyclass(name = "DanmakuElem")] pub struct PyDanmakuElem { - inner: proto::DanmakuElem, + inner: proto::danmaku::DanmakuElem, } impl PyDanmakuElem { - fn new(inner: proto::DanmakuElem) -> Self { + fn new(inner: proto::danmaku::DanmakuElem) -> Self { PyDanmakuElem { inner } } } @@ -94,11 +94,11 @@ impl PyDanmakuElem { #[pyclass(name = "DmSegMobileReply")] pub struct PyDmSegMobileReply { - inner: proto::DmSegMobileReply, + inner: proto::danmaku::DmSegMobileReply, } impl PyDmSegMobileReply { - fn new(inner: proto::DmSegMobileReply) -> Self { + fn new(inner: proto::danmaku::DmSegMobileReply) -> Self { PyDmSegMobileReply { inner } } } @@ -124,7 +124,7 @@ impl PyDmSegMobileReply { #[staticmethod] fn decode(buffer: &[u8]) -> PyResult { Ok(PyDmSegMobileReply::new( - proto::DmSegMobileReply::decode(&mut Cursor::new(buffer)) + proto::danmaku::DmSegMobileReply::decode(&mut Cursor::new(buffer)) .map_err(error::DecodeError::from) .map_err(error::BiliassError::from)?, )) @@ -133,7 +133,7 @@ impl PyDmSegMobileReply { #[pyfunction(name = "get_danmaku_meta_size")] pub fn py_get_danmaku_meta_size(buffer: &[u8]) -> PyResult { - let dm_sge_opt = proto::DmWebViewReply::decode(&mut Cursor::new(buffer)) + let dm_sge_opt = proto::danmaku_view::DmWebViewReply::decode(&mut Cursor::new(buffer)) .map(|reply| reply.dm_sge) .map_err(error::DecodeError::from) .map_err(error::BiliassError::from)?; diff --git a/packages/biliass/rust/src/reader/protobuf.rs b/packages/biliass/rust/src/reader/protobuf.rs index 8005b9fc0..1704f279f 100644 --- a/packages/biliass/rust/src/reader/protobuf.rs +++ b/packages/biliass/rust/src/reader/protobuf.rs @@ -1,6 +1,6 @@ use crate::comment::{Comment, CommentPosition}; use crate::error::{BiliassError, DecodeError}; -use crate::proto::DmSegMobileReply; +use crate::proto::danmaku::DmSegMobileReply; use crate::reader::utils; use prost::Message; use std::io::Cursor; diff --git a/src/yutto/extractor/ugc_video.py b/src/yutto/extractor/ugc_video.py index 5e3f4105f..e36d5166b 100644 --- a/src/yutto/extractor/ugc_video.py +++ b/src/yutto/extractor/ugc_video.py @@ -31,6 +31,8 @@ class UgcVideoExtractor(SingleExtractor): REGEX_AV_ID = re.compile(r"av(?P\d+)(\?p=(?P\d+))?") REGEX_BV_ID = re.compile(r"(?P(bv|BV)\w+)(\?p=(?P\d+))?") + REGEX_BV_SPECIAL_PAGE = re.compile(r"https?://www\.bilibili\.com/festival/.+(?P(bv|BV)\w+)") + page: int avid: AvId @@ -52,13 +54,17 @@ def resolve_shortcut(self, id: str) -> tuple[bool, str]: return matched, url def match(self, url: str) -> bool: - if (match_obj := self.REGEX_AV.match(url)) or (match_obj := self.REGEX_BV.match(url)): + if ( + (match_obj := self.REGEX_AV.match(url)) + or (match_obj := self.REGEX_BV.match(url)) + or (match_obj := self.REGEX_BV_SPECIAL_PAGE.match(url)) + ): self.page: int = 1 if "aid" in match_obj.groupdict().keys(): self.avid = AId(match_obj.group("aid")) else: self.avid = BvId(match_obj.group("bvid")) - if match_obj.group("page") is not None: + if "page" in match_obj.groupdict() and match_obj.group("page") is not None: self.page = int(match_obj.group("page")) return True else: