package input
import (
"crypto/md5"
"encoding/hex"
"fmt"
"github.com/quangngotan95/go-m3u8/m3u8"
"io"
"m3u8.com/config"
"m3u8.com/info"
"m3u8.com/util"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"sync"
"time"
)
const Symbol string = "#"
type Simple struct {
url string
count int
files []string
proxy string
Items []*m3u8.SegmentItem
Domain string
SchemaDomain string
index int
dir string
}
func (i *Simple) RemoveFile() {
if err := os.RemoveAll(i.saveDir()); err != nil {
fmt.Println("removing useless files error", err.Error()+"\n")
}
}
func (i *Simple) GetUrl() string {
return i.url
}
func (i *Simple) GetCount() int {
return i.count
}
func (i *Simple) GetFiles() []string {
return i.files
}
func (i *Simple) Dir() string {
return config.GetConfig().Base.SaveRoot
}
func (i *Simple) saveDir() string {
if i.dir == "" {
panic("empty dir")
}
return config.GetConfig().Base.SaveRoot + i.dir
}
func (i *Simple) MaxConnection() int {
return config.GetConfig().Base.Count
}
func (i *Simple) GetM3u8Name() string {
nowDate := time.Now()
month := int(nowDate.Month())
day := nowDate.Day()
hour := nowDate.Hour()
minute := nowDate.Minute()
second := nowDate.Second()
monthStr := strconv.Itoa(month)
dayStr := strconv.Itoa(day)
hourStr := strconv.Itoa(hour)
minuteStr := strconv.Itoa(minute)
secondStr := strconv.Itoa(second)
if month < 10 {
monthStr = "0" + monthStr
}
if day < 10 {
dayStr = "0" + dayStr
}
if hour < 10 {
hourStr = "0" + hourStr
}
if minute < 10 {
minuteStr = "0" + minuteStr
}
if second < 10 {
secondStr = "0" + secondStr
}
return strconv.Itoa(nowDate.Year()) +
monthStr +
dayStr +
hourStr +
minuteStr +
secondStr
}
func (i *Simple) GetTsNamePattern() string {
panic("简单模式不支持此方法,请使用Input struct")
}
func (i *Simple) Check() {
for _, filename := range i.GetFiles() {
if !util.Exists(filename) {
fmt.Println("文件不全")
os.Exit(-1)
}
}
}
func (i *Simple) GetIndex() int {
return i.index
}
func (i *Simple) Parse() {
i.url = os.Args[1]
i.proxy = config.GetConfig().Base.AgentHost
transport := &http.Transport{DisableKeepAlives: true}
if i.proxy != "" {
proxy := func(_ *http.Request) (*url.URL, error) {
return url.Parse(i.proxy) //根据定义Proxy func(*Request) (*url.URL, error)这里要返回url.URL
}
transport.Proxy = proxy
}
client := &http.Client{Transport: transport, Timeout: time.Second * 60 * 10}
request, err1 := http.NewRequest("GET", i.url, nil)
if err1 != nil {
fmt.Println(err1)
os.Exit(1)
}
/*resp,_:=http.Get("https://cp2.hboav.com/check/hbo8/hls/files/mp4/u/D/7/uD7bd.mp4/index.m3u8?key=UeZ4Kl35J1KhB_600tmjVA&expires=1626431677")
respB,_:=ioutil.ReadAll(resp.Body)
fmt.Println(string(respB))*/
response, err2 := client.Do(request)
if err2 != nil {
fmt.Println(err2)
os.Exit(2)
}
playlist, err3 := m3u8.Read(response.Body)
if err3 != nil {
fmt.Println(err3)
os.Exit(3)
}
for _, item := range playlist.Items {
ii, _ := m3u8.NewSegmentItem(item.String())
i.Items = append(i.Items, ii)
}
i.count = len(i.Items)
i.files = make([]string, i.count)
split := strings.Split(i.url, "/")
path := split[0 : len(split)-1]
i.Domain = strings.Join(path, "/") + "/"
urlParse, _ := url.Parse(i.url)
i.SchemaDomain = urlParse.Scheme + "://" + urlParse.Hostname() + "/"
i.createDir(playlist.String())
}
func (i *Simple) createDir(str string) {
md := md5.New()
md.Write([]byte(str))
mdStr := md.Sum(nil)
i.dir = hex.EncodeToString(mdStr) /*strconv.Itoa(rand.Intn(1000))*/ + "/"
err := os.MkdirAll(i.Dir()+i.dir, os.ModePerm)
if err != nil {
fmt.Print("创建文件夹失败", err.Error())
os.Exit(1)
}
}
func (i *Simple) SaveTs(idx int, channel chan info.Info, downChan chan bool, wg *sync.WaitGroup) {
//进队列
downChan <- true
index := idx - 1
defer func() {
wg.Done()
<-downChan
}()
seg := *i.Items[index].Comment
filename := seg
parseurl, _ := url.Parse(filename)
if parseurl.Scheme == "" {
segByte := []byte(seg)
if segByte[0] == '/' {
filename = i.SchemaDomain + filename
} else {
filename = i.Domain + filename
}
}
saveFilename := i.saveDir() + seg
if util.Exists(saveFilename) {
i.files[index] = saveFilename
channel <- info.Info{Num: idx, Msg: seg + "已存在"}
return
}
transport := &http.Transport{DisableKeepAlives: true}
if i.proxy != "" {
proxy := func(_ *http.Request) (*url.URL, error) {
return url.Parse(i.proxy) //根据定义Proxy func(*Request) (*url.URL, error)这里要返回url.URL
}
transport.Proxy = proxy
}
for tryCount := 1; tryCount <= 3; tryCount++ {
now := time.Now()
client := &http.Client{Transport: transport, Timeout: time.Second * 60}
request, err1 := http.NewRequest("GET", filename, nil)
if err1 != nil {
channel <- info.Info{IsTry: true, Num: idx, Msg: fmt.Sprintf("请求出错:%s,第%d次重试", err1.Error(), tryCount)}
continue
}
request.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36")
request.Header.Add("Accept-Encoding", "identity")
response, err2 := client.Do(request)
if err2 != nil {
channel <- info.Info{IsTry: true, Num: idx, Msg: fmt.Sprintf("响应出错:%s,重,第%d次重试", err2.Error(), tryCount)}
continue
}
defer response.Body.Close()
saveFile, err := os.Create(saveFilename)
if err != nil {
channel <- info.Info{IsTry: true, Num: idx, Msg: fmt.Sprintf("创建文件失败:%s,第%d次重试", err.Error(), tryCount)}
continue
}
defer saveFile.Close()
wInt, err := io.Copy(saveFile, response.Body)
if err != nil && err != io.ErrUnexpectedEOF {
channel <- info.Info{IsTry: true, Num: idx, Msg: fmt.Sprintf("写入文件失败:%s,第%d次重试", err.Error(), tryCount)}
continue
}
i.files[index] = saveFilename
channel <- info.Info{Num: idx, Msg: seg + util.FileSize(wInt) + " 用时:" + util.HumanTime(now)}
break
}
}
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
下载合并m3u8文件,多线程下载,支持代理,支持用m3u8格式播放视频的网站, M3U8 文件简介 m3u8 文件实质是一个播放列表(playlist),其可能是一个媒体播放列表(Media Playlist),或者是一个主列表(Master Playlist)。但无论是哪种播放列表,其内部文字使用的都是 utf-8 编码。 当 m3u8 文件作为媒体播放列表(Meida Playlist)时,其内部信息记录的是一系列媒体片段资源,顺序播放该片段资源,即可完整展示多媒体资源。其格式如下所示: #EXTM3U #EXT-X-TARGETDURATION:10 #EXTINF:9.009, http://media.example.com/first.ts #EXTINF:9.009, http://media.example.com/second.ts #EXTINF:3.003, http://media.example.com/third.ts 对于点播来说,客户端只需按顺序下载上述片段资源,依次进行播放即可。而对于直播来说,客户端需要 定时重新请求 该 m3u8 文件
资源推荐
资源详情
资源评论
收起资源包目录
m3u8-go.zip (15个子文件)
go.mod 163B
go.sum 499B
LICENSE 34KB
input
input.go 3KB
input_many.go 3KB
input_simple.go 6KB
config.ini 85B
ts合并工具.exe 520KB
info
info.go 91B
.gitignore 16B
ffmpeg.exe 10.91MB
m3u8.go 2KB
util
file.go 347B
time.go 424B
config
index.go 398B
共 15 条
- 1
资源评论
谢瑞东521
- 粉丝: 0
- 资源: 2
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功