return true
})
CookieSet([]byte(p.Map_2_Cookies_String(Cookie)))
+}
+
+//正在直播主播
+type UpItem struct{
+ Uname string `json:"uname"`
+ Title string `json:"title"`
+ Roomid int `json:"roomid"`
+}
+func Feed_list() (Uplist []UpItem) {
+ apilog := apilog.Base_add(`正在直播主播`).L(`T: `,`获取中`)
+ //验证cookie
+ if missKey := CookieCheck([]string{
+ `bili_jct`,
+ `DedeUserID`,
+ `LIVE_BUVID`,
+ });len(missKey) != 0 {
+ apilog.L(`T: `,`Cookie无Key:`,missKey)
+ return
+ }
+ if api_limit.TO() {apilog.L(`E: `,`超时!`);return}//超额请求阻塞,超时将取消
+
+ Cookie := make(map[string]string)
+ c.Cookie.Range(func(k,v interface{})(bool){
+ Cookie[k.(string)] = v.(string)
+ return true
+ })
+
+ req := p.Req()
+ for pageNum:=1; true; pageNum+=1 {
+ if err := req.Reqf(p.Rval{
+ Url:`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=`+strconv.Itoa(pageNum)+`&pagesize=10`,
+ Header:map[string]string{
+ `Host`: `api.live.bilibili.com`,
+ `User-Agent`: `Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0`,
+ `Accept`: `application/json, text/plain, */*`,
+ `Accept-Language`: `zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2`,
+ `Accept-Encoding`: `gzip, deflate, br`,
+ `Origin`: `https://t.bilibili.com`,
+ `Connection`: `keep-alive`,
+ `Pragma`: `no-cache`,
+ `Cache-Control`: `no-cache`,
+ `Referer`:`https://t.bilibili.com/pages/nav/index_new`,
+ `Cookie`:p.Map_2_Cookies_String(Cookie),
+ },
+ Timeout:3,
+ Retry:2,
+ });err != nil {
+ apilog.L(`E: `,err)
+ return
+ }
+
+ var res struct{
+ Code int `json:"code"`
+ Msg string `json:"msg"`
+ Message string `json:"message"`
+ Data struct{
+ Results int `json:"results"`
+ List []UpItem `json:"list"`
+ } `json:"data"`
+ }
+
+ if e := json.Unmarshal(req.Respon, &res);e != nil{
+ apilog.L(`E: `, e)
+ return
+ }
+
+ if res.Code != 0{
+ apilog.L(`E: `, res.Message)
+ return
+ }
+
+ Uplist = append(Uplist, res.Data.List...)
+
+ if pageNum*10 > res.Data.Results {break}
+ time.Sleep(time.Second)
+ }
+
+ apilog.L(`T: `,`完成`)
+ return
}
\ No newline at end of file
--- /dev/null
+package F
+
+import (
+ "os"
+ "bufio"
+ "strings"
+ "strconv"
+
+ p "github.com/qydysky/part"
+ send "github.com/qydysky/bili_danmu/Send"
+ c "github.com/qydysky/bili_danmu/CV"
+)
+
+//直播间缓存
+var liveList =make(map[string]int)
+
+func Cmd() {
+
+ cmdlog := c.Log.Base_add(`命令行操作`).L(`T: `,`回车查看帮助`)
+ scanner := bufio.NewScanner(os.Stdin)
+
+ for scanner.Scan() {
+ if inputs := scanner.Text();inputs == `` {//帮助
+ cmdlog.L(`I: `, "切换房间->输入数字回车")
+ cmdlog.L(`I: `, "发送弹幕->输入' 字符串'回车")
+ cmdlog.L(`I: `, "查看直播中主播->输入' live'回车")
+ cmdlog.L(`I: `, "其他输出隔断不影响")
+ } else if inputs[0] == 27 {//屏蔽功能键
+ cmdlog.L(`W: `, "不支持功能键")
+ } else if inputs[0] == 32 {// 开头
+ if strings.Contains(inputs, ` live`) {//直播间切换
+ if len(inputs) > 5 {
+ if room,ok := liveList[inputs];ok{
+ c.Roomid = room
+ cmdlog.L(`I: `, "进入房间",room)
+ c.Danmu_Main_mq.Push_tag(`change_room`,nil)
+ continue
+ }
+ cmdlog.L(`W: `, "输入错误", inputs)
+ continue
+ }
+ for k,v := range Feed_list() {
+ liveList[` live`+strconv.Itoa(k)] = v.Roomid
+ cmdlog.L(`I: `, k, v.Uname, v.Title)
+ }
+ cmdlog.L(`I: `, "回复' live(序号)'进入直播间")
+ continue
+ }
+ {//弹幕发送
+ if len(inputs) < 2 {
+ cmdlog.L(`W: `, "输入长度过短", inputs)
+ continue
+ }
+ Cookie := make(map[string]string)
+ c.Cookie.Range(func(k,v interface{})(bool){
+ Cookie[k.(string)] = v.(string)
+ return true
+ })
+ send.Danmu_s(inputs[1:], p.Map_2_Cookies_String(Cookie),c.Roomid)
+ }
+ } else if room,err := strconv.Atoi(inputs);err == nil {//直接进入房间
+ c.Roomid = room
+ cmdlog.L(`I: `, "进入房间",room)
+ c.Danmu_Main_mq.Push_tag(`change_room`,nil)
+ } else {//其余字符串
+ Cookie := make(map[string]string)
+ c.Cookie.Range(func(k,v interface{})(bool){
+ Cookie[k.(string)] = v.(string)
+ return true
+ })
+ send.Danmu_s(inputs, p.Map_2_Cookies_String(Cookie),c.Roomid)
+ }
+ }
+}
\ No newline at end of file
- [x] 弹幕自动重连(30s)
- [x] 直播流开播自动下载
- [x] 直播流断流再保存
+- [x] 命令行支持房间切换、弹幕发送
- [x] GTK信息窗支持房间切换、弹幕格式化发送、时长统计
- [x] GTK弹幕窗支持自定义人/事件消息停留
### 说明
本项目使用github action自动构建,构建过程详见[yml](https://github.com/qydysky/bili_danmu/blob/master/.github/workflows/go.yml)
+#### 命令行操作
+在准备动作完成(`T: 2021/03/06 16:22:39 命令行操作 [回车查看帮助]`)后,输入回车将显示帮助
+```
+I: 2021/03/06 16:16:17 命令行操作 [切换房间->输入数字回车]
+I: 2021/03/06 16:16:17 命令行操作 [发送弹幕->输入' 字符串'回车]
+I: 2021/03/06 16:16:17 命令行操作 [查看直播中主播->输入' live'回车]
+I: 2021/03/06 16:16:17 命令行操作 [其他输出隔断不影响]
+```
+用例:
+- 直播间切换
+```
+ live
+T: 2021/03/06 16:18:48 api 正在直播主播 [获取中]
+T: 2021/03/06 16:18:48 api 正在直播主播 [完成]
+I: 2021/03/06 16:18:48 命令行操作 [0 奈さま B站第一坑老公]
+I: 2021/03/06 16:18:48 命令行操作 [1 古守血遊official 【B】Apex on]
+I: 2021/03/06 16:18:48 命令行操作 [2 一米八的坤儿 午饭直播]
+I: 2021/03/06 16:18:48 命令行操作 [3 哔哩哔哩英雄联盟赛事 【直播】 LNG vs LGD]
+I: 2021/03/06 16:18:48 命令行操作 [回复' live(序号)'进入直播间]
+ live1
+I: 2021/03/06 16:19:12 命令行操作 [进入房间 8725120]
+```
+```
+120
+I: 2021/03/06 16:21:35 命令行操作 [进入 120]
+```
+- 发送弹幕
+```
+ 1
+I: 2021/03/06 16:21:17 弹幕发送 [发送 1 至 7734200]
+```
#### cookie加密
保护cookie.txt
<-change_room_chan
- //命令行也可切换房间
- go func(){
- for input := ``; true; {
- if _,err := fmt.Scanln(&input);err.Error() == `unexpected newline`{
- fmt.Println("输入房间号并回车(其他显示隔断不影响)\n")
- room := 0
- if _,err := fmt.Scanln(&room);err != nil {
- danmulog.L(`W: `, "房间输入错误", room, err)
- } else {
- c.Roomid = room
- c.Danmu_Main_mq.Push_tag(`change_room`,nil)
- }
- }
- }
- }()
-
//ctrl+c退出
signal.Notify(interrupt, os.Interrupt)
- for !exit_sign {
- //获取cookies
- {
- var get_cookie = func(){
- danmulog.L(`I: `, "未检测到cookie.txt,如果需要登录请在本机打开以下网址扫码登录,不需要请忽略")
- //获取cookie
- F.Get_cookie()
- //验证cookie
- if missKey := F.CookieCheck([]string{
- `bili_jct`,
- `DedeUserID`,
- });len(missKey) == 0 {
- danmulog.L(`I: `,"你已登录,刷新房间!")
- //刷新
- c.Danmu_Main_mq.Push_tag(`change_room`,nil)
- }
+ //获取cookies
+ {
+ var get_cookie = func(){
+ danmulog.L(`I: `, "未检测到cookie.txt,如果需要登录请在本机打开以下网址扫码登录,不需要请忽略")
+ //获取cookie
+ F.Get_cookie()
+ //验证cookie
+ if missKey := F.CookieCheck([]string{
+ `bili_jct`,
+ `DedeUserID`,
+ });len(missKey) == 0 {
+ danmulog.L(`I: `,"你已登录,刷新房间!")
+ //刷新
+ c.Danmu_Main_mq.Push_tag(`change_room`,nil)
}
+ }
+
+ if !p.Checkfile().IsExist("cookie.txt") {//读取cookie文件
+ go get_cookie()
+ p.Sys().Timeoutf(3)
+ } else {
- if !p.Checkfile().IsExist("cookie.txt") {//读取cookie文件
+ cookieString := string(F.CookieGet())
+
+ if cookieString == `` {//cookie.txt为空
+ danmulog.L(`T: `, `cookie.txt为空`)
go get_cookie()
p.Sys().Timeoutf(3)
} else {
-
- cookieString := string(F.CookieGet())
-
- if cookieString == `` {//cookie.txt为空
- danmulog.L(`T: `, `cookie.txt为空`)
+ for k,v := range p.Cookies_String_2_Map(cookieString){//cookie存入全局变量syncmap
+ c.Cookie.Store(k, v)
+ }
+ if uid,ok := c.Cookie.LoadV(`DedeUserID`).(string);!ok{//cookie中无DedeUserID
+ danmulog.L(`T: `, `读取cookie错误,无DedeUserID`)
+ go get_cookie()
+ p.Sys().Timeoutf(3)
+ } else if uid,e := strconv.Atoi(uid);e != nil{
+ danmulog.L(`E: `, e)
go get_cookie()
p.Sys().Timeoutf(3)
} else {
- for k,v := range p.Cookies_String_2_Map(cookieString){//cookie存入全局变量syncmap
- c.Cookie.Store(k, v)
- }
- if uid,ok := c.Cookie.LoadV(`DedeUserID`).(string);!ok{//cookie中无DedeUserID
- danmulog.L(`T: `, `读取cookie错误,无DedeUserID`)
- go get_cookie()
- p.Sys().Timeoutf(3)
- } else if uid,e := strconv.Atoi(uid);e != nil{
- danmulog.L(`E: `, e)
- go get_cookie()
- p.Sys().Timeoutf(3)
- } else {
- c.Uid = uid
- }
+ c.Uid = uid
}
}
}
+ }
- danmulog.L(`T: `,"准备变量")
+ //命令行操作 切换房间 发送弹幕
+ go F.Cmd()
+
+ for !exit_sign {
+ danmulog.L(`T: `,"准备")
//获取房间相关信息
api := F.New_api(c.Roomid).Get_host_Token().Get_live()
c.Roomid = api.Roomid