diff --git a/README.md b/README.md index ae88d58..907f3d2 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ * [x] 支持设置代理 * [x] 增加openwrt路由器的mipsle二进制 * [x] 支持从curl命令解析出需要的信息,正如 https://github.com/cxjava/m3u8-downloader 一样 + * [x] 显示下载速度、合并ts的速度 * [ ] 支持从一个txt里读取下载列表,批量下载 - * [ ] 显示下载速度、合并ts的速度 * [ ] 支持多国语言 ## 二次开发操作手册: * 如果只开发命令行版本, 则只需要修改*.go文件, 然后编译 cmd/main.go 即可 diff --git a/download.go b/download.go index 9f4a004..81d8c7d 100644 --- a/download.go +++ b/download.go @@ -31,13 +31,15 @@ type TsInfo struct { } type GetProgress_Resp struct { - Percent int - Title string - SleepTh string + Percent int + Title string + StatusBar string } func GetProgress() (resp GetProgress_Resp) { var sleepTh int32 + var speedV string + gOldEnvLocker.Lock() if gOldEnv != nil { sleepTh = atomic.LoadInt32(&gOldEnv.sleepTh) @@ -48,10 +50,15 @@ func GetProgress() (resp GetProgress_Resp) { if resp.Title == "" { resp.Title = "正在下载" } + speedV = gOldEnv.speedRecent5sGetAndUpdate() } gOldEnvLocker.Unlock() + resp.StatusBar = speedV if sleepTh > 0 { - resp.SleepTh = "有 " + strconv.Itoa(int(sleepTh)) + "个线程正在休眠." + if resp.StatusBar != "" { + resp.StatusBar += ", " + } + resp.StatusBar += "有 " + strconv.Itoa(int(sleepTh)) + "个线程正在休眠." } return resp } @@ -90,6 +97,9 @@ type downloadEnv struct { progressBarTitle string progressPercent int progressBarShow bool + speedBytesLocker sync.Mutex + speedBeginTime time.Time + speedBytesMap map[time.Time]int64 } func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp) { @@ -183,7 +193,9 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp tsList = tsList[req.SkipTsCountFromHead:] // 下载ts this.SetProgressBarTitle("[4/6]下载ts") + this.speedSetBegin() err = this.downloader(tsList, downloadDir, tsKey) + this.speedClearBytes() if err != nil { resp.ErrMsg = "下载ts文件错误: " + err.Error() resp.IsCancel = this.GetIsCancel() @@ -199,11 +211,13 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp tmpOutputName = filepath.Join(downloadDir, "all.merge.mp4") this.SetProgressBarTitle("[5/6]合并ts为mp4") + this.speedSetBegin() err = MergeTsFileListToSingleMp4(MergeTsFileListToSingleMp4_Req{ TsFileList: tsFileList, OutputMp4: tmpOutputName, Ctx: this.ctx, }) + this.speedClearBytes() if err != nil { resp.ErrMsg = "合并错误: " + err.Error() return resp @@ -272,6 +286,7 @@ func RunDownload(req RunDownload_Req) (resp RunDownload_Resp) { }, Timeout: time.Second * 10, }, + speedBytesMap: map[time.Time]int64{}, } env.ctx, env.cancelFn = context.WithCancel(context.Background()) @@ -411,7 +426,12 @@ func (this *downloadEnv) downloadTsFile(ts TsInfo, download_dir, key string) (er if err != nil { return err } - return os.Rename(tmpPath, currPath) + err = os.Rename(tmpPath, currPath) + if err != nil { + return err + } + this.speedAddBytes(len(origData)) + return nil } func (this *downloadEnv) SleepDur(d time.Duration) { diff --git a/go.mod b/go.mod index c6a230d..4e63a03 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/orestonce/go2cpp v0.0.0-20220730064838-feb9dd043919 github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171 github.com/spf13/cobra v1.4.0 - github.com/yapingcat/gomedia v0.0.0-20220721095559-a283c87d8a0b + github.com/yapingcat/gomedia v0.0.0-20220731053213-04782526c441 golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 golang.org/x/text v0.3.7 ) diff --git a/go.sum b/go.sum index 1c2cce3..d819c48 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/yapingcat/gomedia v0.0.0-20220721095559-a283c87d8a0b h1:ugQfEkchgCe+MBtP/Ih+ypTr1WhlcTHahnIDrS1GXoo= github.com/yapingcat/gomedia v0.0.0-20220721095559-a283c87d8a0b/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc= +github.com/yapingcat/gomedia v0.0.0-20220731053213-04782526c441 h1:SAohYbjWwtDtpjW9GmV6IFDou2CW4MvUXxJtz3FiuR0= +github.com/yapingcat/gomedia v0.0.0-20220731053213-04782526c441/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc= golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc= golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/m3u8d-qt/m3u8d.cpp b/m3u8d-qt/m3u8d.cpp index 32a2a51..6c135b8 100644 --- a/m3u8d-qt/m3u8d.cpp +++ b/m3u8d-qt/m3u8d.cpp @@ -261,7 +261,7 @@ GetProgress_Resp GetProgress(){ uint32_t tmp17 = uint32_t(uint8_t(out[outIdx+3]) << 0); tmp13 = tmp14 | tmp15 | tmp16 | tmp17; outIdx+=4; - retValue.SleepTh = std::string(out+outIdx, out+outIdx+tmp13); + retValue.StatusBar = std::string(out+outIdx, out+outIdx+tmp13); outIdx+=tmp13; } } diff --git a/m3u8d-qt/m3u8d.h b/m3u8d-qt/m3u8d.h index a5dcafa..eb89ec0 100644 --- a/m3u8d-qt/m3u8d.h +++ b/m3u8d-qt/m3u8d.h @@ -31,7 +31,7 @@ void CloseOldEnv(); struct GetProgress_Resp{ int32_t Percent; std::string Title; - std::string SleepTh; + std::string StatusBar; GetProgress_Resp(): Percent(0){} }; GetProgress_Resp GetProgress(); diff --git a/m3u8d-qt/mainwindow.cpp b/m3u8d-qt/mainwindow.cpp index 4b32e82..431aeae 100644 --- a/m3u8d-qt/mainwindow.cpp +++ b/m3u8d-qt/mainwindow.cpp @@ -29,7 +29,7 @@ MainWindow::MainWindow(QWidget *parent) : GetProgress_Resp resp = GetProgress(); ui->progressBar->setValue(resp.Percent); ui->label_progressBar->setText(QString::fromStdString(resp.Title)); - ui->statusBar->showMessage(QString::fromStdString(resp.SleepTh), 5*1000); + ui->statusBar->showMessage(QString::fromStdString(resp.StatusBar), 5*1000); }); } }); diff --git a/merge.go b/merge.go index e76e030..6803f65 100644 --- a/merge.go +++ b/merge.go @@ -4,9 +4,9 @@ import ( "bytes" "context" "errors" - "github.com/yapingcat/gomedia/codec" - "github.com/yapingcat/gomedia/mp4" - "github.com/yapingcat/gomedia/mpeg2" + "github.com/yapingcat/gomedia/go-codec" + "github.com/yapingcat/gomedia/go-mp4" + "github.com/yapingcat/gomedia/go-mpeg2" "io/ioutil" "os" "strconv" @@ -66,16 +66,14 @@ func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) } } + env := getOldEnv() + for idx, tsFile := range req.TsFileList { select { case <-req.Ctx.Done(): return req.Ctx.Err() default: } - tmp := getOldEnv() - if tmp != nil { - tmp.DrawProgressBar(len(req.TsFileList), idx) - } var buf []byte buf, err = ioutil.ReadFile(tsFile) if err != nil { @@ -88,6 +86,10 @@ func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) if OnFrameErr != nil { return OnFrameErr } + if env != nil { + env.DrawProgressBar(len(req.TsFileList), idx) + env.speedAddBytes(len(buf)) + } } err = muxer.WriteTrailer() @@ -98,9 +100,8 @@ func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) if err != nil { return err } - tmp := getOldEnv() - if tmp != nil { - tmp.DrawProgressBar(1, 1) + if env != nil { + env.DrawProgressBar(1, 1) } return nil } diff --git a/speed.go b/speed.go new file mode 100644 index 0000000..95fb49d --- /dev/null +++ b/speed.go @@ -0,0 +1,66 @@ +package m3u8d + +import ( + "strconv" + "time" +) + +func (this *downloadEnv) speedSetBegin() { + this.speedBytesLocker.Lock() + defer this.speedBytesLocker.Unlock() + + this.speedBeginTime = time.Now() +} + +func (this *downloadEnv) speedAddBytes(a int) { + this.speedBytesLocker.Lock() + defer this.speedBytesLocker.Unlock() + + now := time.Now() + this.speedBytesMap[now] += int64(a) +} + +func (this *downloadEnv) speedClearBytes() { + this.speedBytesLocker.Lock() + defer this.speedBytesLocker.Unlock() + + this.speedBytesMap = map[time.Time]int64{} +} + +func (this *downloadEnv) speedRecent5sGetAndUpdate() string { + this.speedBytesLocker.Lock() + defer this.speedBytesLocker.Unlock() + + now := time.Now() + if this.GetIsCancel() || this.speedBeginTime.IsZero() || now.Sub(this.speedBeginTime) < time.Second { // 1s以内, 暂时不计算速度 + return "" + } + + const secondCount = 5 + + expireTime := now.Add(-secondCount * time.Second) + var total int64 + for ct, v := range this.speedBytesMap { + if ct.Before(expireTime) { + delete(this.speedBytesMap, ct) + continue + } + total += v + } + realSecond := now.Sub(this.speedBeginTime).Seconds() + if realSecond > secondCount { + realSecond = secondCount + } + v := float64(total) / realSecond + + if v < 1024 { + return strconv.Itoa(int(v)) + " B/s" + } + v = v / 1024 + if v < 1024 { + return strconv.Itoa(int(v)) + " KB/s" + } + + v = v / 1024 + return strconv.FormatFloat(v, 'f', 2, 64) + " MB/s" +}