From 554eae5185f1b4507932fa476dbafa81c19a617a Mon Sep 17 00:00:00 2001 From: orestonce Date: Sat, 18 Nov 2023 10:57:49 +0800 Subject: [PATCH] =?UTF-8?q?ui=E5=A2=9E=E5=8A=A0=E5=90=88=E5=B9=B6=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.go | 94 +++++++ cmd/main.go | 1 + download.go | 93 +++---- export/main.go | 3 + go.mod | 25 +- go.sum | 64 +++++ m3u8d-qt/m3u8d.cpp | 97 ++++++++ m3u8d-qt/m3u8d.h | 14 ++ m3u8d-qt/mainwindow.cpp | 135 +++++++--- m3u8d-qt/mainwindow.h | 13 + m3u8d-qt/mainwindow.ui | 530 ++++++++++++++++++++++++++-------------- merge.go | 17 +- speed.go | 84 +++++-- speed_test.go | 8 + 14 files changed, 880 insertions(+), 298 deletions(-) create mode 100644 api.go create mode 100644 speed_test.go diff --git a/api.go b/api.go new file mode 100644 index 0000000..b46b74a --- /dev/null +++ b/api.go @@ -0,0 +1,94 @@ +package m3u8d + +import ( + "context" + "io/ioutil" + "path/filepath" + "sort" + "strings" + "sync" + "sync/atomic" +) + +var gMergeStatus SpeedStatus +var gMergeCancel context.CancelFunc +var gMergeCancelLocker sync.Mutex + +type MergeTsDir_Resp struct { + ErrMsg string + IsCancel bool +} + +var gMergeIsRunning atomic.Bool + +func MergeTsDir(InputTsDir string, OutputMp4Name string) (resp MergeTsDir_Resp) { + if !gMergeIsRunning.CompareAndSwap(false, true) { + return resp + } + defer gMergeIsRunning.Store(false) + + fList, err := ioutil.ReadDir(InputTsDir) + if err != nil { + resp.ErrMsg = "读取目录失败 " + err.Error() + return + } + var tsFileList []string + for _, f := range fList { + if f.Mode().IsRegular() && strings.HasSuffix(strings.ToLower(f.Name()), ".ts") { + tsFileList = append(tsFileList, filepath.Join(InputTsDir, f.Name())) + } + } + if len(tsFileList) == 0 { + resp.ErrMsg = "目录下不存在ts文件: " + InputTsDir + return + } + sort.Strings(tsFileList) // 按照字典顺序排序 + if OutputMp4Name == "" { + OutputMp4Name = filepath.Join(InputTsDir, "all.mp4") + } + ctx, cancelFn := context.WithCancel(context.Background()) + defer cancelFn() + + gMergeCancelLocker.Lock() + if gMergeCancel != nil { + gMergeCancel() + } + gMergeCancel = cancelFn + gMergeCancelLocker.Unlock() + + err = MergeTsFileListToSingleMp4(MergeTsFileListToSingleMp4_Req{ + TsFileList: tsFileList, + OutputMp4: OutputMp4Name, + Ctx: ctx, + Status: &gMergeStatus, + }) + if err != nil { + resp.ErrMsg = "合并错误: " + err.Error() + resp.IsCancel = isContextCancel(ctx) + return resp + } + return resp +} + +type MergeGetProgressPercent_Resp struct { + Percent int + SpeedText string + IsRunning bool +} + +func MergeGetProgressPercent() (resp MergeGetProgressPercent_Resp) { + resp.IsRunning = gMergeIsRunning.Load() + if resp.IsRunning { + resp.Percent = gMergeStatus.GetPercent() + resp.SpeedText = gMergeStatus.SpeedRecent5sGetAndUpdate() + } + return resp +} + +func MergeStop() { + gMergeCancelLocker.Lock() + if gMergeCancel != nil { + gMergeCancel() + } + gMergeCancelLocker.Unlock() +} diff --git a/cmd/main.go b/cmd/main.go index c67d3b2..fd830f6 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -96,6 +96,7 @@ var mergeCmd = &cobra.Command{ TsFileList: tsFileList, OutputMp4: gMergeReq.OutputMp4Name, Ctx: context.Background(), + Status: nil, }) if err != nil { log.Fatalln("合并失败", err) diff --git a/download.go b/download.go index eb07902..1730a83 100644 --- a/download.go +++ b/download.go @@ -50,14 +50,14 @@ func GetProgress() (resp GetProgress_Resp) { gOldEnvLocker.Lock() if gOldEnv != nil { sleepTh = atomic.LoadInt32(&gOldEnv.sleepTh) - gOldEnv.progressLocker.Lock() - resp.Percent = gOldEnv.progressPercent - resp.Title = gOldEnv.progressBarTitle - gOldEnv.progressLocker.Unlock() + resp.Percent = gOldEnv.status.GetPercent() + resp.Title = gOldEnv.status.GetTitle() if resp.Title == "" { resp.Title = "正在下载" } - speedV = gOldEnv.speedRecent5sGetAndUpdate() + if !gOldEnv.GetIsCancel() { + speedV = gOldEnv.status.SpeedRecent5sGetAndUpdate() + } } gOldEnvLocker.Unlock() resp.StatusBar = speedV @@ -70,12 +70,6 @@ func GetProgress() (resp GetProgress_Resp) { return resp } -func (this *downloadEnv) SetProgressBarTitle(title string) { - this.progressLocker.Lock() - this.progressBarTitle = title - this.progressLocker.Unlock() -} - type RunDownload_Resp struct { ErrMsg string IsSkipped bool @@ -97,18 +91,12 @@ type RunDownload_Req struct { } type downloadEnv struct { - cancelFn func() - ctx context.Context - nowClient *http.Client - header http.Header - sleepTh int32 - progressLocker sync.Mutex - progressBarTitle string - progressPercent int - progressBarShow bool - speedBytesLocker sync.Mutex - speedBeginTime time.Time - speedBytesMap map[time.Time]int64 + cancelFn func() + ctx context.Context + nowClient *http.Client + header http.Header + sleepTh int32 + status SpeedStatus } func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp) { @@ -142,7 +130,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp for key, valueList := range req.HeaderMap { this.header[key] = valueList } - this.SetProgressBarTitle("[1/6]嗅探m3u8") + this.status.SetProgressBarTitle("[1/6]嗅探m3u8") var m3u8Body []byte var errMsg string req.M3u8Url, m3u8Body, errMsg = this.sniffM3u8(req.M3u8Url) @@ -162,7 +150,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp return resp } if info != nil { - this.SetProgressBarTitle("[2/6]检查是否已下载") + this.status.SetProgressBarTitle("[2/6]检查是否已下载") latestNameFullPath, found := info.SearchVideoInDir(req.SaveDir) if found { resp.IsSkipped = true @@ -200,7 +188,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp resp.IsCancel = this.GetIsCancel() return resp } - this.SetProgressBarTitle("[3/6]获取ts列表") + this.status.SetProgressBarTitle("[3/6]获取ts列表") tsList, errMsg := getTsList(beginSeq, req.M3u8Url, string(m3u8Body)) if errMsg != "" { resp.ErrMsg = "获取ts列表错误: " + errMsg @@ -212,16 +200,16 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp } tsList = tsList[req.SkipTsCountFromHead:] // 下载ts - this.SetProgressBarTitle("[4/6]下载ts") - this.speedSetBegin() + this.status.SetProgressBarTitle("[4/6]下载ts") + this.status.SpeedResetBytes() err = this.downloader(tsList, downloadDir, encInfo, req.ThreadCount) - this.speedClearBytes() + this.status.SpeedResetBytes() if err != nil { resp.ErrMsg = "下载ts文件错误: " + err.Error() resp.IsCancel = this.GetIsCancel() return resp } - this.DrawProgressBar(1, 1) + this.status.DrawProgressBar(1, 1) var tsFileList []string for _, one := range tsList { tsFileList = append(tsFileList, filepath.Join(downloadDir, one.Name)) @@ -230,19 +218,19 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp var contentHash string tmpOutputName = filepath.Join(downloadDir, "all.merge.mp4") - this.SetProgressBarTitle("[5/6]合并ts为mp4") - this.speedSetBegin() + this.status.SetProgressBarTitle("[5/6]合并ts为mp4") err = MergeTsFileListToSingleMp4(MergeTsFileListToSingleMp4_Req{ TsFileList: tsFileList, OutputMp4: tmpOutputName, Ctx: this.ctx, + Status: &this.status, }) - this.speedClearBytes() + this.status.SpeedResetBytes() if err != nil { resp.ErrMsg = "合并错误: " + err.Error() return resp } - this.SetProgressBarTitle("[6/6]计算文件hash") + this.status.SetProgressBarTitle("[6/6]计算文件hash") contentHash = getFileSha256(tmpOutputName) if contentHash == "" { resp.ErrMsg = "无法计算摘要信息: " + tmpOutputName @@ -320,8 +308,9 @@ func RunDownload(req RunDownload_Req) (resp RunDownload_Resp) { Proxy: http.ProxyURL(proxyUrlObj), }, }, - speedBytesMap: map[time.Time]int64{}, - progressBarShow: req.ProgressBarShow, + status: SpeedStatus{ + progressBarShow: req.ProgressBarShow, + }, } env.ctx, env.cancelFn = context.WithCancel(context.Background()) @@ -332,8 +321,8 @@ func RunDownload(req RunDownload_Req) (resp RunDownload_Resp) { gOldEnv = env gOldEnvLocker.Unlock() resp = env.RunDownload(req) - env.SetProgressBarTitle("下载进度") - env.DrawProgressBar(1, 0) + env.status.SetProgressBarTitle("下载进度") + env.status.DrawProgressBar(1, 0) return resp } @@ -483,7 +472,7 @@ func (this *downloadEnv) downloadTsFile(ts TsInfo, download_dir string, encInfo if err != nil { return err } - this.speedAddBytes(len(origData)) + this.status.SpeedAddBytes(len(origData)) return nil } @@ -536,7 +525,7 @@ func (this *downloadEnv) downloader(tsList []TsInfo, downloadDir string, encInfo } locker.Lock() downloadCount++ - this.DrawProgressBar(tsLen, downloadCount) + this.status.DrawProgressBar(tsLen, downloadCount) locker.Unlock() }) } @@ -545,24 +534,6 @@ func (this *downloadEnv) downloader(tsList []TsInfo, downloadDir string, encInfo return err } -// 进度条 -func (this *downloadEnv) DrawProgressBar(total int, current int) { - if total == 0 { - return - } - proportion := float32(current) / float32(total) - - this.progressLocker.Lock() - this.progressPercent = int(proportion * 100) - title := this.progressBarTitle - if this.progressBarShow { - width := 50 - pos := int(proportion * float32(width)) - fmt.Printf(title+" %s%*s %6.2f%%\r", strings.Repeat("■", pos), width-pos, "", proportion*100) - } - this.progressLocker.Unlock() -} - func isFileExists(path string) bool { stat, err := os.Stat(path) return err == nil && stat.Mode().IsRegular() @@ -710,8 +681,12 @@ func (this *downloadEnv) doGetRequest(urlS string) (data []byte, err error) { } func (this *downloadEnv) GetIsCancel() bool { + return isContextCancel(this.ctx) +} + +func isContextCancel(ctx context.Context) bool { select { - case <-this.ctx.Done(): + case <-ctx.Done(): return true default: return false diff --git a/export/main.go b/export/main.go index bbcd99a..fe6c010 100644 --- a/export/main.go +++ b/export/main.go @@ -95,6 +95,9 @@ func CreateLibForQtUi(mode string) { ctx.Generate1(m3u8d.ParseCurlStr) ctx.Generate1(m3u8d.RunDownload_Req_ToCurlStr) ctx.Generate1(m3u8d.GetFileNameFromUrl) + ctx.Generate1(m3u8d.MergeTsDir) + ctx.Generate1(m3u8d.MergeStop) + ctx.Generate1(m3u8d.MergeGetProgressPercent) if mode == "amd64-static" { ctx.MustCreateAmd64LibraryInDir("m3u8d-qt") } else if mode == "386-static" { diff --git a/go.mod b/go.mod index 545a3d2..0903271 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,33 @@ require ( github.com/orestonce/cdb v0.0.0-20220528005855-d187c22240e2 github.com/orestonce/go2cpp v0.0.0-20220802140809-b2a921a62a07 github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171 - github.com/spf13/cobra v1.4.0 + github.com/spf13/cobra v1.8.0 github.com/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5 golang.org/x/text v0.3.3 ) require ( - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/cilium/ebpf v0.12.3 // indirect + github.com/cosiner/argv v0.1.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect + github.com/derekparker/trie v0.0.0-20230829180723-39f4de51ef7d // indirect + github.com/go-delve/delve v1.21.2 // indirect + github.com/go-delve/liner v1.2.3-0.20220127212407-d32d89dd2a5d // indirect + github.com/google/go-dap v0.11.0 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.5 // indirect + go.starlark.net v0.0.0-20231101134539-556fd59b42f6 // indirect + golang.org/x/arch v0.6.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index a7397d6..64dcfc8 100644 --- a/go.sum +++ b/go.sum @@ -1,21 +1,85 @@ +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= +github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= +github.com/cosiner/argv v0.1.0 h1:BVDiEL32lwHukgJKP87btEPenzrrHUjajs/8yzaqcXg= +github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/derekparker/trie v0.0.0-20230829180723-39f4de51ef7d h1:hUWoLdw5kvo2xCsqlsIBMvWUc1QCSsCYD2J2+Fg6YoU= +github.com/derekparker/trie v0.0.0-20230829180723-39f4de51ef7d/go.mod h1:C7Es+DLenIpPc9J6IYw4jrK0h7S9bKj4DNl8+KxGEXU= +github.com/go-delve/delve v1.21.2 h1:eaS+ziJo+660mi3D2q/VP8RxW5GcF4Y1zyKSi82alsU= +github.com/go-delve/delve v1.21.2/go.mod h1:FgTAiRUe43RS5EexL06RPyMtP8AMZVL/t9Qqgy3qUe4= +github.com/go-delve/liner v1.2.3-0.20220127212407-d32d89dd2a5d h1:pxjSLshkZJGLVm0wv20f/H0oTWiq/egkoJQ2ja6LEvo= +github.com/go-delve/liner v1.2.3-0.20220127212407-d32d89dd2a5d/go.mod h1:biJCRbqp51wS+I92HMqn5H8/A0PAhxn2vyOT+JqhiGI= +github.com/google/go-dap v0.11.0 h1:SpAZJL41rOOvd85PuLCCLE1dteTQOyKNnn0H3DBHywo= +github.com/google/go-dap v0.11.0/go.mod h1:HAeyoSd2WIfTfg+0GRXcFrb+RnojAtGNh+k+XTIxJDE= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/orestonce/cdb v0.0.0-20220528005855-d187c22240e2 h1:AmGkuxSIOW0gA/jetY8d1DVV0cyQ08FMCxa1arkI6HQ= github.com/orestonce/cdb v0.0.0-20220528005855-d187c22240e2/go.mod h1:HMNNdA1LMQFJRwobtCzVevWcInFSo9rfs1fYeVYwU+c= github.com/orestonce/go2cpp v0.0.0-20220802140809-b2a921a62a07 h1:nyt0GDiskod5Y9uNVrXgK7PZHeL7Ab1uVc3LhLg7/gk= github.com/orestonce/go2cpp v0.0.0-20220802140809-b2a921a62a07/go.mod h1:1fsOAZftk08/dOTRqlp6f/MVwaEKOhrnPUg0RtWiSdY= github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171 h1:NnOl6HTrhrlTT7aaAybVOtq+fEztGFMoQtegckgwLdk= github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171/go.mod h1:MCQUrAPiG9/PTjHJuGqWLasKbIaG6z62KO6kfp90byM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5 h1:dswmlgf8sSrjaQJCGDpmI14sIkHqyIZdP6Jwzl7gVDY= github.com/yapingcat/gomedia v0.0.0-20221023155149-c5f2f0f45ca5/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc= +go.starlark.net v0.0.0-20231101134539-556fd59b42f6 h1:+eC0F/k4aBLC4szgOcjd7bDTEnpxADJyWJE0yowgM3E= +go.starlark.net v0.0.0-20231101134539-556fd59b42f6/go.mod h1:LcLNIzVOMp4oV+uusnpk+VU+SzXaJakUuBjoCSWH5dM= +golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= +golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c h1:3kC/TjQ+xzIblQv39bCOyRk8fbEeJcDHwbyxPUU2BpA= +golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/m3u8d-qt/m3u8d.cpp b/m3u8d-qt/m3u8d.cpp index b49e4e5..2cc60ae 100644 --- a/m3u8d-qt/m3u8d.cpp +++ b/m3u8d-qt/m3u8d.cpp @@ -82,6 +82,9 @@ extern __declspec(dllexport) void Go2cppFn_GetWd(char* in, int inLen, char** out extern __declspec(dllexport) void Go2cppFn_ParseCurlStr(char* in, int inLen, char** out, int* outLen); extern __declspec(dllexport) void Go2cppFn_RunDownload_Req_ToCurlStr(char* in, int inLen, char** out, int* outLen); extern __declspec(dllexport) void Go2cppFn_GetFileNameFromUrl(char* in, int inLen, char** out, int* outLen); +extern __declspec(dllexport) void Go2cppFn_MergeTsDir(char* in, int inLen, char** out, int* outLen); +extern __declspec(dllexport) void Go2cppFn_MergeStop(char* in, int inLen, char** out, int* outLen); +extern __declspec(dllexport) void Go2cppFn_MergeGetProgressPercent(char* in, int inLen, char** out, int* outLen); #ifdef __cplusplus } @@ -625,6 +628,100 @@ std::string GetFileNameFromUrl(std::string in0){ return retValue; } +MergeTsDir_Resp MergeTsDir(std::string in0, std::string in1){ + std::string in; + { + uint32_t tmp9 = in0.length(); + char tmp10[4]; + tmp10[0] = (uint32_t(tmp9) >> 24) & 0xFF; + tmp10[1] = (uint32_t(tmp9) >> 16) & 0xFF; + tmp10[2] = (uint32_t(tmp9) >> 8) & 0xFF; + tmp10[3] = (uint32_t(tmp9) >> 0) & 0xFF; + in.append(tmp10, 4); + in.append(in0); + } + { + uint32_t tmp11 = in1.length(); + char tmp12[4]; + tmp12[0] = (uint32_t(tmp11) >> 24) & 0xFF; + tmp12[1] = (uint32_t(tmp11) >> 16) & 0xFF; + tmp12[2] = (uint32_t(tmp11) >> 8) & 0xFF; + tmp12[3] = (uint32_t(tmp11) >> 0) & 0xFF; + in.append(tmp12, 4); + in.append(in1); + } + char *out = NULL; + int outLen = 0; + Go2cppFn_MergeTsDir((char *)in.data(), in.length(), &out, &outLen); + MergeTsDir_Resp retValue; + int outIdx = 0; + { + { + uint32_t tmp13 = 0; + uint32_t tmp14 = uint32_t(uint8_t(out[outIdx+0]) << 24); + uint32_t tmp15 = uint32_t(uint8_t(out[outIdx+1]) << 16); + uint32_t tmp16 = uint32_t(uint8_t(out[outIdx+2]) << 8); + uint32_t tmp17 = uint32_t(uint8_t(out[outIdx+3]) << 0); + tmp13 = tmp14 | tmp15 | tmp16 | tmp17; + outIdx+=4; + retValue.ErrMsg = std::string(out+outIdx, out+outIdx+tmp13); + outIdx+=tmp13; + } + retValue.IsCancel = (bool) out[outIdx]; + outIdx++; + } + if (out != NULL) { + free(out); + } + return retValue; +} + +void MergeStop(){ + std::string in; + char *out = NULL; + int outLen = 0; + Go2cppFn_MergeStop((char *)in.data(), in.length(), &out, &outLen); + if (out != NULL) { + free(out); + } +} + +MergeGetProgressPercent_Resp MergeGetProgressPercent(){ + std::string in; + char *out = NULL; + int outLen = 0; + Go2cppFn_MergeGetProgressPercent((char *)in.data(), in.length(), &out, &outLen); + MergeGetProgressPercent_Resp retValue; + int outIdx = 0; + { + { + uint32_t tmp4 = uint32_t(uint8_t(out[outIdx+0]) << 24); + uint32_t tmp5 = uint32_t(uint8_t(out[outIdx+1]) << 16); + uint32_t tmp6 = uint32_t(uint8_t(out[outIdx+2]) << 8); + uint32_t tmp7 = uint32_t(uint8_t(out[outIdx+3]) << 0); + retValue.Percent = tmp4 | tmp5 | tmp6 | tmp7; + outIdx+=4; + } + { + uint32_t tmp8 = 0; + uint32_t tmp9 = uint32_t(uint8_t(out[outIdx+0]) << 24); + uint32_t tmp10 = uint32_t(uint8_t(out[outIdx+1]) << 16); + uint32_t tmp11 = uint32_t(uint8_t(out[outIdx+2]) << 8); + uint32_t tmp12 = uint32_t(uint8_t(out[outIdx+3]) << 0); + tmp8 = tmp9 | tmp10 | tmp11 | tmp12; + outIdx+=4; + retValue.SpeedText = std::string(out+outIdx, out+outIdx+tmp8); + outIdx+=tmp8; + } + retValue.IsRunning = (bool) out[outIdx]; + outIdx++; + } + if (out != NULL) { + free(out); + } + return retValue; +} + // Qt: diff --git a/m3u8d-qt/m3u8d.h b/m3u8d-qt/m3u8d.h index c1f79d8..0371951 100644 --- a/m3u8d-qt/m3u8d.h +++ b/m3u8d-qt/m3u8d.h @@ -45,6 +45,20 @@ struct ParseCurl_Resp{ ParseCurl_Resp ParseCurlStr(std::string in0); std::string RunDownload_Req_ToCurlStr(RunDownload_Req in0); std::string GetFileNameFromUrl(std::string in0); +struct MergeTsDir_Resp{ + std::string ErrMsg; + bool IsCancel; + MergeTsDir_Resp(): IsCancel(false){} +}; +MergeTsDir_Resp MergeTsDir(std::string in0, std::string in1); +void MergeStop(); +struct MergeGetProgressPercent_Resp{ + int32_t Percent; + std::string SpeedText; + bool IsRunning; + MergeGetProgressPercent_Resp(): Percent(0),IsRunning(false){} +}; +MergeGetProgressPercent_Resp MergeGetProgressPercent(); #include #include diff --git a/m3u8d-qt/mainwindow.cpp b/m3u8d-qt/mainwindow.cpp index a10eda8..f235feb 100644 --- a/m3u8d-qt/mainwindow.cpp +++ b/m3u8d-qt/mainwindow.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "curldialog.h" MainWindow::MainWindow(QWidget *parent) : @@ -19,22 +22,33 @@ MainWindow::MainWindow(QWidget *parent) : ui->lineEdit_SkipTsCountFromHead->setValidator(vd); ui->lineEdit_SkipTsCountFromHead->setPlaceholderText("[0,9999]"); ui->lineEdit_SaveDir->setPlaceholderText(QString::fromStdString(GetWd())); - m_syncUi.AddRunFnOn_OtherThread([this](){ - while(!this->m_syncUi.Get_Done()) + m_timer = new QTimer(this); + connect(m_timer, &QTimer::timeout, [this](){ + //更新ui1 { - QThread::msleep(50); - m_syncUi.AddRunFnOn_UiThread([this](){ - GetProgress_Resp resp = GetProgress(); - ui->progressBar->setValue(resp.Percent); - ui->label_progressBar->setText(QString::fromStdString(resp.Title)); + GetProgress_Resp resp = GetProgress(); + ui->progressBar->setValue(resp.Percent); + ui->label_progressBar->setText(QString::fromStdString(resp.Title)); + if(!resp.StatusBar.empty()) ui->statusBar->showMessage(QString::fromStdString(resp.StatusBar), 5*1000); - }); + } + + //更新ui2 + { + auto resp = MergeGetProgressPercent(); + ui->progressBar_merge->setValue(resp.Percent); + if(!resp.SpeedText.empty()) + ui->statusBar->showMessage(QString::fromStdString(resp.SpeedText), 5*1000); } }); + m_timer->start(50); + this->updateDownloadUi(false); + this->updateMergeUi(false); } MainWindow::~MainWindow() { + m_timer->stop(); CloseOldEnv(); delete ui; } @@ -44,19 +58,7 @@ void MainWindow::on_pushButton_RunDownload_clicked() if (ui->lineEdit_M3u8Url->isEnabled()==false) { return; } - ui->lineEdit_M3u8Url->setEnabled(false); - ui->lineEdit_SaveDir->setEnabled(false); - ui->pushButton_SaveDir->setEnabled(false); - ui->lineEdit_FileName->setEnabled(false); - ui->lineEdit_SkipTsCountFromHead->setEnabled(false); - ui->pushButton_RunDownload->setEnabled(false); - ui->checkBox_Insecure->setEnabled(false); - ui->progressBar->setValue(0); - ui->lineEdit_SetProxy->setEnabled(false); - ui->pushButton_curlMode->setEnabled(false); - ui->checkBox_SkipRemoveTs->setEnabled(false); - ui->lineEdit_ThreadCount->setEnabled(false); - ui->pushButton_StopDownload->setEnabled(true); + updateDownloadUi(true); RunDownload_Req req; req.M3u8Url = ui->lineEdit_M3u8Url->text().toStdString(); @@ -72,19 +74,7 @@ void MainWindow::on_pushButton_RunDownload_clicked() m_syncUi.AddRunFnOn_OtherThread([req, this](){ RunDownload_Resp resp = RunDownload(req); m_syncUi.AddRunFnOn_UiThread([req, this, resp](){ - ui->lineEdit_M3u8Url->setEnabled(true); - ui->lineEdit_SaveDir->setEnabled(true); - ui->pushButton_SaveDir->setEnabled(true); - ui->lineEdit_FileName->setEnabled(true); - ui->lineEdit_SkipTsCountFromHead->setEnabled(true); - ui->pushButton_RunDownload->setEnabled(true); - ui->checkBox_Insecure->setEnabled(true); - ui->pushButton_RunDownload->setText("开始下载"); - ui->lineEdit_SetProxy->setEnabled(true); - ui->pushButton_StopDownload->setEnabled(false); - ui->pushButton_curlMode->setEnabled(true); - ui->checkBox_SkipRemoveTs->setEnabled(true); - ui->lineEdit_ThreadCount->setEnabled(true); + this->updateDownloadUi(false); if (resp.IsCancel) { return; } @@ -142,3 +132,80 @@ void MainWindow::on_lineEdit_M3u8Url_textChanged(const QString &arg1) } ui->lineEdit_FileName->setPlaceholderText(fileName); } + +void MainWindow::on_pushButton_returnDownload_clicked() +{ + ui->stackedWidget->setCurrentIndex(0); +} + +void MainWindow::on_pushButton_gotoMergeTs_clicked() +{ + ui->stackedWidget->setCurrentIndex(1); +} + +void MainWindow::on_pushButton_startMerge_clicked() +{ + QString fileName = ui->lineEdit_mergeFileName->text(); + if(fileName.isEmpty()) + fileName = ui->lineEdit_mergeFileName->placeholderText(); + QString dir = ui->lineEdit_mergeDir->text(); + + this->updateMergeUi(true); + + m_syncUi.AddRunFnOn_OtherThread([=](){ + auto resp = MergeTsDir(dir.toStdString(), fileName.toStdString()); + + m_syncUi.AddRunFnOn_UiThread([=](){ + this->updateMergeUi(false); + if(resp.ErrMsg.empty()) + Toast::Instance()->SetSuccess("合并成功!"); + else if(!resp.IsCancel) + QMessageBox::warning(this, "下载错误", QString::fromStdString(resp.ErrMsg)); + }); + }); +} + +void MainWindow::on_pushButton_stopMerge_clicked() +{ + MergeStop(); +} + +void MainWindow::on_toolButton_selectMergeDir_clicked() +{ + QString dir = QFileDialog::getExistingDirectory(this); + if(dir.isEmpty()) + return; + ui->lineEdit_mergeDir->setText(dir); +} + +void MainWindow::updateDownloadUi(bool runing) +{ + ui->lineEdit_M3u8Url->setEnabled(!runing); + ui->lineEdit_SaveDir->setEnabled(!runing); + ui->pushButton_SaveDir->setEnabled(!runing); + ui->lineEdit_FileName->setEnabled(!runing); + ui->lineEdit_SkipTsCountFromHead->setEnabled(!runing); + ui->pushButton_RunDownload->setEnabled(!runing); + ui->checkBox_Insecure->setEnabled(!runing); + if(runing == false) + ui->pushButton_RunDownload->setText("开始下载"); + ui->lineEdit_SetProxy->setEnabled(!runing); + ui->pushButton_StopDownload->setEnabled(runing); + ui->pushButton_curlMode->setEnabled(!runing); + ui->checkBox_SkipRemoveTs->setEnabled(!runing); + ui->lineEdit_ThreadCount->setEnabled(!runing); + + if(runing == false) + ui->progressBar->setValue(0); + + ui->pushButton_gotoMergeTs->setEnabled(!runing); +} + +void MainWindow::updateMergeUi(bool runing) +{ + ui->lineEdit_mergeDir->setEnabled(!runing); + ui->toolButton_selectMergeDir->setEnabled(!runing); + ui->pushButton_stopMerge->setEnabled(runing); + ui->lineEdit_mergeFileName->setEnabled(!runing); + ui->pushButton_returnDownload->setEnabled(!runing); +} diff --git a/m3u8d-qt/mainwindow.h b/m3u8d-qt/mainwindow.h index 2cc3b52..d0ce725 100644 --- a/m3u8d-qt/mainwindow.h +++ b/m3u8d-qt/mainwindow.h @@ -27,9 +27,22 @@ private slots: void on_lineEdit_M3u8Url_textChanged(const QString &arg1); + void on_pushButton_returnDownload_clicked(); + + void on_pushButton_gotoMergeTs_clicked(); + + void on_pushButton_startMerge_clicked(); + + void on_pushButton_stopMerge_clicked(); + + void on_toolButton_selectMergeDir_clicked(); +private: + void updateDownloadUi(bool runing); + void updateMergeUi(bool runing); private: Ui::MainWindow *ui; RunOnUiThread m_syncUi; + QTimer *m_timer = nullptr; std::map> m_HeaderMap; }; diff --git a/m3u8d-qt/mainwindow.ui b/m3u8d-qt/mainwindow.ui index b9ceca3..31044ee 100644 --- a/m3u8d-qt/mainwindow.ui +++ b/m3u8d-qt/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 762 - 271 + 857 + 297 @@ -16,185 +16,359 @@ - - - - - m3u8的url - - - - - - - - - - - - - - curl模式 - - - - - - - 保存位置 - - - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 99999 - 99999 - - - - ... - - - - - - - 保存的文件名 - - - - - - - all - - - - - - - 跳过前面几个TS - - - - - - - - - - 代理设置 - - - - - - - - - - http://127.0.0.1:8080 socks5://127.0.0.1:1089 - - - - - - - 下载线程数 - - - - - - - 8 - - - [1,1000] - - - - - - - - - 允许不安全的https请求 + + + 1 + + + + + + + + + + + 8 + + + [1,1000] + + + + + + + 保存的文件名 + + + + + + + all + + + + + + + m3u8的url + + + + + + + curl模式 + + + + + + + 保存位置 + + + + + + + 跳过前面几个TS + + + + + + + 下载线程数 + + + + + + + 代理设置 + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 99999 + 99999 + + + + ... + + + + + + + + + + http://127.0.0.1:8080 socks5://127.0.0.1:1089 + + + + + + + + + 允许不安全的https请求 + + + + + + + 不删除下载的ts文件 + + + + + + + Qt::Vertical + + + + 20 + 25 + + + + + + + + + + 下载进度 + + + + + + + 0 + + + + + + + 合并ts + + + + + + + 开始下载 + + + + + + + false + + + 停止下载 + + + + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 文件夹: + + + + + + + + + + ... + + + + + + + + + 0 + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 输出文件名: + + + + + + + all.mp4 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + 进度 + + + + + + + 0 + + + + + + + 返回 + + + + + + + 开始合并 + + + + + + + 停止合并 + + + + + + + - - - - 不删除下载的ts文件 - - - - - - - Qt::Vertical - - - - 20 - 25 - - - - - - - - - - 下载进度 - - - - - - - 0 - - - - - - - 开始下载 - - - - - - - false - - - 停止下载 - - - - - diff --git a/merge.go b/merge.go index 64701a7..957fbb7 100644 --- a/merge.go +++ b/merge.go @@ -15,6 +15,7 @@ import ( type MergeTsFileListToSingleMp4_Req struct { TsFileList []string OutputMp4 string + Status *SpeedStatus Ctx context.Context } @@ -25,6 +26,10 @@ func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) } defer mp4file.Close() + if req.Status != nil { + req.Status.SpeedResetBytes() + } + muxer, err := mp4.CreateMp4Muxer(mp4file) if err != nil { return err @@ -67,8 +72,6 @@ func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) } } - env := getOldEnv() - for idx, tsFile := range req.TsFileList { select { case <-req.Ctx.Done(): @@ -87,9 +90,9 @@ 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)) + if req.Status != nil { + req.Status.DrawProgressBar(len(req.TsFileList), idx) + req.Status.SpeedAddBytes(len(buf)) } } @@ -101,8 +104,8 @@ func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) if err != nil { return err } - if env != nil { - env.DrawProgressBar(1, 1) + if req.Status != nil { + req.Status.DrawProgressBar(1, 1) } return nil } diff --git a/speed.go b/speed.go index 95fb49d..0757896 100644 --- a/speed.go +++ b/speed.go @@ -1,39 +1,68 @@ package m3u8d import ( + "fmt" "strconv" + "strings" + "sync" "time" ) -func (this *downloadEnv) speedSetBegin() { +type SpeedStatus struct { + speedBytesLocker sync.Mutex + speedBeginTime time.Time + speedBytesMap map[time.Time]int64 + + progressLocker sync.Mutex + progressPercent int + progressBarTitle string + progressBarShow bool +} + +func (this *SpeedStatus) DrawProgressBar(total int, current int) { + if total == 0 { + return + } + proportion := float32(current) / float32(total) + + this.progressLocker.Lock() + this.progressPercent = int(proportion * 100) + title := this.progressBarTitle + if this.progressBarShow { + width := 50 + pos := int(proportion * float32(width)) + fmt.Printf(title+" %s%*s %6.2f%%\r", strings.Repeat("■", pos), width-pos, "", proportion*100) + } + this.progressLocker.Unlock() +} + +func (this *SpeedStatus) SpeedAddBytes(a int) { + this.speedBytesLocker.Lock() + defer this.speedBytesLocker.Unlock() + + now := time.Now() + + this.speedBytesMap[now] += int64(a) +} + +func (this *SpeedStatus) SpeedResetBytes() { 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() - + if this.speedBytesMap == nil { + this.speedBytesMap = map[time.Time]int64{} + } this.speedBytesMap = map[time.Time]int64{} } -func (this *downloadEnv) speedRecent5sGetAndUpdate() string { +func (this *SpeedStatus) 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 "" + if this.speedBeginTime.IsZero() || now.Sub(this.speedBeginTime) < time.Second { // 1s以内, 暂时不计算速度 + return "x1 " + strconv.FormatBool(this.speedBeginTime.IsZero()) + " " + strconv.FormatBool(now.Sub(this.speedBeginTime) < time.Second) } const secondCount = 5 @@ -64,3 +93,22 @@ func (this *downloadEnv) speedRecent5sGetAndUpdate() string { v = v / 1024 return strconv.FormatFloat(v, 'f', 2, 64) + " MB/s" } + +func (this *SpeedStatus) GetPercent() (percent int) { + this.progressLocker.Lock() + defer this.progressLocker.Unlock() + + return this.progressPercent +} + +func (this *SpeedStatus) GetTitle() (title string) { + this.progressLocker.Lock() + defer this.progressLocker.Unlock() + + return this.progressBarTitle +} +func (this *SpeedStatus) SetProgressBarTitle(title string) { + this.progressLocker.Lock() + this.progressBarTitle = title + this.progressLocker.Unlock() +} diff --git a/speed_test.go b/speed_test.go new file mode 100644 index 0000000..24cb040 --- /dev/null +++ b/speed_test.go @@ -0,0 +1,8 @@ +package m3u8d + +import "testing" + +func TestSpeedStatus_GetPercent(t *testing.T) { + var status SpeedStatus + status.SpeedResetBytes() +}