通过下载m3u8文件,下载所有ts文件,并合并成视频文件
音视频文件各种格式的转换工作
主要使用扩展包 #
github.com/grafov/m3u8
github.com/spf13/cobra
代码 #
下载视频文件 #
package download
import (
"bufio"
"crypto/md5"
"fmt"
"github.com/grafov/m3u8"
"github.com/spf13/cobra"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"strconv"
"sync"
"time"
)
var (
file string
path string
Command = &cobra.Command{
Use: "download",
Short: "download 视频下载",
Example: "tool download",
Run: func(cmd *cobra.Command, args []string) {
execute()
},
}
)
func init() {
current,_ := os.Getwd()
Command.PersistentFlags().StringVarP(&file, "file", "f", "index.m3u8", "要解析的m3u8文件")
Command.PersistentFlags().StringVarP(&path, "path", "p", current, "路径地址")
}
var urls = make(map[string]int,1000)
func execute() {
wg := &sync.WaitGroup{}
p := createDateDir(path)
plists := getUrls(file)
for idx, url := range plists {
filename := p + "/" + strconv.Itoa(idx + 1) + ".ts"
wg.Add(1)
go download(wg,url,filename)
}
wg.Wait()
defer func() {
if err := recover(); err != nil {
log.Println(err)
}
}()
}
func md5Check(u string) bool {
key := fmt.Sprintf("%x",md5.Sum([]byte(u)))
if _,ok := urls[key]; ok == true {
return true
}
urls[key] = 1
return false
}
func download(wg *sync.WaitGroup,url string,filename string) {
fmt.Println("start download url:",url)
resp, err := http.Get(url)
if err != nil {
panic("不能下载文件" + err.Error())
}
defer func(wg *sync.WaitGroup) {
resp.Body.Close()
wg.Done()
}(wg)
//读取内容弄
content, err := ioutil.ReadAll(resp.Body)
if err == io.EOF {
goto End
}
if err != nil {
panic("读取文件失败"+err.Error())
}
err = ioutil.WriteFile(filename, content, 0666)
if err != nil {
panic("写入文件错误" + err.Error())
}
End:
fmt.Println("save url to file sucess",filename)
}
func createDateDir(Path string) string {
folderName := time.Now().Format("200601021504")
folderPath := filepath.Join(Path, folderName)
if _, err := os.Stat(folderPath); os.IsNotExist(err) {
// 必须分成两步:先创建文件夹、再修改权限
_ = os.Mkdir(folderPath, 0777) //0777也可以os.ModePerm
_ = os.Chmod(folderPath, 0777)
}
return folderPath
}
/**
* 解析m3u8文件,获取url列表
*/
func getUrls(filename string) (urls []string) {
file,err := os.Open(filename)
if err != nil {
panic(err)
}
p, listType, err := m3u8.DecodeFrom(bufio.NewReader(file), true)
if err != nil {
log.Println(err)
}
if listType != m3u8.MEDIA {
panic("不能获取视频类型ts")
}
mediapl := p.(*m3u8.MediaPlaylist)
if mediapl.Segments == nil || len(mediapl.Segments) == 0 {
panic("不能获取视频列表")
}
for _,seg := range mediapl.Segments {
if seg != nil && seg.URI != "" {
if !md5Check(seg.URI) {
urls = append(urls,seg.URI)
}
}
}
return
}
合并ts文件到mp4 #
package merge
import (
"fmt"
"github.com/spf13/cobra"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
)
var (
path string
delete bool
Command = &cobra.Command{
Use: "merge",
Short: "merge 合并文件",
Example: "tool merge -p=202202232344",
Run: func(cmd *cobra.Command, args []string) {
execute()
},
}
)
func init() {
current,_ := os.Getwd()
Command.PersistentFlags().BoolVarP(&delete,"delete","d",false,"是否删除下载路径")
Command.PersistentFlags().StringVarP(&path, "path", "p", current, "路径地址")
}
func execute(){
files, err := filepath.Glob(path + "/*.ts")
if err != nil {
panic(err)
}
p,_ := os.Getwd()
videofile,_ := filepath.Abs( p+ "/" + strings.Trim(path,"/") + ".mp4")
fii, err := os.OpenFile(videofile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm)
if err != nil {
panic(err)
}
for i := 1; i <= len(files); i++ {
tsfile,_ := filepath.Abs(path + "/" + strconv.Itoa(i) + ".ts")
f, err := os.OpenFile(tsfile, os.O_RDONLY, os.ModePerm)
if err != nil {
fmt.Println(err)
}
b, err := ioutil.ReadAll(f)
if err != nil {
fmt.Println(err)
return
}
_, _ = fii.Write(b)
_ = f.Close()
}
defer func() {
if delete == true {
delpath,_ := filepath.Abs(path)
os.RemoveAll(delpath)
}
fii.Close()
}()
}
音视频转换 #
通过ffmpeg可执行命令进行封装
package format
import (
"bytes"
"fmt"
"github.com/spf13/cobra"
"log"
"os/exec"
"path/filepath"
"strconv"
"strings"
)
var (
input string
output string
voice bool
start int
end int
cmds map[string]func(input,output string)
Command = &cobra.Command{
Use: "format",
Short: "format 格式化文件",
Example: "tool format 1.flv 1.mp4",
PreRun: func(cmd *cobra.Command, args []string) {
usage()
cmds = map[string]func(input string, output string){}
cmds["flv2mp4"] =flv2mp4
cmds["mkv2mp4"] = mkv2mp4
cmds["tovoice"] = tovoice
},
Run: func(cmd *cobra.Command, args []string) {
execute()
},
}
)
func init() {
Command.PersistentFlags().IntVarP(&start,"start","s",0,"截取视频开始mp42git使用")
Command.PersistentFlags().IntVarP(&end,"end","e",10,"截取视频长度mp42git使用")
Command.PersistentFlags().BoolVarP(&voice, "voice", "v", false, "音频文件")
Command.PersistentFlags().StringVarP(&input, "input", "i", "1.flv", "输入视频文件")
Command.PersistentFlags().StringVarP(&output, "output", "o", "1.mp4", "输出视频文件")
}
func usage() {
fmt.Println("+--------------------------------------------------+")
fmt.Println("| list command |")
fmt.Println("| tool format -i=1.flv -o=1.mp4 |")
fmt.Println("| tool format -i=1.mkv -o1.mp4 |")
fmt.Println("| tool format -i=1.mp4 -o=1.gif -s=1 -e=10 |")
fmt.Println("| tool format -i=1.mp4 -o=1.mp3 -v=true |")
fmt.Println("+--------------------------------------------------+")
}
func execute() {
var fname string
iext := filepath.Ext(input)
oext := filepath.Ext(output)
if voice {
fname = "tovoice"
} else {
fname = strings.ToLower(iext[1:]) + "2"+ strings.ToLower(oext[1:])
}
if strings.ToLower(oext[1:]) == "gif" {
mp42gif(input,output,start,end)
return
}
fn,ok := cmds[fname];
if !ok {
log.Panic("没有转化函数")
}
fn(input,output)
defer func() {
if err := recover(); err != nil {
log.Println(err)
}
}()
}
func flv2mp4(input,output string) {
//
cmd := exec.Command("bin/ffmpeg.exe","-i",input,"-c","copy",output)
fmt.Println(cmd.String())
template(cmd)
}
func mkv2mp4(input,output string) {
//ffmpeg -i 1.mkv -c:v copy -c:a aac 1.mp4
cmd := exec.Command("bin/ffmpeg.exe","-i",input,"-c:v","copy","-c:a","aac",output)
fmt.Println(cmd.String())
template(cmd)
}
func mp42gif(input,output string,start,end int) {
cmd := exec.Command("bin/ffmpeg.exe","-ss",strconv.Itoa(start),"-i",input,"-t",strconv.Itoa(end),output)
fmt.Println(cmd.String())
template(cmd)
}
func tovoice(input,output string) {
//ffmpeg -i input -vn output
cmd := exec.Command("bin/ffmpeg.exe","-i",input,"-vn",output)
fmt.Println(cmd.String())
template(cmd)
}
func template(cmd *exec.Cmd) {
out := new(bytes.Buffer)
cmd.Stdout = out
if err := cmd.Start(); err != nil {
log.Panic(err)
}
if err := cmd.Wait(); err != nil {
log.Panic(err)
}
fmt.Println(out.String())
}
操作命令 #
- 去视频网站下载m3u8文件
- 执行下载命令
视频处理小工具 1、下载m3m8文件
tool.exe download [-f 执行*.m3u8文件 -p 下载目录]
2、合并ts文件到mp4
tool.exe merge [-p 下载后的ts地址 --d 生成视频后是否删除ts目录]
3、格式转化
tool.exe format -h 查看帮助