134 lines
3.6 KiB
Go
134 lines
3.6 KiB
Go
package m3u8
|
||
|
||
import (
|
||
"bytes"
|
||
"crypto/md5"
|
||
"encoding/hex"
|
||
"fmt"
|
||
"strconv"
|
||
"time"
|
||
"videoweb/pub/common/errors"
|
||
"videoweb/pub/common/utils"
|
||
"videoweb/pub/pubdef"
|
||
"videoweb/pub/storage/proxy"
|
||
|
||
"github.com/grafov/m3u8"
|
||
)
|
||
|
||
// transform m3u8文件转换,将不正确的m3u8文件,替换为正确的m3u8文件
|
||
// apiType(1:app,2:h5app,3:web)
|
||
func TransformEx(name string, cdnDomain, origDomain string, apiType int, authKey string) (
|
||
media *m3u8.MediaPlaylist, buff *bytes.Buffer, err error) {
|
||
|
||
if name == "" {
|
||
err = errors.MakeWithMsg(errors.M3u8FileName, "m3u8 file name is empty")
|
||
return
|
||
}
|
||
if cdnDomain == "" || origDomain == "" {
|
||
err = errors.MakeWithMsg(errors.DomainErr, "cdnDomain or origDomain is empty")
|
||
return
|
||
}
|
||
// 处理媒资库 桶1(v1) 桶2(v2) 桶3(v3)
|
||
mediaVerson := proxy.AppendsMediaS3Version(name)
|
||
if len(mediaVerson) > 0 {
|
||
name = mediaVerson + name
|
||
}
|
||
authKey = resolveTsAuthKey(authKey)
|
||
|
||
//log.Info("Test", log.Any("name", name), log.Any("cdnDomain", cdnDomain), log.Any("origDomain", origDomain), log.Any("authKey", authKey))
|
||
m3u8reader, err := readFromRedis(name, origDomain)
|
||
if err != nil {
|
||
return
|
||
}
|
||
p, t, err := m3u8.DecodeFrom(m3u8reader, false)
|
||
if err != nil {
|
||
err = errors.MakeWithErr(errors.M3u8Read, err)
|
||
return
|
||
}
|
||
apiPath := keyUri
|
||
if apiType == 2 {
|
||
apiPath = h5KeyUri
|
||
} else if apiType == 3 {
|
||
apiPath = webkeyUri
|
||
}
|
||
|
||
switch t {
|
||
case m3u8.MEDIA:
|
||
pl := p.(*m3u8.MediaPlaylist)
|
||
dirPath := utils.PathForInfo(name).Dir
|
||
media, err = makeTSList(pl, cdnDomain, dirPath, apiPath, authKey)
|
||
if err != nil {
|
||
return
|
||
}
|
||
buff = media.Encode()
|
||
case m3u8.MASTER:
|
||
mpl := p.(*m3u8.MasterPlaylist)
|
||
buff = mpl.Encode()
|
||
default:
|
||
err = errors.MakeWithMsg(errors.M3u8FileName, fmt.Sprintf("invalid m3u8 type %d", t))
|
||
}
|
||
return
|
||
}
|
||
|
||
// makeTSList 根据from,重新生成播放列表
|
||
func makeTSList(from *m3u8.MediaPlaylist, cdnDomain string,
|
||
dirPath string, apiPath string, authKey string) (
|
||
media *m3u8.MediaPlaylist, err error) {
|
||
media, err = m3u8.NewMediaPlaylist(from.WinSize(), from.Count())
|
||
if err != nil {
|
||
return
|
||
}
|
||
now := time.Now()
|
||
base := utils.JoinUrlPath(cdnDomain, dirPath)
|
||
for _, segment := range from.Segments {
|
||
if segment == nil {
|
||
continue
|
||
}
|
||
sg := new(m3u8.MediaSegment)
|
||
sg.URI = utils.JoinUrlPath(base, segment.URI)
|
||
if len(authKey) > 0 {
|
||
//生成鉴权url
|
||
urlPath := utils.JoinUrlPath(dirPath, segment.URI)
|
||
urlAuth := generateUrlAuth(now, urlPath, authKey)
|
||
sg.URI = sg.URI + urlAuth
|
||
}
|
||
sg.Title = segment.Title
|
||
sg.Duration = segment.Duration
|
||
if err = media.AppendSegment(sg); err != nil {
|
||
return
|
||
}
|
||
}
|
||
_ = media.SetDefaultKey("AES-128", apiPath, "", "", "")
|
||
media.Close()
|
||
return
|
||
}
|
||
|
||
// 生成鉴权url
|
||
func generateUrlAuth(now time.Time, path string, authKey string) string {
|
||
timestamp := now.Unix()
|
||
signStr := fmt.Sprintf("%s-%d-0-0-%s", path, timestamp, authKey)
|
||
md5Str := getMD5Sign(signStr)
|
||
// TS CDN 鉴权参数后追加应用标识,便于流量统计。
|
||
urlAuth := fmt.Sprintf("?md=%d-0-0-%s&c=%d", timestamp, md5Str, pubdef.AppId)
|
||
return urlAuth
|
||
}
|
||
|
||
// 生成鉴权url 七牛云
|
||
func generateUrlAuthQiniu(now time.Time, path string, authKey string) string {
|
||
timestamp := strconv.FormatInt(now.Add(2*time.Hour).Unix(), 16)
|
||
base64 := path
|
||
signStr := authKey + base64 + timestamp
|
||
md5Str := getMD5Sign(signStr)
|
||
urlAuth := fmt.Sprintf("?sign=%s&t=%s", md5Str, timestamp)
|
||
return urlAuth
|
||
}
|
||
|
||
// getMD5Sign 得到签名
|
||
func getMD5Sign(buf string) string {
|
||
md5Ctx := md5.New()
|
||
md5Ctx.Write([]byte(buf))
|
||
cipherStr := md5Ctx.Sum(nil)
|
||
nsign := hex.EncodeToString(cipherStr)
|
||
return nsign
|
||
}
|