parent
d2e9e4faeb
commit
763a5aa59d
|
|
@ -28,8 +28,8 @@
|
||||||
* [x] 支持设置代理
|
* [x] 支持设置代理
|
||||||
* [x] 增加openwrt路由器的mipsle二进制
|
* [x] 增加openwrt路由器的mipsle二进制
|
||||||
* [x] 支持从curl命令解析出需要的信息,正如 https://github.com/cxjava/m3u8-downloader 一样
|
* [x] 支持从curl命令解析出需要的信息,正如 https://github.com/cxjava/m3u8-downloader 一样
|
||||||
|
* [x] 显示下载速度、合并ts的速度
|
||||||
* [ ] 支持从一个txt里读取下载列表,批量下载
|
* [ ] 支持从一个txt里读取下载列表,批量下载
|
||||||
* [ ] 显示下载速度、合并ts的速度
|
|
||||||
* [ ] 支持多国语言
|
* [ ] 支持多国语言
|
||||||
## 二次开发操作手册:
|
## 二次开发操作手册:
|
||||||
* 如果只开发命令行版本, 则只需要修改*.go文件, 然后编译 cmd/main.go 即可
|
* 如果只开发命令行版本, 则只需要修改*.go文件, 然后编译 cmd/main.go 即可
|
||||||
|
|
|
||||||
30
download.go
30
download.go
|
|
@ -31,13 +31,15 @@ type TsInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetProgress_Resp struct {
|
type GetProgress_Resp struct {
|
||||||
Percent int
|
Percent int
|
||||||
Title string
|
Title string
|
||||||
SleepTh string
|
StatusBar string
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetProgress() (resp GetProgress_Resp) {
|
func GetProgress() (resp GetProgress_Resp) {
|
||||||
var sleepTh int32
|
var sleepTh int32
|
||||||
|
var speedV string
|
||||||
|
|
||||||
gOldEnvLocker.Lock()
|
gOldEnvLocker.Lock()
|
||||||
if gOldEnv != nil {
|
if gOldEnv != nil {
|
||||||
sleepTh = atomic.LoadInt32(&gOldEnv.sleepTh)
|
sleepTh = atomic.LoadInt32(&gOldEnv.sleepTh)
|
||||||
|
|
@ -48,10 +50,15 @@ func GetProgress() (resp GetProgress_Resp) {
|
||||||
if resp.Title == "" {
|
if resp.Title == "" {
|
||||||
resp.Title = "正在下载"
|
resp.Title = "正在下载"
|
||||||
}
|
}
|
||||||
|
speedV = gOldEnv.speedRecent5sGetAndUpdate()
|
||||||
}
|
}
|
||||||
gOldEnvLocker.Unlock()
|
gOldEnvLocker.Unlock()
|
||||||
|
resp.StatusBar = speedV
|
||||||
if sleepTh > 0 {
|
if sleepTh > 0 {
|
||||||
resp.SleepTh = "有 " + strconv.Itoa(int(sleepTh)) + "个线程正在休眠."
|
if resp.StatusBar != "" {
|
||||||
|
resp.StatusBar += ", "
|
||||||
|
}
|
||||||
|
resp.StatusBar += "有 " + strconv.Itoa(int(sleepTh)) + "个线程正在休眠."
|
||||||
}
|
}
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
@ -90,6 +97,9 @@ type downloadEnv struct {
|
||||||
progressBarTitle string
|
progressBarTitle string
|
||||||
progressPercent int
|
progressPercent int
|
||||||
progressBarShow bool
|
progressBarShow bool
|
||||||
|
speedBytesLocker sync.Mutex
|
||||||
|
speedBeginTime time.Time
|
||||||
|
speedBytesMap map[time.Time]int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp) {
|
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:]
|
tsList = tsList[req.SkipTsCountFromHead:]
|
||||||
// 下载ts
|
// 下载ts
|
||||||
this.SetProgressBarTitle("[4/6]下载ts")
|
this.SetProgressBarTitle("[4/6]下载ts")
|
||||||
|
this.speedSetBegin()
|
||||||
err = this.downloader(tsList, downloadDir, tsKey)
|
err = this.downloader(tsList, downloadDir, tsKey)
|
||||||
|
this.speedClearBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.ErrMsg = "下载ts文件错误: " + err.Error()
|
resp.ErrMsg = "下载ts文件错误: " + err.Error()
|
||||||
resp.IsCancel = this.GetIsCancel()
|
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")
|
tmpOutputName = filepath.Join(downloadDir, "all.merge.mp4")
|
||||||
|
|
||||||
this.SetProgressBarTitle("[5/6]合并ts为mp4")
|
this.SetProgressBarTitle("[5/6]合并ts为mp4")
|
||||||
|
this.speedSetBegin()
|
||||||
err = MergeTsFileListToSingleMp4(MergeTsFileListToSingleMp4_Req{
|
err = MergeTsFileListToSingleMp4(MergeTsFileListToSingleMp4_Req{
|
||||||
TsFileList: tsFileList,
|
TsFileList: tsFileList,
|
||||||
OutputMp4: tmpOutputName,
|
OutputMp4: tmpOutputName,
|
||||||
Ctx: this.ctx,
|
Ctx: this.ctx,
|
||||||
})
|
})
|
||||||
|
this.speedClearBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.ErrMsg = "合并错误: " + err.Error()
|
resp.ErrMsg = "合并错误: " + err.Error()
|
||||||
return resp
|
return resp
|
||||||
|
|
@ -272,6 +286,7 @@ func RunDownload(req RunDownload_Req) (resp RunDownload_Resp) {
|
||||||
},
|
},
|
||||||
Timeout: time.Second * 10,
|
Timeout: time.Second * 10,
|
||||||
},
|
},
|
||||||
|
speedBytesMap: map[time.Time]int64{},
|
||||||
}
|
}
|
||||||
env.ctx, env.cancelFn = context.WithCancel(context.Background())
|
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 {
|
if err != nil {
|
||||||
return err
|
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) {
|
func (this *downloadEnv) SleepDur(d time.Duration) {
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -7,7 +7,7 @@ require (
|
||||||
github.com/orestonce/go2cpp v0.0.0-20220730064838-feb9dd043919
|
github.com/orestonce/go2cpp v0.0.0-20220730064838-feb9dd043919
|
||||||
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171
|
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171
|
||||||
github.com/spf13/cobra v1.4.0
|
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/net v0.0.0-20220617184016-355a448f1bc9
|
||||||
golang.org/x/text v0.3.7
|
golang.org/x/text v0.3.7
|
||||||
)
|
)
|
||||||
|
|
|
||||||
2
go.sum
2
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/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 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-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 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc=
|
||||||
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
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=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ GetProgress_Resp GetProgress(){
|
||||||
uint32_t tmp17 = uint32_t(uint8_t(out[outIdx+3]) << 0);
|
uint32_t tmp17 = uint32_t(uint8_t(out[outIdx+3]) << 0);
|
||||||
tmp13 = tmp14 | tmp15 | tmp16 | tmp17;
|
tmp13 = tmp14 | tmp15 | tmp16 | tmp17;
|
||||||
outIdx+=4;
|
outIdx+=4;
|
||||||
retValue.SleepTh = std::string(out+outIdx, out+outIdx+tmp13);
|
retValue.StatusBar = std::string(out+outIdx, out+outIdx+tmp13);
|
||||||
outIdx+=tmp13;
|
outIdx+=tmp13;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ void CloseOldEnv();
|
||||||
struct GetProgress_Resp{
|
struct GetProgress_Resp{
|
||||||
int32_t Percent;
|
int32_t Percent;
|
||||||
std::string Title;
|
std::string Title;
|
||||||
std::string SleepTh;
|
std::string StatusBar;
|
||||||
GetProgress_Resp(): Percent(0){}
|
GetProgress_Resp(): Percent(0){}
|
||||||
};
|
};
|
||||||
GetProgress_Resp GetProgress();
|
GetProgress_Resp GetProgress();
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
GetProgress_Resp resp = GetProgress();
|
GetProgress_Resp resp = GetProgress();
|
||||||
ui->progressBar->setValue(resp.Percent);
|
ui->progressBar->setValue(resp.Percent);
|
||||||
ui->label_progressBar->setText(QString::fromStdString(resp.Title));
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
21
merge.go
21
merge.go
|
|
@ -4,9 +4,9 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/yapingcat/gomedia/codec"
|
"github.com/yapingcat/gomedia/go-codec"
|
||||||
"github.com/yapingcat/gomedia/mp4"
|
"github.com/yapingcat/gomedia/go-mp4"
|
||||||
"github.com/yapingcat/gomedia/mpeg2"
|
"github.com/yapingcat/gomedia/go-mpeg2"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -66,16 +66,14 @@ func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env := getOldEnv()
|
||||||
|
|
||||||
for idx, tsFile := range req.TsFileList {
|
for idx, tsFile := range req.TsFileList {
|
||||||
select {
|
select {
|
||||||
case <-req.Ctx.Done():
|
case <-req.Ctx.Done():
|
||||||
return req.Ctx.Err()
|
return req.Ctx.Err()
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
tmp := getOldEnv()
|
|
||||||
if tmp != nil {
|
|
||||||
tmp.DrawProgressBar(len(req.TsFileList), idx)
|
|
||||||
}
|
|
||||||
var buf []byte
|
var buf []byte
|
||||||
buf, err = ioutil.ReadFile(tsFile)
|
buf, err = ioutil.ReadFile(tsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -88,6 +86,10 @@ func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error)
|
||||||
if OnFrameErr != nil {
|
if OnFrameErr != nil {
|
||||||
return OnFrameErr
|
return OnFrameErr
|
||||||
}
|
}
|
||||||
|
if env != nil {
|
||||||
|
env.DrawProgressBar(len(req.TsFileList), idx)
|
||||||
|
env.speedAddBytes(len(buf))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = muxer.WriteTrailer()
|
err = muxer.WriteTrailer()
|
||||||
|
|
@ -98,9 +100,8 @@ func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tmp := getOldEnv()
|
if env != nil {
|
||||||
if tmp != nil {
|
env.DrawProgressBar(1, 1)
|
||||||
tmp.DrawProgressBar(1, 1)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue