From 7ba9a54cac936b7d9ed4d32451a42a7e7a4eb80d Mon Sep 17 00:00:00 2001 From: liyuchao Date: Wed, 7 Sep 2022 16:38:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=90=88=E5=B9=B6ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- m3u8-downloader.go | 59 +++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/m3u8-downloader.go b/m3u8-downloader.go index 7ad66dd..ddcb9e4 100755 --- a/m3u8-downloader.go +++ b/m3u8-downloader.go @@ -5,6 +5,7 @@ package main import ( + "bufio" "bytes" "crypto/aes" "crypto/cipher" @@ -37,12 +38,12 @@ const ( var ( // 命令行参数 urlFlag = flag.String("u", "", "m3u8下载地址(http(s)://url/xx/xx/index.m3u8)") - nFlag = flag.Int("n", 16, "下载线程数(max goroutines num)") + nFlag = flag.Int("n", 16, "下载线程数(默认16)") htFlag = flag.String("ht", "apiv1", "设置getHost的方式(apiv1: `http(s):// + url.Host + filepath.Dir(url.Path)`; apiv2: `http(s)://+ u.Host`") - oFlag = flag.String("o", "movie", "自定义文件名(默认为movie)") - cFlag = flag.String("c", "", "自定义请求 cookie") - sFlag = flag.Int("s", 0, "是否允许不安全的请求(默认为0)") - spFlag = flag.String("sp", "", "文件保存路径(默认为当前路径)") + oFlag = flag.String("o", "movie", "自定义文件名(默认为movie)不带后缀") + cFlag = flag.String("c", "", "自定义请求cookie") + sFlag = flag.Int("s", 0, "是否允许不安全的请求(默认0)") + spFlag = flag.String("sp", "", "文件保存的绝对路径(默认为当前路径,建议默认值)") logger *log.Logger ro = &grequests.RequestOptions{ @@ -72,7 +73,7 @@ func main() { } func Run() { - msgTpl := "[功能]:多线程下载直播流 m3u8 视屏(ts + 合并)\n[提醒]:如果下载失败,请使用 -ht=apiv2 \n[提醒]:如果下载失败,m3u8 地址可能存在嵌套\n[提醒]:如果进度条中途下载失败,可重复执行" + msgTpl := "[功能]:多线程下载直播流m3u8视屏\n[提醒]:下载失败,请使用 -ht=apiv2 \n[提醒]:下载失败,m3u8 地址可能存在嵌套\n[提醒]:进度条中途下载失败,可重复执行" fmt.Println(msgTpl) runtime.GOMAXPROCS(runtime.NumCPU()) now := time.Now() @@ -82,7 +83,7 @@ func Run() { m3u8Url := *urlFlag maxGoroutines := *nFlag hostType := *htFlag - movieDir := *oFlag + movieName := *oFlag cookie := *cFlag insecure := *sFlag savePath := *spFlag @@ -104,7 +105,8 @@ func Run() { if savePath != "" { pwd = savePath } - download_dir = filepath.Join(pwd, movieDir) + // 初始化下载ts的目录,后面所有的ts文件会保存在这里 + download_dir = filepath.Join(pwd, movieName) if isExist, _ := pathExists(download_dir); !isExist { os.MkdirAll(download_dir, os.ModePerm) } @@ -120,7 +122,7 @@ func Run() { ts_list := getTsList(m3u8Host, m3u8Body) fmt.Println("待下载 ts 文件数量:", len(ts_list)) - // 3、下载ts切割文件到download_dir + // 3、下载ts文件到download_dir downloader(ts_list, maxGoroutines, download_dir, ts_key) if ok := checkTsDownDir(download_dir); !ok { fmt.Printf("\n[Failed] 请检查url地址有效性 \n") @@ -128,19 +130,11 @@ func Run() { } // 4、合并ts切割文件成mp4文件 - switch runtime.GOOS { - case "windows": - win_merge_file(download_dir) - default: - unix_merge_file(download_dir) - } + mv := mergeTs(download_dir) - // 5、输出下载视频信息 - os.Rename(filepath.Join(download_dir, "merge.mp4"), download_dir+".mp4") - os.RemoveAll(download_dir) - os.Chdir(pwd) - DrawProgressBar("Merging", float32(1), PROGRESS_WIDTH, "merge.ts") - fmt.Printf("\n[Success] 下载保存路径:%s | 共耗时: %6.2fs\n", download_dir+".mp4", time.Now().Sub(now).Seconds()) + //5、输出下载视频信息 + DrawProgressBar("Merging", float32(1), PROGRESS_WIDTH, mv) + fmt.Printf("\n[Success] 下载保存路径:%s | 共耗时: %6.2fs\n", mv, time.Now().Sub(now).Seconds()) } // 获取m3u8地址的host @@ -307,6 +301,29 @@ func checkTsDownDir(dir string) bool { return false } +// 合并ts文件 +func mergeTs(downloadDir string) string { + mvName := downloadDir + ".mp4" + outMv, _ := os.Create(mvName) + defer outMv.Close() + writer := bufio.NewWriter(outMv) + err := filepath.Walk(downloadDir, func(path string, f os.FileInfo, err error) error { + if f == nil { + return err + } + if f.IsDir() || filepath.Ext(path) != ".ts" { + return nil + } + bytes, _ := ioutil.ReadFile(path) + _, err = writer.Write(bytes) + return err + }) + checkErr(err) + _ = writer.Flush() + os.RemoveAll(downloadDir) + return mvName +} + // 进度条 func DrawProgressBar(prefix string, proportion float32, width int, suffix ...string) { pos := int(proportion * float32(width))