//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,
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{
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{
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{
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{
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{
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{
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{
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,
//有新实例,退出
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,
{//获取牌子列表
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{
})
{//获取
- 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{
}
}
{//切换牌子
- r := reqf.Req()
+ r := reqf.New()
if e := r.Reqf(reqf.Rval{
Url:post_url,
PostStr:post_str,
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{
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{
}
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{
return true
})
- req := reqf.Req()
+ req := reqf.New()
for {
//新调用,此退出
if boot_F_x25Kn.NeedExit(id) {return}
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{
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{
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{
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{
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),
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`,
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{
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,
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`,
#### 其他特性
+- [x] 使用http代理
- [x] cookie加密
- [x] 弹幕自动重连(30s)
- [x] 直播流开播自动下载
"net/url"
"errors"
"bytes"
+ // "runtime"
c "github.com/qydysky/bili_danmu/CV"
F "github.com/qydysky/bili_danmu/F"
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"
query := url_struct.Query()
- r := reqf.Req()
+ r := reqf.New()
if e := r.Reqf(reqf.Rval{
Url:m3u8_url,
Retry:4,
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
}
)
savestream.wait = s.Init()
savestream.cancel = s.Init()
- rr := reqf.Req()
+ rr := reqf.New()
go func(){
savestream.cancel.Wait()
rr.Close()
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: `,"结束")
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,
c "github.com/qydysky/bili_danmu/CV"
F "github.com/qydysky/bili_danmu/F"
+
+ reqf "github.com/qydysky/part/reqf"
)
const (
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: `,`退出`)
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
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,
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`,
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),
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),
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),
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 (
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=
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=
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=
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=
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=
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=
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=
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=
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
)
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=
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=
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=
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=
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=
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=