diff --git a/README.md b/README.md
index 0c82f04..4b0b1af 100644
--- a/README.md
+++ b/README.md
@@ -7,9 +7,6 @@
## 实现说明
* download.go 大部分抄自 https://github.com/llychao/m3u8-downloader
-* 将ffmpeg直接编译进windows/linux-arm/linux-386/darwin的二进制了.
- 转换mp4时,会自动将二进制里的ffmpeg解压到系统临时目录,然后使用.
- 因此linux/mac版本的可执行文件达到了32MB, 带Qt ui的可执行文件达到了惊人的 50MB
* 使用 https://github.com/yapingcat/gomedia 代替ffmpeg进行格式转换
* 支持跳过前面几个ts文件(一般是广告, 嘿嘿)
* 程序会在下载保存目录创建:
@@ -24,7 +21,7 @@
* [x] 如果不是m3u8样子的URL,自动下载html下来、搜索其中的m3u8链接进行下载
* [x] windows、linux、mac都支持ffmpeg合并ts列表为mp4
* [x] 充分测试后,使用 https://github.com/yapingcat/gomedia 代替ffmpeg进行格式转换
- * [ ] 支持嵌套m3u8的url
+ * [x] 支持嵌套m3u8的url
* [ ] 支持设置代理
* [ ] 支持从curl命令解析出需要的header、auth-basic、cookie等信息,正如 https://github.com/cxjava/m3u8-downloader 一样
## 二次开发操作手册:
diff --git a/download.go b/download.go
index 25d4135..0ca496d 100644
--- a/download.go
+++ b/download.go
@@ -110,7 +110,8 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
"Referer": []string{host},
}
SetProgressBarTitle("嗅探m3u8")
- req.M3u8Url, err = this.sniffM3u8(req.M3u8Url)
+ var m3u8Body []byte
+ req.M3u8Url, m3u8Body, err = this.sniffM3u8(req.M3u8Url)
if err != nil {
resp.ErrMsg = "sniffM3u8: " + err.Error()
resp.IsCancel = this.GetIsCancel()
@@ -154,12 +155,6 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
return resp
}
// 获取m3u8地址的内容体
- m3u8Body, err := this.doGetRequest(req.M3u8Url)
- if err != nil {
- resp.ErrMsg = "getM3u8Body: " + err.Error()
- resp.IsCancel = this.GetIsCancel()
- return resp
- }
ts_key, err := this.getM3u8Key(m3u8Host, string(m3u8Body))
if err != nil {
resp.ErrMsg = "getM3u8Key: " + err.Error()
@@ -194,6 +189,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
err = MergeTsFileListToSingleMp4(MergeTsFileListToSingleMp4_Req{
TsFileList: tsFileList,
OutputMp4: tmpOutputName,
+ ctx: this.ctx,
})
if err != nil {
resp.ErrMsg = "合并错误: " + err.Error()
@@ -241,6 +237,7 @@ func (this *downloadEnv) RunDownload(req RunDownload_Req) (resp RunDownload_Resp
resp.ErrMsg = "删除下载目录失败: " + err.Error()
return resp
}
+ _ = os.Remove(filepath.Join(req.SaveDir, "downloading"))
SetProgressBarTitle("下载进度")
return resp
}
@@ -267,7 +264,10 @@ func RunDownload(req RunDownload_Req) (resp RunDownload_Resp) {
}
gOldEnv = env
gOldEnvLocker.Unlock()
- return env.RunDownload(req)
+ resp = env.RunDownload(req)
+ SetProgressBarTitle("下载进度")
+ DrawProgressBar(1, 0)
+ return resp
}
func CloseOldEnv() {
@@ -522,19 +522,52 @@ func getFileSha256(targetFile string) (v string) {
return hex.EncodeToString(tmp[:])
}
-func (this *downloadEnv) sniffM3u8(urlS string) (afterUrl string, err error) {
- if strings.HasSuffix(strings.ToLower(urlS), ".m3u8") {
- return urlS, nil
+func (this *downloadEnv) sniffM3u8(urlS string) (afterUrl string, content []byte, err error) {
+ for idx := 0; idx < 5; idx++ {
+ content, err = this.doGetRequest(urlS)
+ if err != nil {
+ return "", nil, err
+ }
+ if strings.HasSuffix(strings.ToLower(urlS), ".m3u8") {
+ // 看这个是不是嵌套的m3u8
+ var m3u8Url string
+ containsTs := false
+ for _, line := range strings.Split(string(content), "\n") {
+ lineOrigin := strings.TrimSpace(line)
+ line = strings.ToLower(lineOrigin)
+ if strings.HasSuffix(line, ".m3u8") {
+ m3u8Url = lineOrigin
+ break
+ }
+ if strings.HasSuffix(line, ".ts") {
+ containsTs = true
+ break
+ }
+ }
+ if containsTs {
+ return urlS, content, err
+ }
+ if m3u8Url == "" {
+ return "", nil, errors.New("未发现m3u8资源_1")
+ }
+ urlObj, err := url.Parse(urlS)
+ if err != nil {
+ return "", nil, err
+ }
+ lineObj, err := url.Parse(m3u8Url)
+ if err != nil {
+ return "", nil, err
+ }
+ urlS = urlObj.ResolveReference(lineObj).String()
+ continue
+ }
+ groups := regexp.MustCompile(`http[s]://[a-zA-Z0-9/\\.%_-]+.m3u8`).FindSubmatch(content)
+ if len(groups) == 0 {
+ return "", nil, errors.New("未发现m3u8资源_2")
+ }
+ urlS = string(groups[0])
}
- content, err := this.doGetRequest(urlS)
- if err != nil {
- return "", err
- }
- groups := regexp.MustCompile(`http[s]://[a-zA-Z0-9/\\.%_-]+.m3u8`).FindSubmatch(content)
- if len(groups) == 0 {
- return "", errors.New("未发现m3u8资源")
- }
- return string(groups[0]), nil
+ return "", nil, errors.New("未发现m3u8资源_3")
}
func (this *downloadEnv) doGetRequest(urlS string) (data []byte, err error) {
diff --git a/export/main.go b/export/main.go
index 0186ddd..28c7852 100644
--- a/export/main.go
+++ b/export/main.go
@@ -10,7 +10,7 @@ import (
)
func main() {
- BuildCliBinary() // 编译二进制
+ //BuildCliBinary() // 编译二进制
CreateLibForQtUi() // 创建Qt需要使用的.a库文件
}
diff --git a/m3u8d-qt/mainwindow.cpp b/m3u8d-qt/mainwindow.cpp
index f04f7b3..ed8f2b5 100644
--- a/m3u8d-qt/mainwindow.cpp
+++ b/m3u8d-qt/mainwindow.cpp
@@ -35,7 +35,6 @@ 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_StopDownload->setEnabled(true);
m_syncUi.AddRunFnOn_OtherThread([this](){
@@ -45,9 +44,9 @@ void MainWindow::on_pushButton_RunDownload_clicked()
while(isFinished->load() == false)
{
QThread::msleep(50);
- GetProgress_Resp resp = GetProgress();
// 可能以下闭包在运行前, other thread已经退出了, 所以isFinished需要使用shared_ptr
- m_syncUi.AddRunFnOn_UiThread([resp, this, isFinished](){
+ m_syncUi.AddRunFnOn_UiThread([this, isFinished](){
+ GetProgress_Resp resp = GetProgress();
ui->progressBar->setValue(resp.Percent);
ui->label_progressBar->setText(QString::fromStdString(resp.Title));
if (ui->pushButton_RunDownload->isEnabled()) {
diff --git a/m3u8d-qt/mainwindow.ui b/m3u8d-qt/mainwindow.ui
index 3db0f42..6da1585 100644
--- a/m3u8d-qt/mainwindow.ui
+++ b/m3u8d-qt/mainwindow.ui
@@ -63,7 +63,11 @@
-
-
+
+
+
+
+
-
diff --git a/merge.go b/merge.go
index be11b91..b3909ce 100644
--- a/merge.go
+++ b/merge.go
@@ -2,6 +2,7 @@ package m3u8d
import (
"bytes"
+ "context"
"errors"
"github.com/yapingcat/gomedia/mp4"
"github.com/yapingcat/gomedia/mpeg2"
@@ -13,6 +14,7 @@ import (
type MergeTsFileListToSingleMp4_Req struct {
TsFileList []string
OutputMp4 string
+ ctx context.Context
}
func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) {
@@ -42,6 +44,11 @@ func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error)
}
for idx, tsFile := range req.TsFileList {
+ select {
+ case <-req.ctx.Done():
+ return req.ctx.Err()
+ default:
+ }
DrawProgressBar(len(req.TsFileList), idx)
var buf []byte
buf, err = ioutil.ReadFile(tsFile)