save
parent
7558dae4a2
commit
34aa6764c3
|
|
@ -15,7 +15,7 @@
|
|||
* downloading/ 目录, 用于存放正在下载的分段ts视频, 按照m3u8的url进行划分
|
||||
* m3u8d_cache.cdb 文件, 用于存放以前的下载历史, 用于防止重复下载文件
|
||||
* 重复下载文件的判定和跳过
|
||||
* 将除了保存位置和保存文件名以外的参数进行hash, 得到文件下载id
|
||||
* 将M3u8Url+SkipTsCountFromHead进行hash, 得到文件下载id
|
||||
* 将文件下载id/文件大小/文件内容hash 储存在 m3u8_cache.cdb里面, 下载前搜索下载目录
|
||||
如果发现某个文件大小/文件内容hash和以前的记录相相等,则认为这个文件是以前下载的文件, 跳过
|
||||
此次下载.
|
||||
|
|
|
|||
22
cache.go
22
cache.go
|
|
@ -8,6 +8,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type DbVideoInfo struct {
|
||||
|
|
@ -18,7 +19,7 @@ type DbVideoInfo struct {
|
|||
}
|
||||
|
||||
func (this *RunDownload_Req) getVideoId() (id string, err error) {
|
||||
b, err := json.Marshal(this)
|
||||
b, err := json.Marshal([]string{this.M3u8Url, strconv.Itoa(this.SkipTsCountFromHead)})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -78,22 +79,3 @@ func cacheWrite(dir string, id string, originReq RunDownload_Req, videoNameFullP
|
|||
}
|
||||
return cdb.FileRewriteKeyValue(filepath.Join(dir, "m3u8d_cache.cdb"), id, string(content))
|
||||
}
|
||||
|
||||
func dbRead(dir string, key string) (content []byte, err error) {
|
||||
db, err := cdb.OpenFile(filepath.Join(dir, "m3u8d_cache.cdb"))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
content, err = db.GetValue([]byte(key))
|
||||
if err != nil {
|
||||
if err == cdb.ErrNoData {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return content, nil
|
||||
}
|
||||
|
|
|
|||
68
download.go
68
download.go
|
|
@ -9,7 +9,6 @@ import (
|
|||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/orestonce/goffmpeg"
|
||||
"github.com/orestonce/gopool"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
|
@ -30,14 +29,30 @@ type TsInfo struct {
|
|||
Url string
|
||||
}
|
||||
|
||||
var gProgressBarTitle string
|
||||
var gProgressPercent int
|
||||
var gProgressPercentLocker sync.Mutex
|
||||
|
||||
func GetProgress() int {
|
||||
type GetProgress_Resp struct {
|
||||
Percent int
|
||||
Title string
|
||||
}
|
||||
|
||||
func GetProgress() (resp GetProgress_Resp) {
|
||||
gProgressPercentLocker.Lock()
|
||||
tmp := gProgressPercent
|
||||
resp.Percent = gProgressPercent
|
||||
resp.Title = gProgressBarTitle
|
||||
gProgressPercentLocker.Unlock()
|
||||
return tmp
|
||||
if resp.Title == "" {
|
||||
resp.Title = "正在下载"
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
func SetProgressBarTitle(title string) {
|
||||
gProgressPercentLocker.Lock()
|
||||
defer gProgressPercentLocker.Unlock()
|
||||
gProgressBarTitle = title
|
||||
}
|
||||
|
||||
type RunDownload_Resp struct {
|
||||
|
|
@ -48,12 +63,12 @@ type RunDownload_Resp struct {
|
|||
}
|
||||
|
||||
type RunDownload_Req struct {
|
||||
M3u8Url string `json:",omitempty"`
|
||||
HostType string `json:",omitempty"` // "设置getHost的方式(apiv1: `http(s):// + url.Host + filepath.Dir(url.Path)`; apiv2: `http(s)://+ u.Host`"
|
||||
Insecure bool `json:"-"` // "是否允许不安全的请求(默认为false)"
|
||||
SaveDir string `json:"-"` // "文件保存路径(默认为当前路径)"
|
||||
FileName string `json:"-"` // 文件名
|
||||
SkipTsCountFromHead int `json:",omitempty"` // 跳过前面几个ts
|
||||
M3u8Url string
|
||||
HostType string // "设置getHost的方式(apiv1: `http(s):// + url.Host + filepath.Dir(url.Path)`; apiv2: `http(s)://+ u.Host`"
|
||||
Insecure bool // "是否允许不安全的请求(默认为false)"
|
||||
SaveDir string // "文件保存路径(默认为当前路径)"
|
||||
FileName string // 文件名
|
||||
SkipTsCountFromHead int // 跳过前面几个ts
|
||||
}
|
||||
|
||||
type downloadEnv struct {
|
||||
|
|
@ -64,7 +79,6 @@ type downloadEnv struct {
|
|||
}
|
||||
|
||||
func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp) {
|
||||
|
||||
if req.HostType == "" {
|
||||
req.HostType = "apiv1"
|
||||
}
|
||||
|
|
@ -95,6 +109,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
|
|||
"Accept-Language": []string{"zh-CN,zh;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5"},
|
||||
"Referer": []string{host},
|
||||
}
|
||||
SetProgressBarTitle("嗅探m3u8")
|
||||
req.M3u8Url, err = this.sniffM3u8(req.M3u8Url)
|
||||
if err != nil {
|
||||
resp.ErrMsg = "sniffM3u8: " + err.Error()
|
||||
|
|
@ -112,6 +127,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
|
|||
return resp
|
||||
}
|
||||
if info != nil {
|
||||
SetProgressBarTitle("检查是否已下载")
|
||||
latestNameFullPath, found := info.SearchVideoInDir(req.SaveDir)
|
||||
if found {
|
||||
resp.IsSkipped = true
|
||||
|
|
@ -119,12 +135,6 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
|
|||
return resp
|
||||
}
|
||||
}
|
||||
var ffmpegExe string
|
||||
ffmpegExe, err = goffmpeg.SetupFfmpeg()
|
||||
if err != nil {
|
||||
resp.ErrMsg = "SetupFfmpeg error: " + err.Error()
|
||||
return resp
|
||||
}
|
||||
if !strings.HasPrefix(req.M3u8Url, "http") || req.M3u8Url == "" {
|
||||
resp.ErrMsg = "M3u8Url not valid " + strconv.Quote(req.M3u8Url)
|
||||
return resp
|
||||
|
|
@ -156,6 +166,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
|
|||
resp.IsCancel = this.GetIsCancel()
|
||||
return resp
|
||||
}
|
||||
SetProgressBarTitle("获取ts列表")
|
||||
tsList := getTsList(m3u8Host, string(m3u8Body))
|
||||
if len(tsList) <= req.SkipTsCountFromHead {
|
||||
resp.ErrMsg = "需要下载的文件为空"
|
||||
|
|
@ -163,13 +174,14 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
|
|||
}
|
||||
tsList = tsList[req.SkipTsCountFromHead:]
|
||||
// 下载ts
|
||||
SetProgressBarTitle("下载ts")
|
||||
err = this.downloader(tsList, downloadDir, ts_key)
|
||||
if err != nil {
|
||||
resp.ErrMsg = "下载ts文件错误: " + err.Error()
|
||||
resp.IsCancel = this.GetIsCancel()
|
||||
return resp
|
||||
}
|
||||
DrawProgressBar(1)
|
||||
DrawProgressBar(1, 1)
|
||||
var tsFileList []string
|
||||
for _, one := range tsList {
|
||||
tsFileList = append(tsFileList, filepath.Join(downloadDir, one.Name))
|
||||
|
|
@ -177,16 +189,17 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
|
|||
var tmpOutputName string
|
||||
var contentHash string
|
||||
tmpOutputName = filepath.Join(downloadDir, "all.merge.mp4")
|
||||
err = goffmpeg.MergeMultiToSingleMp4(goffmpeg.MergeMultiToSingleMp4_Req{
|
||||
FfmpegExePath: ffmpegExe,
|
||||
TsFileList: tsFileList,
|
||||
OutputMp4: tmpOutputName,
|
||||
ProgressCh: nil,
|
||||
|
||||
SetProgressBarTitle("合并ts为mp4")
|
||||
err = MergeTsFileListToSingleMp4(MergeTsFileListToSingleMp4_Req{
|
||||
TsFileList: tsFileList,
|
||||
OutputMp4: tmpOutputName,
|
||||
})
|
||||
if err != nil {
|
||||
resp.ErrMsg = "合并错误: " + err.Error()
|
||||
return resp
|
||||
}
|
||||
SetProgressBarTitle("计算文件hash")
|
||||
contentHash = getFileSha256(tmpOutputName)
|
||||
if contentHash == "" {
|
||||
resp.ErrMsg = "无法计算摘要信息: " + tmpOutputName
|
||||
|
|
@ -228,6 +241,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
|
|||
resp.ErrMsg = "删除下载目录失败: " + err.Error()
|
||||
return resp
|
||||
}
|
||||
SetProgressBarTitle("下载进度")
|
||||
return resp
|
||||
}
|
||||
|
||||
|
|
@ -423,7 +437,7 @@ func (this *downloadEnv) downloader(tsList []TsInfo, downloadDir string, key str
|
|||
}
|
||||
locker.Lock()
|
||||
downloadCount++
|
||||
DrawProgressBar(float32(downloadCount) / float32(tsLen))
|
||||
DrawProgressBar(tsLen, downloadCount)
|
||||
locker.Unlock()
|
||||
})
|
||||
}
|
||||
|
|
@ -442,7 +456,11 @@ func SetShowProgressBar() {
|
|||
}
|
||||
|
||||
// 进度条
|
||||
func DrawProgressBar(proportion float32) {
|
||||
func DrawProgressBar(total int, current int) {
|
||||
if total == 0 {
|
||||
return
|
||||
}
|
||||
proportion := float32(current) / float32(total)
|
||||
gProgressPercentLocker.Lock()
|
||||
gProgressPercent = int(proportion * 100)
|
||||
gProgressPercentLocker.Unlock()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
)
|
||||
|
||||
func main() {
|
||||
BuildCliBinary() // 编译二进制
|
||||
//BuildCliBinary() // 编译二进制
|
||||
CreateLibForQtUi() // 创建Qt需要使用的.a库文件
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ func BuildCliBinary() {
|
|||
},
|
||||
}
|
||||
for _, cfg := range list {
|
||||
name := "m3u8d_cli_v1.2_" + cfg.GOOS + "_" + cfg.GOARCH + cfg.Ext
|
||||
name := "m3u8d_cli_v1.3_" + cfg.GOOS + "_" + cfg.GOARCH + cfg.Ext
|
||||
cmd := exec.Command("go", "build", "-o", filepath.Join(wd, "bin", name))
|
||||
cmd.Dir = filepath.Join(wd, "cmd")
|
||||
cmd.Env = append(os.Environ(), "GOOS="+cfg.GOOS)
|
||||
|
|
|
|||
10
go.mod
10
go.mod
|
|
@ -3,22 +3,14 @@ module m3u8d
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/levigross/grequests v0.0.0-20190908174114-253788527a1a
|
||||
github.com/orestonce/cdb v0.0.0-20220528005855-d187c22240e2
|
||||
github.com/orestonce/go2cpp v0.0.0-20220507123906-b66d3600c123
|
||||
github.com/orestonce/goffmpeg v0.0.0-20220528011920-92f3449b6c15
|
||||
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171
|
||||
github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/yapingcat/gomedia v0.0.0-20220619163023-5a5544262ef6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/saracen/go7z-fixtures v0.0.0-20190623165746-aa6b8fba1d2f // indirect
|
||||
github.com/saracen/solidblock v0.0.0-20190426153529-45df20abab6f // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
)
|
||||
|
|
|
|||
51
go.sum
51
go.sum
|
|
@ -1,65 +1,18 @@
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/levigross/grequests v0.0.0-20190908174114-253788527a1a h1:DGFy/362j92vQRE3ThU1yqg9TuJS8YJOSbQuB7BP9cA=
|
||||
github.com/levigross/grequests v0.0.0-20190908174114-253788527a1a/go.mod h1:jVntzcUU+2BtVohZBQmSHWUmh8B55LCNfPhcNCIvvIg=
|
||||
github.com/orestonce/cdb v0.0.0-20210317131130-99d93d11de21 h1:kFAgzquHOv3dmVU2HoUUzu1586bd1DKHfAz6dd5do+I=
|
||||
github.com/orestonce/cdb v0.0.0-20210317131130-99d93d11de21/go.mod h1:HMNNdA1LMQFJRwobtCzVevWcInFSo9rfs1fYeVYwU+c=
|
||||
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-20220507123906-b66d3600c123 h1:AyAKqO7kC68OKiZk9GV4bUG+xMe1VQCy2CPbS9hvdY4=
|
||||
github.com/orestonce/go2cpp v0.0.0-20220507123906-b66d3600c123/go.mod h1:1fsOAZftk08/dOTRqlp6f/MVwaEKOhrnPUg0RtWiSdY=
|
||||
github.com/orestonce/goffmpeg v0.0.0-20220519233347-2266c9b171d9 h1:ki+QkZANpELM4WJjjcFwwFmt6r9ni53QxIYeS6OX77Y=
|
||||
github.com/orestonce/goffmpeg v0.0.0-20220519233347-2266c9b171d9/go.mod h1:QHZrzI4ewo7pYfEo8+QzrPxsCixua/TS0aE505m/nBU=
|
||||
github.com/orestonce/goffmpeg v0.0.0-20220528011920-92f3449b6c15 h1:Ix2AmnSHlA2hrI1NkpmXnFeOcxtdCj66fj1KoGFq9tI=
|
||||
github.com/orestonce/goffmpeg v0.0.0-20220528011920-92f3449b6c15/go.mod h1:QHZrzI4ewo7pYfEo8+QzrPxsCixua/TS0aE505m/nBU=
|
||||
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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda h1:h+YpzUB/bGVJcLqW+d5GghcCmE/A25KbzjXvWJQi/+o=
|
||||
github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda/go.mod h1:MSotTrCv1PwoR8QgU1JurEx+lNNbtr25I+m0zbLyAGw=
|
||||
github.com/saracen/go7z-fixtures v0.0.0-20190623165746-aa6b8fba1d2f h1:PF9WV5j/x6MT+x/sauUHd4objCvJbZb0wdxZkHSdd5A=
|
||||
github.com/saracen/go7z-fixtures v0.0.0-20190623165746-aa6b8fba1d2f/go.mod h1:6Ff0ADODZ6S3gYepgZ2w7OqFrTqtFcfwDUhmm8jsUhs=
|
||||
github.com/saracen/solidblock v0.0.0-20190426153529-45df20abab6f h1:1cJITU3JUI8qNS5T0BlXwANsVdyoJQHQ4hvOxbunPCw=
|
||||
github.com/saracen/solidblock v0.0.0-20190426153529-45df20abab6f/go.mod h1:LyBTue+RWeyIfN3ZJ4wVxvDuvlGJtDgCLgCb6HCPgps=
|
||||
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/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
github.com/yapingcat/gomedia v0.0.0-20220619163023-5a5544262ef6 h1:d9MplS5tlYkVzS20zFz47Hg82wvTnTk4Oafwo6j9Eb0=
|
||||
github.com/yapingcat/gomedia v0.0.0-20220619163023-5a5544262ef6/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
|
|
|||
|
|
@ -181,20 +181,33 @@ void CloseOldEnv(){
|
|||
}
|
||||
}
|
||||
|
||||
int32_t GetProgress(){
|
||||
GetProgress_Resp GetProgress(){
|
||||
std::string in;
|
||||
char *out = NULL;
|
||||
int outLen = 0;
|
||||
Go2cppFn_GetProgress((char *)in.data(), in.length(), &out, &outLen);
|
||||
int32_t retValue;
|
||||
GetProgress_Resp retValue;
|
||||
int outIdx = 0;
|
||||
{
|
||||
uint32_t tmp2 = uint32_t(uint8_t(out[outIdx+0]) << 24);
|
||||
uint32_t tmp3 = uint32_t(uint8_t(out[outIdx+1]) << 16);
|
||||
uint32_t tmp4 = uint32_t(uint8_t(out[outIdx+2]) << 8);
|
||||
uint32_t tmp5 = uint32_t(uint8_t(out[outIdx+3]) << 0);
|
||||
retValue = tmp2 | tmp3 | tmp4 | tmp5;
|
||||
outIdx+=4;
|
||||
{
|
||||
uint32_t tmp3 = uint32_t(uint8_t(out[outIdx+0]) << 24);
|
||||
uint32_t tmp4 = uint32_t(uint8_t(out[outIdx+1]) << 16);
|
||||
uint32_t tmp5 = uint32_t(uint8_t(out[outIdx+2]) << 8);
|
||||
uint32_t tmp6 = uint32_t(uint8_t(out[outIdx+3]) << 0);
|
||||
retValue.Percent = tmp3 | tmp4 | tmp5 | tmp6;
|
||||
outIdx+=4;
|
||||
}
|
||||
{
|
||||
uint32_t tmp7 = 0;
|
||||
uint32_t tmp8 = uint32_t(uint8_t(out[outIdx+0]) << 24);
|
||||
uint32_t tmp9 = uint32_t(uint8_t(out[outIdx+1]) << 16);
|
||||
uint32_t tmp10 = uint32_t(uint8_t(out[outIdx+2]) << 8);
|
||||
uint32_t tmp11 = uint32_t(uint8_t(out[outIdx+3]) << 0);
|
||||
tmp7 = tmp8 | tmp9 | tmp10 | tmp11;
|
||||
outIdx+=4;
|
||||
retValue.Title = std::string(out+outIdx, out+outIdx+tmp7);
|
||||
outIdx+=tmp7;
|
||||
}
|
||||
}
|
||||
if (out != NULL) {
|
||||
free(out);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,11 @@ struct RunDownload_Resp{
|
|||
};
|
||||
RunDownload_Resp RunDownload(RunDownload_Req in0);
|
||||
void CloseOldEnv();
|
||||
int32_t GetProgress();
|
||||
struct GetProgress_Resp{
|
||||
int32_t Percent;
|
||||
std::string Title;
|
||||
};
|
||||
GetProgress_Resp GetProgress();
|
||||
std::string GetWd();
|
||||
|
||||
#include <QObject>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ void MainWindow::on_pushButton_RunDownload_clicked()
|
|||
ui->pushButton_RunDownload->setEnabled(false);
|
||||
ui->checkBox_Insecure->setEnabled(false);
|
||||
ui->progressBar->setValue(0);
|
||||
ui->pushButton_RunDownload->setText("正在下载...");
|
||||
// ui->pushButton_RunDownload->setText("正在下载...");
|
||||
ui->pushButton_StopDownload->setEnabled(true);
|
||||
|
||||
m_syncUi.AddRunFnOn_OtherThread([this](){
|
||||
|
|
@ -45,10 +45,11 @@ void MainWindow::on_pushButton_RunDownload_clicked()
|
|||
while(isFinished->load() == false)
|
||||
{
|
||||
QThread::msleep(50);
|
||||
int value = GetProgress();
|
||||
GetProgress_Resp resp = GetProgress();
|
||||
// 可能以下闭包在运行前, other thread已经退出了, 所以isFinished需要使用shared_ptr
|
||||
m_syncUi.AddRunFnOn_UiThread([value, this, isFinished](){
|
||||
ui->progressBar->setValue(value);
|
||||
m_syncUi.AddRunFnOn_UiThread([resp, this, isFinished](){
|
||||
ui->progressBar->setValue(resp.Percent);
|
||||
ui->label_progressBar->setText(QString::fromStdString(resp.Title));
|
||||
if (ui->pushButton_RunDownload->isEnabled()) {
|
||||
isFinished->store(true);
|
||||
}
|
||||
|
|
@ -73,7 +74,7 @@ void MainWindow::on_pushButton_RunDownload_clicked()
|
|||
ui->lineEdit_SkipTsCountFromHead->setEnabled(true);
|
||||
ui->comboBox_HostType->setEnabled(true);
|
||||
ui->pushButton_RunDownload->setEnabled(true);
|
||||
ui->checkBox_Insecure->setEnabled(false);
|
||||
ui->checkBox_Insecure->setEnabled(true);
|
||||
ui->pushButton_RunDownload->setText("开始下载");
|
||||
ui->pushButton_StopDownload->setEnabled(false);
|
||||
if (resp.IsCancel) {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@
|
|||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0,0">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<widget class="QLabel" name="label_progressBar">
|
||||
<property name="text">
|
||||
<string>下载进度</string>
|
||||
</property>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
package m3u8d
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/yapingcat/gomedia/mp4"
|
||||
"github.com/yapingcat/gomedia/mpeg2"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type MergeTsFileListToSingleMp4_Req struct {
|
||||
TsFileList []string
|
||||
OutputMp4 string
|
||||
}
|
||||
|
||||
func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) {
|
||||
mp4file, err := os.OpenFile(req.OutputMp4, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer mp4file.Close()
|
||||
|
||||
muxer := mp4.CreateMp4Muxer(mp4file)
|
||||
vtid := muxer.AddVideoTrack(mp4.MP4_CODEC_H264)
|
||||
atid := muxer.AddAudioTrack(mp4.MP4_CODEC_AAC, 0, 16, 44100)
|
||||
|
||||
demuxer := mpeg2.NewTSDemuxer()
|
||||
var OnFrameErr error
|
||||
demuxer.OnFrame = func(cid mpeg2.TS_STREAM_TYPE, frame []byte, pts uint64, dts uint64) {
|
||||
if OnFrameErr != nil {
|
||||
return
|
||||
}
|
||||
if cid == mpeg2.TS_STREAM_AAC {
|
||||
OnFrameErr = muxer.Write(atid, frame, pts, dts)
|
||||
} else if cid == mpeg2.TS_STREAM_H264 {
|
||||
OnFrameErr = muxer.Write(vtid, frame, pts, dts)
|
||||
} else {
|
||||
OnFrameErr = errors.New("unknown cid " + strconv.Itoa(int(cid)))
|
||||
}
|
||||
}
|
||||
|
||||
for idx, tsFile := range req.TsFileList {
|
||||
DrawProgressBar(len(req.TsFileList), idx)
|
||||
var buf []byte
|
||||
buf, err = ioutil.ReadFile(tsFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = demuxer.Input(bytes.NewReader(buf))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if OnFrameErr != nil {
|
||||
return OnFrameErr
|
||||
}
|
||||
}
|
||||
|
||||
err = muxer.WriteTrailer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
DrawProgressBar(1, 1)
|
||||
return err
|
||||
}
|
||||
Loading…
Reference in New Issue