]> 127.0.0.1 Git - bili_danmu/.git/commitdiff
flv流超时接合时间戳修正
authorqydysky <qydysky@foxmail.com>
Wed, 5 May 2021 09:15:05 +0000 (17:15 +0800)
committerqydysky <qydysky@foxmail.com>
Wed, 5 May 2021 09:15:05 +0000 (17:15 +0800)
14 files changed:
F/api.go
F/xinxin.go
README.md
Reply/F.go
Reply/flvDecode.go
Reply/gtk.go
Reply/tts.go
Send/Send.go
Send/Send_gift.go
Send/Send_pm.go
demo/go.mod
demo/go.sum
go.mod
go.sum

index 5e343201a7104a3e851472bc7a9090a8a459ae8c..a3e32d488f3e51a71060f659042030cbba1733c5 100644 (file)
--- a/F/api.go
+++ b/F/api.go
@@ -238,7 +238,7 @@ func Info(UpUid int) (info J.Info) {
 
        //html
        {
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:`https://api.bilibili.com/x/space/acc/info?mid=`+strconv.Itoa(UpUid)+`&jsonp=jsonp`,
                        Proxy:c.Proxy,
@@ -441,7 +441,7 @@ func getInfoByRoom() (missKey []string) {
        Roomid := strconv.Itoa(c.Roomid)
 
        {//使用其他api
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:"https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=" + Roomid,
                        Header:map[string]string{
@@ -526,7 +526,7 @@ func getRoomPlayInfo() (missKey []string) {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:"https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo?no_playurl=0&mask=1&qn=0&platform=web&protocol=0,1&format=0,2&codec=0,1&room_id=" + Roomid,
                        Header:map[string]string{
@@ -687,7 +687,7 @@ func getRoomPlayInfoByQn() (missKey []string) {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:"https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo?no_playurl=0&mask=1&qn="+ strconv.Itoa(c.Live_qn) +"&platform=web&protocol=0,1&format=0,2&codec=0,1&room_id=" + Roomid,
                        Header:map[string]string{
@@ -839,7 +839,7 @@ func getDanmuInfo() (missKey []string) {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:"https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?type=0&id=" + Roomid,
                        Header:map[string]string{
@@ -884,7 +884,7 @@ func Get_face_src(uid string) (string) {
                return true
        })
 
-       req := reqf.Req()
+       req := reqf.New()
        if err := req.Reqf(reqf.Rval{
                Url:"https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuMedalAnchorInfo?ruid=" + uid,
                Header:map[string]string{
@@ -939,7 +939,7 @@ func Get_HotRank() (missKey []string) {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/xlive/general-interface/v1/rank/getHotRank?ruid=`+strconv.Itoa(c.UpUid)+`&room_id=`+Roomid+`&is_pre=0&page_size=50&source=2&area_id=`+strconv.Itoa(c.ParentAreaID),
                        Header:map[string]string{
@@ -1009,7 +1009,7 @@ func Get_guardNum() (missKey []string) {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/xlive/app-room/v2/guardTab/topList?roomid=`+Roomid+`&page=1&ruid=`+strconv.Itoa(c.UpUid)+`&page_size=29`,
                        Header:map[string]string{
@@ -1143,7 +1143,7 @@ func Get_cookie() (missKey []string) {
        var img_url string
        var oauth string
        {//获取二维码
-               r := reqf.Req()
+               r := reqf.New()
                if e := r.Reqf(reqf.Rval{
                        Url:`https://passport.bilibili.com/qrcode/getLoginUrl`,
                        Proxy:c.Proxy,
@@ -1240,7 +1240,7 @@ func Get_cookie() (missKey []string) {
                        //有新实例,退出
                        if boot_Get_cookie.NeedExit(id) {return}
 
-                       r := reqf.Req()
+                       r := reqf.New()
                        if e := r.Reqf(reqf.Rval{
                                Url:`https://passport.bilibili.com/qrcode/getLoginInfo`,
                                PostStr:`oauthKey=`+oauth,
@@ -1364,7 +1364,7 @@ func Get_list_in_room() (array []TGet_list_in_room) {
        {//获取牌子列表
                var medalList []TGet_list_in_room
                for pageNum:=1; true;pageNum+=1{
-                       r := reqf.Req()
+                       r := reqf.New()
                        if e := r.Reqf(reqf.Rval{
                                Url:`https://api.live.bilibili.com/fans_medal/v5/live_fans_medal/iApiMedal?page=`+strconv.Itoa(pageNum)+`&pageSize=10`,
                                Header:map[string]string{
@@ -1444,7 +1444,7 @@ func Get_weared_medal() (item TGet_weared_medal) {
        })
 
        {//获取
-               r := reqf.Req()
+               r := reqf.New()
                if e := r.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/live_user/v1/UserInfo/get_weared_medal`,
                        Header:map[string]string{
@@ -1550,7 +1550,7 @@ func CheckSwitch_FansMedal() (missKey []string) {
                }
        }
        {//切换牌子
-               r := reqf.Req()
+               r := reqf.New()
                if e := r.Reqf(reqf.Rval{
                        Url:post_url,
                        PostStr:post_str,
@@ -1602,7 +1602,7 @@ func Dosign() {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/xlive/web-ucenter/v1/sign/WebGetSignInfo`,
                        Header:map[string]string{
@@ -1649,7 +1649,7 @@ func Dosign() {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/xlive/web-ucenter/v1/sign/DoSign`,
                        Header:map[string]string{
@@ -1706,7 +1706,7 @@ func Get_LIVE_BUVID() (missKey []string) {
        }
 
        for _,roomid := range roomIdList{//获取
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/live/getRoomKanBanModel?roomid=`+roomid,
                        Header:map[string]string{
@@ -1854,7 +1854,7 @@ func F_x25Kn() {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                for {
                        //新调用,此退出
                        if boot_F_x25Kn.NeedExit(id) {return}
@@ -1967,7 +1967,7 @@ func F_x25Kn() {
                                return true
                        })
 
-                       req := reqf.Req()
+                       req := reqf.New()
                        if err := req.Reqf(reqf.Rval{
                                Url:`https://live-trace.bilibili.com/xlive/data-interface/v1/x25Kn/X`,
                                Header:map[string]string{
@@ -2051,7 +2051,7 @@ func Gift_list() (list []Gift_list_type_Data_List) {
                return true
        })
 
-       req := reqf.Req()
+       req := reqf.New()
        if err := req.Reqf(reqf.Rval{
                Url:`https://api.live.bilibili.com/xlive/web-room/v1/gift/bag_list?t=`+strconv.Itoa(int(p.Sys().GetMTime()))+`&room_id=`+strconv.Itoa(c.Roomid),
                Header:map[string]string{
@@ -2118,7 +2118,7 @@ func Silver_2_coin() (missKey []string) {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/pay/v1/Exchange/getStatus`,
                        Header:map[string]string{
@@ -2178,7 +2178,7 @@ func Silver_2_coin() (missKey []string) {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/pay/v1/Exchange/getRule`,
                        Header:map[string]string{
@@ -2239,7 +2239,7 @@ func Silver_2_coin() (missKey []string) {
                        return true
                })
 
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/pay/v1/Exchange/silver2coin`,
                        PostStr:url.PathEscape(post_str),
@@ -2325,7 +2325,7 @@ func Feed_list() (Uplist []UpItem) {
                return true
        })
 
-       req := reqf.Req()
+       req := reqf.New()
        for pageNum:=1; true; pageNum+=1 {
                if err := req.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=`+strconv.Itoa(pageNum)+`&pagesize=10`,
@@ -2386,7 +2386,7 @@ func GetHistory(Roomid_int int) (j J.GetHistory) {
        Roomid := strconv.Itoa(Roomid_int)
 
        {//使用其他api
-               req := reqf.Req()
+               req := reqf.New()
                if err := req.Reqf(reqf.Rval{
                        Url:"https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=" + Roomid,
                        Header:map[string]string{
@@ -2428,7 +2428,7 @@ func IsConnected() bool {
        v,ok := c.K_v.LoadV(`网络中断不退出`).(bool)
        if !ok || !v {return true}
 
-       req := reqf.Req()
+       req := reqf.New()
        if err := req.Reqf(reqf.Rval{
                Url:"https://www.bilibili.com",
                Proxy:c.Proxy,
index 198b66c7b0cb7147d4dd0b3b6c6a87aca786bf0f..a483dd6680d0a0ef2c8dd27181cd7af04f0a9021 100644 (file)
@@ -140,7 +140,7 @@ func server() {
 func Wasm(uid uintptr,s RT) (o string) {//maxloop 超时重试
        {//nodejs
                if nodeJsUrl != "" {
-                       req := reqf.Req()
+                       req := reqf.New()
                        if err := req.Reqf(reqf.Rval{
                                Header:map[string]string{
                                        `Content-Type`: `application/json`,
index da8b9877cdb5b6a1dd0e3a91eee263e0cbe962e8..2cd3ce6d2f9a86de2674dd5663f2afd662581a7d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -89,6 +89,7 @@ golang go version go1.15 linux/amd64
 
 #### 其他特性
 
+- [x] 使用http代理
 - [x] cookie加密
 - [x] 弹幕自动重连(30s)
 - [x] 直播流开播自动下载
index 2238946c65c68ff37becda0b2da899c70777a5ab..869e4e4ff49fac25479de65da9495c176ddfd11d 100644 (file)
@@ -16,6 +16,7 @@ import (
        "net/url"
        "errors"
        "bytes"
+       // "runtime"
        
        c "github.com/qydysky/bili_danmu/CV"
        F "github.com/qydysky/bili_danmu/F"
@@ -23,6 +24,7 @@ import (
        
        p "github.com/qydysky/part"
        funcCtrl "github.com/qydysky/part/funcCtrl"
+       idpool "github.com/qydysky/part/idpool"
        msgq "github.com/qydysky/part/msgq"
        reqf "github.com/qydysky/part/reqf"
        web "github.com/qydysky/part/web"
@@ -283,7 +285,7 @@ func Savestreamf(){
 
                        query := url_struct.Query()
 
-                       r := reqf.Req()
+                       r := reqf.New()
                        if e := r.Reqf(reqf.Rval{
                                Url:m3u8_url,
                                Retry:4,
@@ -376,8 +378,17 @@ func Savestreamf(){
 
                        return
                }
-               flv_get_link = func(link string) (need_download string) {
+               flv_get_link = func(link string) (need_download string,expires int,err error) {
                        need_download = link
+
+                       url_struct,e := url.Parse(link)
+                       if e != nil {
+                               err = e
+                               return
+                       }
+                       query := url_struct.Query()
+                       expires,_ = strconv.Atoi(query.Get("expires"))
+
                        return
                }
        )
@@ -400,7 +411,7 @@ func Savestreamf(){
                savestream.wait = s.Init()
                savestream.cancel = s.Init()
                
-               rr := reqf.Req()
+               rr := reqf.New()
                go func(){
                        savestream.cancel.Wait()
                        rr.Close()
@@ -438,71 +449,360 @@ func Savestreamf(){
                if strings.Contains(c.Live[0],"flv") {
                        l.L(`I: `,"保存到", savestream.path + ".flv")
                        Ass_f(savestream.path, time.Now())
-
+                       
                        // no expect qn
                        exit_chan := make(chan struct{})
-                       go func(){//flv stream
-                               byteC := make(chan []byte,1024*1024*30)//传来的关键帧间隔buf为3s,避免超出buf,设为30M
+                       {
+                               // go func(){//flv stream
+                               //      byteC := make(chan []byte,1<<17)
+       
+                               //      go func(){
+                               //              for !p.Checkfile().IsExist(savestream.path + ".flv.dtmp") {
+                               //                      select {
+                               //                      case <-exit_chan:return;
+                               //                      case <-time.After(time.Second):;
+                               //                      }
+                               //              }
+                               //              for {
+                               //                      if err := Stream(savestream.path + ".flv.dtmp",&savestream.flv_front,byteC,exit_chan);err != nil {
+                               //                              flog.L(`T: `,err);
+                               //                              return
+                               //                      }
+                               //                      select {
+                               //                      case <-exit_chan:return;
+                               //                      default:;
+                               //                      }
+                               //              }
+                               //      }()
+       
+                               //      var buf []byte
+                               //      for {
+                               //              select{
+                               //              case res :=<- byteC:
+                               //                      buf = append(buf, res...)
+                               //                      if len(byteC) != 0 {break}
+                               //                      savestream.flv_stream.Push_tag("stream",buf)
+                               //                      buf = []byte{}
+                               //              case <- exit_chan:
+                               //                      savestream.flv_stream.Push_tag("close",nil)
+                               //                      return;
+                               //              }
+                               //      }
+                               // }()
+                       }
 
-                               go func(){
-                                       for !p.Checkfile().IsExist(savestream.path + ".flv.dtmp") {
-                                               select {
-                                               case <-exit_chan:return;
-                                               case <-time.After(time.Second):;
+                       // go func(){
+                       //      var count int = 5
+                       //      for count > 0 && c.Live_want_qn < c.Live_qn {
+                       //              count -= 1
+                       //              select{
+                       //              case <- time.After(time.Minute*2):;
+                       //              case <- exit_chan:return;
+                       //              }
+                       //              F.Get(`Liveing`)
+                       //              if !c.Liveing {break}
+       
+                       //              F.Get(`Live`)
+                       //              if len(c.Live)==0 {break}
+                       //      }
+                       //      Savestream_wait()
+                       // }()
+
+                       type link_stream struct {
+                               id *idpool.Id
+                               front []byte
+                               keyframe [][]byte
+                               // sync_buf []byte
+                               close func()
+
+                               sync.RWMutex
+                       }
+                       
+                       //chans
+                       var (
+                               reqs = msgq.New(10)
+                               id_pool = idpool.New()
+                       )
+
+                       //文件
+                       out, err := os.Create(savestream.path + ".flv" + ".dtmp")
+                       if err != nil {
+                               l.L(`E: `,err)
+                               return
+                       }
+
+                       //数据整合
+                       {
+                               var (
+                                       reqs_used_id []uintptr
+                                       reqs_remove_id []uintptr
+                                       
+                                       reqs_keyframe [][][]byte
+
+                                       reqs_func_block funcCtrl.BlockFunc
+                                       last_time_stamp int
+                               )
+                               reqs.Pull_tag(map[string]func(interface{})(bool){
+                                       `req`:func(data interface{})(bool){
+                                               req,ok := data.(link_stream)
+       
+                                               if !ok {return false}
+       
+                                               if len(req.keyframe) == 0 {
+                                                       // fmt.Println(req.id.Id, `没有keyframe,退出`)
+                                                       req.close()
+                                                       return false
+                                               }
+                                               // fmt.Println(`处理req_id`,req.id.Id,`keyframe_len`,len(req.keyframe))
+       
+                                               if offset,_ := out.Seek(0,1);offset == 0 {
+                                                       // fmt.Println(`添加头`,len(req.front))
+                                                       //stream
+                                                       savestream.flv_front = req.front
+                                                       out.Write(req.front)
+                                               }
+       
+                                               reqs_func_block.Block()
+                                               defer reqs_func_block.UnBlock()
+       
+                                               {
+                                                       var isclose bool
+                                                       for i:=0;i<len(reqs_remove_id);i+=1 {
+                                                               if reqs_remove_id[i] == req.id.Id {
+                                                                       isclose = true
+                                                                       reqs_remove_id = append(reqs_remove_id[:i], reqs_remove_id[i+1:]...)
+                                                                       break
+                                                               }
+                                                       }
+                                                       if isclose {
+                                                               // fmt.Println(`移除req`,req.id.Id)
+                                                               req.close()
+                                                               return false
+                                                       }
+                                               }
+                                               
+       
+                                               var reqs_keyframe_index int = len(reqs_used_id)
+                                               {
+                                                       var isnew bool = true
+                                                       for i:=0;i<len(reqs_used_id);i+=1 {
+                                                               if reqs_used_id[i] == req.id.Id {
+                                                                       reqs_keyframe_index = i
+                                                                       isnew = false
+                                                                       break
+                                                               }
+                                                       }
+                                                       if isnew {
+                                                               // fmt.Println(`新req`,req.id.Id,reqs_keyframe_index)
+                                                               reqs_used_id = append(reqs_used_id, req.id.Id)
+                                                       }
+                                               }
+                                               
+       
+                                               if len(reqs_used_id) == 1 {
+                                                       // fmt.Println(`单req写入`,len(req.keyframe))
+
+                                                       last_time_stamp,_ = Keyframe_timebase(req.keyframe,last_time_stamp)
+
+                                                       for i:=0;i<len(req.keyframe);i+=1 {
+                                                               //stream
+                                                               savestream.flv_stream.Push_tag("stream",req.keyframe[i])
+                                                               out.Write(req.keyframe[i])
+                                                       }
+                                                       return false
+                                               }
+       
+                                               for reqs_keyframe_index >= len(reqs_keyframe) {
+                                                       reqs_keyframe = append(reqs_keyframe, [][]byte{})
+                                               }
+                                               reqs_keyframe[reqs_keyframe_index] = append(reqs_keyframe[reqs_keyframe_index], req.keyframe...)
+       
+                                               // fmt.Println(`merge,添加reqs_keyframe数据`,reqs_keyframe_index,len(reqs_keyframe[reqs_keyframe_index]))
+
+                                               for _,v := range reqs_keyframe {
+                                                       if len(v) == 0 {
+                                                               // fmt.Println(`merge,req无数据`,k)
+                                                               return false
+                                                       }
+                                               }
+       
+                                               if success_last_keyframe_timestramp,b,merged := Merge_stream(reqs_keyframe);merged == 0 {
+                                                       // fmt.Println(`merge失败,reqs_keyframe[1]`,reqs_keyframe[1][0][:11],reqs_keyframe[1][len(reqs_keyframe[1])-1][:11])
+                                                       if reqs_keyframe_index == 0 {
+                                                               // fmt.Println(`merge失败,reqs_keyframe[0]写入`,len(req.keyframe))
+
+                                                               last_time_stamp,_ = Keyframe_timebase(req.keyframe,last_time_stamp)
+
+                                                               for i:=0;i<len(req.keyframe);i+=1 {
+                                                                       //stream
+                                                                       savestream.flv_stream.Push_tag("stream",req.keyframe[i])
+                                                                       out.Write(req.keyframe[i])
+                                                               }
+                                                               reqs_keyframe[0] = [][]byte{reqs_keyframe[0][len(reqs_keyframe[0])-1]}
+                                                       } else if len(reqs_keyframe[len(reqs_used_id)-1]) > 5 {
+                                                               // fmt.Println(`强行merge`)
+
+                                                               // last_time_stamp = int(F.Btoi32([]byte{reqs_keyframe[0][0][7], reqs_keyframe[0][0][4], reqs_keyframe[0][0][5], reqs_keyframe[0][0][6]},0))
+       
+                                                               reqs_keyframe = [][][]byte{}
+                                                               
+                                                               for i:=0;i<len(reqs_used_id)-1;i+=1 {
+                                                                       reqs_remove_id = append(reqs_remove_id, reqs_used_id[i])
+                                                               }
+                                                               reqs_used_id = []uintptr{reqs_used_id[len(reqs_used_id)-1]}
+
+                                                               last_time_stamp,_ = Keyframe_timebase(req.keyframe,last_time_stamp)
+
+                                                               for i:=0;i<len(req.keyframe);i+=1 {
+                                                                       //stream
+                                                                       savestream.flv_stream.Push_tag("stream",req.keyframe[i])
+                                                                       out.Write(req.keyframe[i])
+                                                               }
+                                                       }
+                                               } else {
+                                                       // fmt.Println(`merge成功`,len(b))
+
+                                                       last_time_stamp = success_last_keyframe_timestramp
+       
+                                                       for i:=0;i<merged;i+=1 {
+                                                               reqs_keyframe[i] = [][]byte{}
+                                                               reqs_remove_id = append(reqs_remove_id, reqs_used_id[i])
+                                                       }
+                                                       
+                                                       reqs_used_id = []uintptr{reqs_used_id[merged]}
+
+                                                       //stream
+                                                       savestream.flv_stream.Push_tag("stream",b)
+                                                       out.Write(b)
                                                }
+       
+                                               return false
+                                       },
+                                       `close`:func(data interface{})(bool){
+                                               return true
+                                       },
+                               })
+                       }
+
+                       //连接保持
+                       for savestream.cancel.Islive() {
+                               //获取超时时间
+                               link,exp,e := flv_get_link(c.Live[0])
+                               if e != nil {
+                                       l.L(`E: `,e)
+                                       break
+                               }
+
+                               // 新建chan
+                               var (
+                                       bc = make(chan []byte,1<<17)
+                                       req = reqf.New()
+                               )
+
+                               //新建请求
+                               go func(r *reqf.Req,rval reqf.Rval){
+                                       if e := r.Reqf(rval);e != nil {
+                                               l.L(`E: `,e)
+                                               return
                                        }
+                               }(req,reqf.Rval{
+                                       Url:link,
+                                       Proxy:c.Proxy,
+                                       Header:map[string]string{
+                                               `Cookie`:reqf.Map_2_Cookies_String(CookieM),
+                                       },
+                                       //SaveToPath:savestream.path + ".flv",
+                                       SaveToChan:bc,
+                                       Timeout:int(int64(exp) - p.Sys().GetSTime()),
+                               })
+                               
+                               //返回通道
+                               var item = link_stream{
+                                       close:req.Close,
+                                       id:id_pool.Get(),
+                               }
+
+                               //解析
+                               go func(bc chan[]byte,item *link_stream){
+                                       var buf []byte
                                        for {
-                                               if err := Stream(savestream.path + ".flv.dtmp",&savestream.flv_front,byteC,exit_chan);err != nil {
-                                                       flog.L(`T: `,err);
-                                                       return
-                                               }
                                                select {
                                                case <-exit_chan:return;
-                                               default:;
+                                               case b :=<- bc:
+                                                       if len(b) == 0 {
+                                                               // fmt.Println(`req退出`,item.id.Id)
+                                                               id_pool.Put(item.id)
+                                                               return
+                                                       }
+
+                                                       buf = append(buf, b...)
+                                                       // var tmp_buf []byte
+                                                       // {
+                                                       //      tmp_buf = make([]byte,len(buf))
+                                                       //      copy(tmp_buf, buf)
+                                                       // }
+                                                       
+                                                       if len(buf) < 1<<21 {break}
+
+                                                       front,list,_ := Seach_stream_tag(buf)
+
+                                                       // fmt.Println(`=<`,buf[:3])
+
+                                                       if len(front) != 0 && len(item.front) == 0 {
+                                                               // fmt.Println(item.id.Id,`获取到header`,len(front))
+                                                               item.front = make([]byte,len(front))
+                                                               copy(item.front, front)
+                                                       }
+
+                                                       if len(list) == 0 || len(item.front) == 0 {break}
+
+                                                       // total := 0
+                                                       item.keyframe = list
+                                                       // item.keyframe = make([][]byte,len(list))
+                                                       // for i:=0;i<len(list);i+=1 {
+                                                       //      total += len(list[i])
+                                                       //      item.keyframe[i] = make([]byte,len(list[i]))
+                                                       //      copy(item.keyframe[i],list[i])
+                                                       // }
+
+                                                       // fmt.Println(item.id.Id,`获取到keyframe`,len(list))
+
+                                                       {
+                                                               last_keyframe := list[len(list)-1]
+                                                               cut_offset := bytes.LastIndex(buf, last_keyframe)+len(last_keyframe)
+                                                               // fmt.Println(`buf截断 剩余`,len(buf), `下一header`,buf[:11])
+                                                               buf = buf[cut_offset:]
+                                                       }
+
+                                                       reqs.Push_tag(`req`,*item)
                                                }
                                        }
-                               }()
-
-                               for {
-                                       select{
-                                       case res :=<- byteC:
-                                               savestream.flv_stream.Push_tag("stream",res)
-                                       case <- exit_chan:
-                                               savestream.flv_stream.Push_tag("close",nil)
-                                               return;
+                               }(bc,&item)
+                               
+
+                               //等待过期/退出
+                               {
+                                       var exit_sign bool
+                                       select {
+                                       case <- savestream.cancel.Chan:
+                                               exit_sign = true
+                                       case <- time.After(time.Second*time.Duration(int(int64(exp) - p.Sys().GetSTime())-120)):;
                                        }
+                                       if exit_sign {break}
                                }
-                       }()
-                       if c.Live_want_qn < c.Live_qn {
-                               go func(){
-                                       for c.Live_want_qn < c.Live_qn {
-                                               select{
-                                               case <- time.After(time.Minute):;
-                                               case <- exit_chan:return;
-                                               }
-                                               F.Get(`Liveing`)
-                                               if !c.Liveing {break}
-               
-                                               F.Get(`Live`)
-                                               if len(c.Live)==0 {break}
-                                       }
-                                       Savestream_wait()
-                               }()
+                               
+                               l.L(`I: `,"flv过期,开始新连接")
+                               // fmt.Println(`过期`)
+       
+                               //即将过期,刷新c.Live
+                               F.Get(`Liveing`)
+                               if !c.Liveing {break}
+                               F.Get(`Live`)
+                               if len(c.Live)==0 {break}
                        }
-
-                       link := flv_get_link(c.Live[0])
-                       if e := rr.Reqf(reqf.Rval{
-                               Url:link,
-                               Retry:3,
-                               Proxy:c.Proxy,
-                               SleepTime:3,
-                               Header:map[string]string{
-                                       `Cookie`:reqf.Map_2_Cookies_String(CookieM),
-                               },
-                               SaveToPath:savestream.path + ".flv",
-                               Timeout:-1,
-                       }); e != nil{l.L(`W: `,e)}
                        
+                       reqs.Push_tag(`close`,nil)
                        close(exit_chan)
 
                        l.L(`I: `,"结束")
@@ -681,7 +981,7 @@ func Savestreamf(){
                                for i:=0;i<len(links);i+=1 {
                                        go func(link *m4s_link_item,path string){
                                                download_limit.TO()
-                                               r := reqf.Req()
+                                               r := reqf.New()
                                                if e := r.Reqf(reqf.Rval{
                                                        Url:(*link).Url,
                                                        Retry:3,
index d7235f0390340fe6d00b39cb1145b51857aaffe6..70567a448624bc5843bf7a64d141827c39c482d1 100644 (file)
@@ -10,6 +10,8 @@ import (
 
        c "github.com/qydysky/bili_danmu/CV"
        F "github.com/qydysky/bili_danmu/F"
+
+       reqf "github.com/qydysky/part/reqf"
 )
 
 const (
@@ -31,6 +33,127 @@ var (
        send_sign = []byte{0x00}
 )
 
+type flv_source struct {
+       buf []byte
+       Rval reqf.Rval
+       Inuse bool
+}
+
+// func Stream_sync(sources []*flv_source) (buf_p *[]byte,err error) {
+//     var (
+//             sources sync.Map
+//             buf = []byte{}
+//     )
+//     buf_p = &buf
+
+//     for i:=0;i<len(sources);i+=1 {
+//             item := *sources[i]
+//             if _,ok := sources.Load(item.req.Url);ok{
+//                     time.Sleep(time.Second*5)
+//                     continue
+//             }
+
+//             if len(sources)
+
+//             go func(m *sync.Map,source_p *flv_source){
+//                     m.Store(source_p.Rval.Url,interface{})
+//                     defer m.Delete(source_p.Rval.Url)
+
+//                     *source_p.Inuse = true
+//                     rval := *source_p.Rval
+//                     rval.ResponChan = make(chan []byte,1024*1024)
+
+//                     go func(){
+//                             for {
+//                                     *source_p.buf = append(*source_p.buf, <-rval.ResponChan)
+
+//                             }
+//                     }()
+
+//                     if e := rr.Reqf(rval); e != nil{l.L(`W: `,e)}
+
+//                     *source_p.Inuse = false
+//             }(&sources,sources[i])
+//     }
+// }
+
+type flv_tag struct {
+       Tag byte
+       Offset int64
+       Timestamp int32
+       PreSize int32
+       FirstByte byte
+       Buf *[]byte
+}
+
+// func Tag_stream(c chan []byte,co chan []byte) ( bool) {
+//     //check channel
+//     if c == nil || co == nil {return}
+               
+//     var (
+//             buf []byte
+//             seach_stream_tag = func(buf []byte)(front_buf []byte,available_offset int64){
+//                     //get flv header(9byte) + FirstTagSize(4byte)
+//                     {
+//                             if bytes.Index(buf,flv_header_sign) == 0 {
+//                                     front_buf = buf[:flv_header_size+previou_tag_size]
+//                             } else {
+//                                     defer front_buf = []byte{}
+//                             }
+//                     }
+
+//                     var sign = 0x00
+//                     for buf_offset:=0;buf_offset<len(buf); {
+//                             if tag_offset := buf_offset+bytes.IndexAny(buf[buf_offset:], string([]byte{video_tag,audio_tag,script_tag}));tag_offset == buf_offset-1 {
+//                                     return//no found available video,audio,script tag
+//                             } else if streamid_offset := tag_offset+bytes.Index(buf[tag_offset:], []byte{0x00,0x00,0x00});streamid_offset == tag_offset-1 {
+//                                     return//no found available streamid
+//                             } else if streamid_offset-8 != tag_offset {
+//                                     buf_offset = tag_offset + 1
+//                                     continue//streamid offset error
+//                             } else if time_offset := tag_offset+4;buf[time_offset:time_offset+2] == []byte{0x00,0x00,0x00}{
+
+//                                     size := F.Btoi32(append([]byte{0x00},buf[tag_offset+1:tag_offset+3]...),0)+7
+//                                     if (buf[tag_offset] == video_tag) && (sign & 0x04 == 0x00) {
+//                                             sign |= 0x04
+//                                             front_buf = append(front_buf, buf[tag_offset:tag_offset+size])
+//                                     } else if (buf[tag_offset] == audio_tag) && (sign & 0x02 == 0x00) {
+//                                             sign |= 0x02
+//                                             front_buf = append(front_buf, buf[tag_offset:tag_offset+size])
+//                                     } else if (buf[tag_offset] == script_tag) && (sign & 0x01 == 0x00) {
+//                                             sign |= 0x01
+//                                             front_buf = append(front_buf, buf[tag_offset:tag_offset+size])
+//                                     }
+
+//                                     buf_offset = tag_offset + 1
+//                                     continue//time error
+
+//                             } else {
+//                                     available_offset = tag_offset
+//                                     return
+//                             }
+//                     }
+//                     return
+//             }
+//     )
+
+//     for {
+//             if b:=<- c;len(b) == 0 {
+//                     return
+//             } else {
+//                     buf = append(buf, b...)
+//             }
+//             if _,offset := seach_stream_tag(buf);offset != -1{
+//                     co <- buf[offset:]
+//                     buf = []byte{}
+//                     break
+//             }
+//     }
+//     for len(co) != 0 {runtime.Gosched()}
+//     co = c
+//     return true
+// }
+
 func Stream(path string,front_buf *[]byte,streamChan chan []byte,cancel chan struct{}) (error) {
        flvlog.L(`T: `,path)
        defer flvlog.L(`T: `,`退出`)
@@ -204,3 +327,410 @@ func Stream(path string,front_buf *[]byte,streamChan chan []byte,cancel chan str
 
        return nil
 }
+
+// this fuction read []byte and return flv header and all complete keyframe if possible.
+// complete keyframe means the video and audio tags between two video key frames tag
+func Seach_stream_tag(buf []byte)(front_buf []byte, keyframe[][]byte,err error){
+       //get flv header(9byte) + FirstTagSize(4byte)
+       if header_offset := bytes.Index(buf,flv_header_sign);header_offset != -1 {
+               front_buf = buf[header_offset:header_offset+flv_header_size+previou_tag_size]
+       }
+
+       var (
+               sign = 0x00
+               keyframe_num = -1
+               tag_num = 0
+       )
+
+       defer func(){
+               if sign != 0x07 {
+                       front_buf = []byte{}
+               }
+               if len(keyframe) > 0 {
+                       keyframe = keyframe[:len(keyframe)-1]
+               }
+       }()
+
+       for buf_offset:=0;buf_offset+tag_header_size<len(buf); {
+
+               tag_offset := buf_offset+bytes.IndexAny(buf[buf_offset:], string([]byte{video_tag,audio_tag,script_tag}));
+               if tag_offset == buf_offset-1 {
+                       err = errors.New(`no found available tag`)
+                       // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       return//no found available video,audio,script tag
+               }
+               if tag_offset+tag_header_size > len(buf) {
+                       err = errors.New(`reach end when get tag header`)
+                       // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       return//buf end
+               }
+
+               streamid := int(F.Btoi32([]byte{0x00,buf[tag_offset+8],buf[tag_offset+9],buf[tag_offset+10]},0))
+               if streamid != 0 {
+                       buf_offset = tag_offset + 1
+                       // fmt.Printf("streamid error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       continue//streamid error
+               }
+
+               tag_size := int(F.Btoi32([]byte{0x00,buf[tag_offset+1],buf[tag_offset+2],buf[tag_offset+3]},0))
+               if tag_offset+tag_header_size+tag_size+previou_tag_size > len(buf) {
+                       err = errors.New(`reach end when get tag body`)
+                       // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       return//buf end
+               }
+               if tag_size == 0 {
+                       buf_offset = tag_offset + 1
+                       // fmt.Printf("tag_size error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       continue//tag_size error
+               }
+
+               tag_size_check := int(F.Btoi32(buf[tag_offset+tag_header_size+tag_size:tag_offset+tag_header_size+tag_size+previou_tag_size],0))
+               if tag_num + tag_size_check == 0 {tag_size_check = tag_size+tag_header_size}
+               if tag_size_check != tag_size+tag_header_size {
+                       buf_offset = tag_offset + 1
+                       // fmt.Printf("tag_size_check error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       continue//tag_size_check error
+               }
+
+               time_stamp := int(F.Btoi32([]byte{buf[tag_offset+7], buf[tag_offset+4], buf[tag_offset+5], buf[tag_offset+6]},0))
+       
+               // fmt.Printf("%x\n",buf[tag_offset:tag_offset+tag_header_size])
+
+               tag_num += 1
+
+               if time_stamp == 0 {
+                       if len(front_buf) != 0 {
+                               if (buf[tag_offset] == video_tag) && (sign & 0x04 == 0x00) {
+                                       sign |= 0x04
+                                       front_buf = append(front_buf, buf[tag_offset:tag_offset+tag_size_check+previou_tag_size]...)
+                               } else if (buf[tag_offset] == audio_tag) && (sign & 0x02 == 0x00) {
+                                       sign |= 0x02
+                                       front_buf = append(front_buf, buf[tag_offset:tag_offset+tag_size_check+previou_tag_size]...)
+                               } else if (buf[tag_offset] == script_tag) && (sign & 0x01 == 0x00) {
+                                       sign |= 0x01
+                                       front_buf = append(front_buf, buf[tag_offset:tag_offset+tag_size_check+previou_tag_size]...)
+                               }
+                       }
+                       buf_offset = tag_offset+tag_size_check+previou_tag_size
+                       continue
+               }
+               
+               if buf[tag_offset] == video_tag {
+                       if buf[tag_offset+11] & 0xf0 == 0x10 {//key frame
+                               keyframe_num += 1
+                               keyframe = append(keyframe,[]byte{})
+                       }
+
+                       if keyframe_num >= 0 {
+                               keyframe[keyframe_num] = append(keyframe[keyframe_num], buf[tag_offset:tag_offset+tag_size_check+previou_tag_size]...)
+                       }
+               } else if buf[tag_offset] == audio_tag {
+                       if keyframe_num >= 0 {
+                               keyframe[keyframe_num] = append(keyframe[keyframe_num], buf[tag_offset:tag_offset+tag_size_check+previou_tag_size]...)
+                       }
+               } else {;}
+
+               buf_offset = tag_offset+tag_size_check+previou_tag_size
+       }
+       
+       return
+}
+
+//same as Seach_stream_tag but faster
+func Seach_keyframe_tag(buf []byte)(front_buf []byte, keyframe[][]byte,err error){
+
+       var (
+               sign = 0x00
+               // keyframe_num = -1
+               tag_num = 0
+               buf_offset = 0
+       )
+
+       defer func(){
+               if sign != 0x07 {
+                       front_buf = []byte{}
+               }
+       }()
+
+       //front_buf
+       if header_offset := bytes.Index(buf,flv_header_sign);header_offset != -1 {
+               front_buf = buf[header_offset:header_offset+flv_header_size+previou_tag_size]
+
+               for ;buf_offset+tag_header_size<len(buf); {
+
+                       tag_offset := buf_offset+bytes.IndexAny(buf[buf_offset:], string([]byte{video_tag,audio_tag,script_tag}));
+                       if tag_offset == buf_offset-1 {
+                               err = errors.New(`no found available tag`)
+                               // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               return//no found available video,audio,script tag
+                       }
+                       if tag_offset+tag_header_size > len(buf) {
+                               err = errors.New(`reach end when get tag header`)
+                               // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               return//buf end
+                       }
+       
+                       if buf[tag_offset+8] | buf[tag_offset+9] | buf[tag_offset+10] != 0 {
+                               buf_offset = tag_offset + 1
+                               // fmt.Printf("streamid error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               continue//streamid error
+                       }
+       
+                       tag_size := int(F.Btoi32([]byte{0x00,buf[tag_offset+1],buf[tag_offset+2],buf[tag_offset+3]},0))
+                       if tag_offset+tag_header_size+tag_size+previou_tag_size > len(buf) {
+                               err = errors.New(`reach end when get tag body`)
+                               // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               return//buf end
+                       }
+                       if tag_size == 0 {
+                               buf_offset = tag_offset + 1
+                               // fmt.Printf("tag_size error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               continue//tag_size error
+                       }
+       
+                       tag_size_check := int(F.Btoi32(buf[tag_offset+tag_header_size+tag_size:tag_offset+tag_header_size+tag_size+previou_tag_size],0))
+                       if tag_num + tag_size_check == 0 {tag_size_check = tag_size+tag_header_size}
+                       if tag_size_check != tag_size+tag_header_size {
+                               buf_offset = tag_offset + 1
+                               // fmt.Printf("tag_size_check error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               continue//tag_size_check error
+                       }
+       
+                       tag_num += 1
+       
+                       if buf[tag_offset+7] | buf[tag_offset+4] | buf[tag_offset+5] | buf[tag_offset+6] == 0 {
+
+                               if len(front_buf) != 0 {
+                                       if (buf[tag_offset] == video_tag) && (sign & 0x04 == 0x00) {
+                                               sign |= 0x04
+                                               front_buf = append(front_buf, buf[tag_offset:tag_offset+tag_size_check+previou_tag_size]...)
+                                       } else if (buf[tag_offset] == audio_tag) && (sign & 0x02 == 0x00) {
+                                               sign |= 0x02
+                                               front_buf = append(front_buf, buf[tag_offset:tag_offset+tag_size_check+previou_tag_size]...)
+                                       } else if (buf[tag_offset] == script_tag) && (sign & 0x01 == 0x00) {
+                                               sign |= 0x01
+                                               front_buf = append(front_buf, buf[tag_offset:tag_offset+tag_size_check+previou_tag_size]...)
+                                       }
+                               }
+                               buf_offset = tag_offset+tag_size_check+previou_tag_size
+                       }
+                       if sign == 0x07 {break}
+               }
+       }
+
+       //keyframe
+       var last_keyframe_offset int
+       for ;buf_offset+tag_header_size<len(buf); {
+
+               tag_offset := buf_offset+bytes.Index(buf[buf_offset:], []byte{video_tag})
+               if tag_offset == buf_offset-1 {
+                       err = errors.New(`no found available tag`)
+                       // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       return//no found available video,audio,script tag
+               }
+               if tag_offset+tag_header_size > len(buf) {
+                       err = errors.New(`reach end when get tag header`)
+                       // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       return//buf end
+               }
+
+               if buf[tag_offset+8] | buf[tag_offset+9] | buf[tag_offset+10] != 0 {
+                       buf_offset = tag_offset + 1
+                       // fmt.Printf("streamid error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       continue//streamid error
+               }
+
+               tag_size := int(F.Btoi32([]byte{0x00,buf[tag_offset+1],buf[tag_offset+2],buf[tag_offset+3]},0))
+               if tag_offset+tag_header_size+tag_size+previou_tag_size > len(buf) {
+                       err = errors.New(`reach end when get tag body`)
+                       // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       return//buf end
+               }
+               if tag_size == 0 {
+                       buf_offset = tag_offset + 1
+                       // fmt.Printf("tag_size error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       continue//tag_size error
+               }
+
+               tag_size_check := int(F.Btoi32(buf[tag_offset+tag_header_size+tag_size:tag_offset+tag_header_size+tag_size+previou_tag_size],0))
+               if tag_num + tag_size_check == 0 {tag_size_check = tag_size+tag_header_size}
+               if tag_size_check != tag_size+tag_header_size {
+                       buf_offset = tag_offset + 1
+                       // fmt.Printf("tag_size_check error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                       continue//tag_size_check error
+               }
+       
+               // fmt.Printf("%x\n",buf[tag_offset:tag_offset+tag_header_size])
+
+               tag_num += 1
+               
+               if buf[tag_offset] == video_tag {
+                       if buf[tag_offset+11] & 0xf0 == 0x10 {//key frame
+                               if last_keyframe_offset != 0 {
+                                       keyframe = append(keyframe,buf[last_keyframe_offset:tag_offset])
+                               }
+
+                               last_keyframe_offset = tag_offset
+                       }
+               }
+
+               buf_offset = tag_offset+tag_size_check+previou_tag_size
+       }
+
+       return
+}
+
+//this fuction merge two stream and return the merge buffer,which has the newest frame.
+//once len(merge_buf) isn't 0,old_buf can be drop and new_buf can be used from now on.or it's still need to keep buf until find the same tag.
+func Merge_stream(keyframe_lists [][][]byte)(last_keyframe_timestramp int,merge_buf []byte,merged int){
+
+       if len(keyframe_lists) == 0 {return}
+
+       // var keyframe_lists [][][]byte
+       // for i:=0;i<len(bufs);i+=1 {
+       //      _,keyframe_list,_ := Seach_stream_tag(bufs[i])
+       //      keyframe_lists = append(keyframe_lists, keyframe_list)
+       // }
+
+       var (
+               buf [][]byte
+               buf_o int
+       )
+       buf = keyframe_lists[0]
+       
+       // fmt.Println(`buf:`,len(buf[0]),buf[0][:tag_header_size])
+       // fmt.Println(`buf:`,buf[len(buf)-1][:tag_header_size])        
+       // fmt.Println(`buf1:`,len(keyframe_lists[1]),keyframe_lists[1][0][:tag_header_size])
+       // fmt.Println(`buf1:`,keyframe_lists[1][len(keyframe_lists[1])-1][:tag_header_size])
+
+       for i:=1;i<len(keyframe_lists);i+=1 {
+               for n:=buf_o;n<len(buf);n+=1 {
+                       for o:=0;o<len(keyframe_lists[i]);o+=1 {
+                       // fmt.Println(keyframe_lists[o])
+                       // keyframe_list_i_header := fmt.Sprintf("%x",keyframe_lists[i][o][:tag_header_size-3])
+                       // old_buf_o := buf_o
+                               if bytes.Index(buf[n][tag_header_size:],keyframe_lists[i][o][tag_header_size:]) != -1 {
+
+                                       last_time_stamp := int(F.Btoi32([]byte{buf[n][7], buf[n][4], buf[n][5], buf[n][6]},0))
+
+                                       // tmp_kfs := make([][]byte,len(keyframe_lists[i][o:]))
+
+                                       last_keyframe_timestramp,_ = Keyframe_timebase(keyframe_lists[i][o:],last_time_stamp)
+
+                                       buf = append(buf[:n], keyframe_lists[i][o:]...)
+                                       merged = i
+                                       break
+                               }
+
+                               // if keyframe_list_i_header == fmt.Sprintf("%x",buf[n][:tag_header_size-3]) {
+                               //      // buf_o = n
+                               //      buf = append(buf[:buf_o], keyframe_lists[i][o:]...)
+                               //      merged = true
+                               //      break
+                               // }
+                       }
+                       // if old_buf_o != buf_o {break}
+               }
+       }
+
+       // merged = len(buf) != len(keyframe_lists[0])
+
+       for n:=0;n<len(buf);n+=1 {
+               merge_buf = append(merge_buf, buf[n]...)
+       }
+       return
+
+       // for i:=0;i<len(old_list);i+=1 {
+       //      old_tag_header := fmt.Sprintf("%x",old_list[i][:tag_header_size])
+       //      for n:=0;n<len(new_list);n+=1 {
+       //              new_tag_header := fmt.Sprintf("%x",new_list[n][:tag_header_size])
+       //              if old_tag_header == new_tag_header {
+       //                      old_offset := bytes.Index(old_buf, old_list[i][:tag_header_size])
+       //                      new_offset := bytes.Index(new_buf, new_list[n][:tag_header_size])
+       //                      merge_buf = append(old_buf[:old_offset], new_buf[new_offset:]...)
+       //                      return
+       //              }
+       //      }
+       // }
+
+       // return
+}
+
+func Keyframe_timebase(buf [][]byte,last_time_stamp int)(newest_time_stamp int,err error){
+       var (
+               tag_num int
+               diff_time int
+       )
+       
+       // defer func(){
+       //      fmt.Printf("时间戳调整 newest:%d\n",newest_time_stamp)
+       // }()
+
+       for i:=0;i<len(buf);i+=1 {
+               for buf_offset:=0;buf_offset+tag_header_size<len(buf[i]); {
+
+                       tag_offset := buf_offset+bytes.IndexAny(buf[i][buf_offset:], string([]byte{video_tag,audio_tag,script_tag}));
+                       if tag_offset == buf_offset-1 {
+                               err = errors.New(`no found available tag`)
+                               // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               return//no found available video,audio,script tag
+                       }
+                       if tag_offset+tag_header_size > len(buf[i]) {
+                               err = errors.New(`reach end when get tag header`)
+                               // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               return//buf end
+                       }
+       
+                       if buf[i][tag_offset+8] | buf[i][tag_offset+9] | buf[i][tag_offset+10] != 0 {
+                               buf_offset = tag_offset + 1
+                               // fmt.Printf("streamid error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               continue//streamid error
+                       }
+       
+                       tag_size := int(F.Btoi32([]byte{0x00,buf[i][tag_offset+1],buf[i][tag_offset+2],buf[i][tag_offset+3]},0))
+                       if tag_offset+tag_header_size+tag_size+previou_tag_size > len(buf[i]) {
+                               err = errors.New(`reach end when get tag body`)
+                               // fmt.Printf("last %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               return//buf end
+                       }
+                       if tag_size == 0 {
+                               buf_offset = tag_offset + 1
+                               // fmt.Printf("tag_size error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               continue//tag_size error
+                       }
+       
+                       tag_size_check := int(F.Btoi32(buf[i][tag_offset+tag_header_size+tag_size:tag_offset+tag_header_size+tag_size+previou_tag_size],0))
+                       if tag_num + tag_size_check == 0 {tag_size_check = tag_size+tag_header_size}
+                       if tag_size_check != tag_size+tag_header_size {
+                               buf_offset = tag_offset + 1
+                               // fmt.Printf("tag_size_check error %x\n",buf[tag_offset:tag_offset+tag_header_size])
+                               continue//tag_size_check error
+                       }
+       
+                       tag_num += 1
+       
+                       time_stamp := int(F.Btoi32([]byte{buf[i][tag_offset+7], buf[i][tag_offset+4], buf[i][tag_offset+5], buf[i][tag_offset+6]},0))
+       
+                       if tag_num == 1 && last_time_stamp != 0 {
+                               diff_time = last_time_stamp + 3000 - time_stamp
+                               // fmt.Printf("时间戳调整 last:%d now:%d diff:%d\n",last_time_stamp,time_stamp,diff_time)
+                       }
+
+                       if buf[i][tag_offset] == video_tag {
+                               if buf[i][tag_offset+11] & 0xf0 == 0x10 {//key frame
+                                       newest_time_stamp = time_stamp+diff_time
+                               }
+                       }
+
+                       time_stamp_byte := F.Itob32(int32(time_stamp+diff_time))
+       
+                       buf[i][tag_offset+7] = time_stamp_byte[0]
+                       buf[i][tag_offset+4] = time_stamp_byte[1]
+                       buf[i][tag_offset+5] = time_stamp_byte[2]
+                       buf[i][tag_offset+6] = time_stamp_byte[3]
+       
+                       buf_offset = tag_offset+tag_size_check+previou_tag_size
+               }
+       }
+       return
+}
\ No newline at end of file
index cdc2fb51607b59d2c6148bce52122dc077670623..6d6cb616e946cdb0f6d2f5b2842ec3d916a4efc8 100644 (file)
@@ -471,7 +471,7 @@ func Gtk_danmu() {
                                        if p.Checkfile().IsExist(Gtk_img_path + `/` + uid) {return}
                                        src := F.Get_face_src(uid)
                                        if src == "" {return}
-                                       req := reqf.Req()
+                                       req := reqf.New()
                                        if e := req.Reqf(reqf.Rval{
                                                Url:src,
                                                SaveToPath:Gtk_img_path + `/` + uid,
index 9adc2f11c4749f2c804b4de1b506601d8a17ca40..1a60ce263cbd55431218ee2b99e03ea8c28f2cdd 100644 (file)
@@ -86,7 +86,7 @@ func TTS(uid,msg string) {
 
        msg = strings.ReplaceAll(v, "{D}", msg)
 
-       req := reqf.Req()
+       req := reqf.New()
        if err := req.Reqf(reqf.Rval{
                Url:`https://fanyi.baidu.com/gettts?lan=zh&text=`+ url.QueryEscape(msg) +`&spd=5&source=web`,
                SaveToPath:p.Sys().Cdir()+`/tts.mp3`,
index 5e17ffaa6a7b6aa79f01fcbbbd5d1e0b94e8011f..7993677507a5d403172f1ee1d77b32b60dd8aa91 100644 (file)
@@ -38,7 +38,7 @@ func Danmu_s(msg string, roomid int) {
 
        PostStr := `color=16777215&fontsize=25&mode=1&msg=` + msg + `&rnd=` + strconv.Itoa(int(p.Sys().GetSTime())) + `&roomid=` + strconv.Itoa(roomid) + `&bubble=0&csrf_token=` + csrf + `&csrf=` + csrf
        l.L(`I: `,"发送", msg, "至", roomid)
-       r := reqf.Req()
+       r := reqf.New()
        err := r.Reqf(reqf.Rval{
                Url:"https://api.live.bilibili.com/msg/send",
                PostStr:url.PathEscape(PostStr),
index aaeef884e11da6bd04f7544cd9fe1a7ac734a6da..883904329989ab8b9b7a988b8ee3fa67888c30bc 100644 (file)
@@ -50,7 +50,7 @@ func Send_gift(gift_id,bag_id,gift_num int) {
                        return true
                })
                
-               req := reqf.Req()
+               req := reqf.New()
                if e:= req.Reqf(reqf.Rval{
                        Url:`https://api.live.bilibili.com/gift/v2/live/bag_send`,
                        PostStr:url.PathEscape(sendStr),
index 7e70d0074227d45e16e3d582e9722de50b0e81a6..b45f76db0803fdf0d7f02d72cafc6f0e226f8b80 100644 (file)
@@ -60,7 +60,7 @@ func Send_pm(uid int, msg string) error {
                return true
        })
        
-       req := reqf.Req()
+       req := reqf.New()
        if e:= req.Reqf(reqf.Rval{
                Url:`https://api.vc.bilibili.com/web_im/v1/web_im/send_msg`,
                PostStr:url.PathEscape(send_str),
index ba4c0dfa693bb46bfbb1a86afd488de0efe2fe65..82fccd7c4c088bd725e2bef34a9666b258b08448 100644 (file)
@@ -4,23 +4,23 @@ go 1.14
 
 require (
        github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
+       github.com/andybalholm/brotli v1.0.2 // indirect
        github.com/christopher-dG/go-obs-websocket v0.0.0-20200720193653-c4fed10356a5 // indirect
        github.com/gofrs/uuid v4.0.0+incompatible // indirect
        github.com/gorilla/websocket v1.4.2 // indirect
        github.com/gotk3/gotk3 v0.5.2 // indirect
-       github.com/klauspost/compress v1.11.13 // indirect
+       github.com/klauspost/compress v1.12.2 // indirect
        github.com/mdp/qrterminal/v3 v3.0.0 // indirect
        github.com/miekg/dns v1.1.41 // indirect
        github.com/mitchellh/mapstructure v1.4.1 // indirect
-       github.com/qydysky/bili_danmu v0.5.7
-       github.com/qydysky/part v0.5.10 // indirect
-       github.com/shirou/gopsutil v3.21.3+incompatible // indirect
+       github.com/qydysky/bili_danmu v0.5.8
+       github.com/qydysky/part v0.5.12 // indirect
+       github.com/shirou/gopsutil v3.21.4+incompatible // indirect
        github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
        github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
        github.com/tklauser/go-sysconf v0.3.5 // indirect
-       golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
-       golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c // indirect
-       golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54 // indirect
+       golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 // indirect
+       golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 // indirect
 )
 
 replace (
index 5cdb2fb5c9f9b71bd4d7e4ad3001b8a8d2aa2cc0..8b709cc175a90b141fcfd6e9ca1de0ddee526efb 100644 (file)
@@ -9,6 +9,8 @@ github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 h1:5sXbqlSomvdjl
 github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
 github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc=
 github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
+github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E=
+github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/christopher-dG/go-obs-websocket v0.0.0-20200720193653-c4fed10356a5 h1:UFBgEMSPv6a2vgzowHOPphVit+ZBNQ3+4Q+dEBgwIww=
@@ -57,6 +59,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -98,6 +101,8 @@ github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaH
 github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.11.13 h1:eSvu8Tmq6j2psUJqJrLcWH6K3w5Dwc+qipbaA6eVEN4=
 github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8=
+github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
 github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
 github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -269,6 +274,8 @@ github.com/qydysky/part v0.5.9 h1:XZxBs6bBVQCKH48791X8ebrReY50aGw9IFCdaM1QhGA=
 github.com/qydysky/part v0.5.9/go.mod h1:43opuciW71sZvOR67kye50jgMDSDrn/t6+LefNdlXPg=
 github.com/qydysky/part v0.5.10 h1:SYdPGV1DlHFDKjDGBU3dXbuR9WA8NNwTbQ2nDjdyeiA=
 github.com/qydysky/part v0.5.10/go.mod h1:43opuciW71sZvOR67kye50jgMDSDrn/t6+LefNdlXPg=
+github.com/qydysky/part v0.5.12 h1:HnXJ7NmL5kvpFwPSpz5D5Kmg50mTblRP6tIufVsXP+U=
+github.com/qydysky/part v0.5.12/go.mod h1:43opuciW71sZvOR67kye50jgMDSDrn/t6+LefNdlXPg=
 github.com/qydysky/part/msgq v0.0.0-20201213031129-ca3253dc72ad h1:Jtzf509lQrkUMGTV0Sc6IDCAiR1VrBcHrIban7hpye4=
 github.com/qydysky/part/msgq v0.0.0-20201213031129-ca3253dc72ad/go.mod h1:w32TkJNVtTJd4LOS09cq+4uYG6itcN2vsqw+slp44Rg=
 github.com/qydysky/part/msgq v0.0.0-20201213120821-f36e49c32bba h1:1ew9dRpc0Rux0WkWeT/4AE15ynYWmL2D7onJEJIFOB8=
@@ -286,6 +293,8 @@ github.com/shirou/gopsutil v3.21.1+incompatible h1:2LwXWdbjXwyDgq26Yy/OT4xozlpms
 github.com/shirou/gopsutil v3.21.1+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/shirou/gopsutil v3.21.3+incompatible h1:uenXGGa8ESCQq+dbgtl916dmg6PSAz2cXov0uORQ9v8=
 github.com/shirou/gopsutil v3.21.3+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil v3.21.4+incompatible h1:fuHcTm5mX+wzo542cmYcV9RTGQLbnHLI5SyQ5ryTVck=
+github.com/shirou/gopsutil v3.21.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
@@ -332,6 +341,8 @@ golang.org/x/crypto v0.0.0-20210218145215-b8e89b74b9df/go.mod h1:jdWPYTVW3xRLrWP
 golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
 golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -367,6 +378,10 @@ golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c h1:KHUzaHIpjWVlVVNh65G3hhuj3KB1HnjY6Cq5cTvRQT8=
 golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk=
+golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 h1:Ugb8sMTWuWRC3+sz5WeN/4kejDx9BvIwnPUiJBjJE+8=
+golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -419,12 +434,18 @@ golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54 h1:rF3Ohx8DRyl8h2zw9qojyLHLhrJpEMgyPOImREEryf0=
 golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
+golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c=
+golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/go.mod b/go.mod
index b77e55662050e8ff580123d1b6e68f074d2a29d0..1650bbb7cfcb9c891ddabb69dcc84ca6111f7aef 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -3,13 +3,21 @@ module github.com/qydysky/bili_danmu
 go 1.15
 
 require (
+       github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
+       github.com/andybalholm/brotli v1.0.2 // indirect
        github.com/christopher-dG/go-obs-websocket v0.0.0-20200720193653-c4fed10356a5
        github.com/gofrs/uuid v4.0.0+incompatible
        github.com/gotk3/gotk3 v0.5.2
-       github.com/klauspost/compress v1.11.7 // indirect
+       github.com/klauspost/compress v1.12.2 // indirect
+       github.com/mdp/qrterminal/v3 v3.0.0
+       github.com/miekg/dns v1.1.41 // indirect
        github.com/mitchellh/mapstructure v1.4.1 // indirect
-       github.com/qydysky/part v0.3.6
+       github.com/qydysky/part v0.5.12
+       github.com/shirou/gopsutil v3.21.4+incompatible // indirect
        github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
-       golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
-       golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
+       github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
+       github.com/tklauser/go-sysconf v0.3.5 // indirect
+       golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
+       golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 // indirect
+       golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 // indirect
 )
diff --git a/go.sum b/go.sum
index 9b3f0603bf40ec3c24c65efe52faa716a28d7868..fce9e539778e8f3321df45a6eab34cebd154383c 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,11 @@
 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 h1:5sXbqlSomvdjlRbWyNqkPsJ3Fg+tQZCbgeX1VGljbQY=
+github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
 github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc=
 github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
+github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E=
+github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
 github.com/christopher-dG/go-obs-websocket v0.0.0-20200720193653-c4fed10356a5 h1:UFBgEMSPv6a2vgzowHOPphVit+ZBNQ3+4Q+dEBgwIww=
 github.com/christopher-dG/go-obs-websocket v0.0.0-20200720193653-c4fed10356a5/go.mod h1:P5w+dDqQEbCMFAkmucNcEQ6xgAt/NP+Aw58OQfY/H/o=
 github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
@@ -10,6 +14,7 @@ github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
 github.com/gofrs/uuid v1.2.0 h1:coDhrjgyJaglxSjxuJdqQSSdUpG3w6p1OwN2od6frBU=
 github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
 github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@@ -20,10 +25,20 @@ github.com/klauspost/compress v1.11.6 h1:EgWPCW6O3n1D5n99Zq3xXBt9uCwRGvpwGOusOLN
 github.com/klauspost/compress v1.11.6/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=
 github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8=
+github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
 github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mdp/qrterminal v1.0.1 h1:07+fzVDlPuBlXS8tB0ktTAyf+Lp1j2+2zK3fBOL5b7c=
+github.com/mdp/qrterminal v1.0.1/go.mod h1:Z33WhxQe9B6CdW37HaVqcRKzP+kByF3q/qLxOGe12xQ=
+github.com/mdp/qrterminal/v3 v3.0.0 h1:ywQqLRBXWTktytQNDKFjhAvoGkLVN3J2tAFZ0kMd9xQ=
+github.com/mdp/qrterminal/v3 v3.0.0/go.mod h1:NJpfAs7OAm77Dy8EkWrtE4aq+cE6McoLXlBqXQEwvE0=
 github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
 github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
 github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
+github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=
+github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
 github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
@@ -31,23 +46,39 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
 github.com/qydysky/part v0.3.1/go.mod h1:93s9ohLtzULet5ZPEUUWrT9BELC30oDZgRpgGSiDye4=
 github.com/qydysky/part v0.3.6 h1:KKmNAhF9VtON5p3AH5ohMjrIwGv1lJKrGqmNwYYxFU0=
 github.com/qydysky/part v0.3.6/go.mod h1:zE9KPP+RD3EQ4wYL14szrB927AU3amyha/2wKPjPWzo=
+github.com/qydysky/part v0.5.10 h1:SYdPGV1DlHFDKjDGBU3dXbuR9WA8NNwTbQ2nDjdyeiA=
+github.com/qydysky/part v0.5.10/go.mod h1:43opuciW71sZvOR67kye50jgMDSDrn/t6+LefNdlXPg=
+github.com/qydysky/part v0.5.12 h1:HnXJ7NmL5kvpFwPSpz5D5Kmg50mTblRP6tIufVsXP+U=
+github.com/qydysky/part v0.5.12/go.mod h1:43opuciW71sZvOR67kye50jgMDSDrn/t6+LefNdlXPg=
 github.com/qydysky/part/msgq v0.0.0-20201213120821-f36e49c32bba h1:1ew9dRpc0Rux0WkWeT/4AE15ynYWmL2D7onJEJIFOB8=
 github.com/qydysky/part/msgq v0.0.0-20201213120821-f36e49c32bba/go.mod h1:w32TkJNVtTJd4LOS09cq+4uYG6itcN2vsqw+slp44Rg=
 github.com/shirou/gopsutil v2.20.7+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/shirou/gopsutil v3.20.12+incompatible h1:6VEGkOXP/eP4o2Ilk8cSsX0PhOEfX6leqAnD+urrp9M=
 github.com/shirou/gopsutil v3.20.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil v3.21.3+incompatible h1:uenXGGa8ESCQq+dbgtl916dmg6PSAz2cXov0uORQ9v8=
+github.com/shirou/gopsutil v3.21.3+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil v3.21.4+incompatible h1:fuHcTm5mX+wzo542cmYcV9RTGQLbnHLI5SyQ5ryTVck=
+github.com/shirou/gopsutil v3.21.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
+github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
+github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
 github.com/thedevsaddam/gojsonq v2.3.0+incompatible h1:i2lFTvGY4LvoZ2VUzedsFlRiyaWcJm3Uh6cQ9+HyQA8=
 github.com/thedevsaddam/gojsonq v2.3.0+incompatible/go.mod h1:RBcQaITThgJAAYKH7FNp2onYodRz8URfsuEGpAch0NA=
 github.com/thedevsaddam/gojsonq/v2 v2.5.2 h1:CoMVaYyKFsVj6TjU6APqAhAvC07hTI6IQen8PHzHYY0=
 github.com/thedevsaddam/gojsonq/v2 v2.5.2/go.mod h1:bv6Xa7kWy82uT0LnXPE2SzGqTj33TAEeR560MdJkiXs=
+github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4=
+github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
+github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA=
+github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -57,8 +88,15 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLD
 golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
 golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk=
+golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 h1:Ugb8sMTWuWRC3+sz5WeN/4kejDx9BvIwnPUiJBjJE+8=
+golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -70,10 +108,20 @@ golang.org/x/sys v0.0.0-20210113000019-eaf3bda374d2 h1:F9vNgpIiamoF+Q1/c78bikg/N
 golang.org/x/sys v0.0.0-20210113000019-eaf3bda374d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
+golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c=
+golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
+rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=