Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
97 lines
2.6 KiB
Go
97 lines
2.6 KiB
Go
package m3u8
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"io"
|
|
"strings"
|
|
"videoweb/pub/common/errors"
|
|
"videoweb/pub/common/utils"
|
|
"videoweb/pub/storage/proxy"
|
|
)
|
|
|
|
// TransformVtt 读取雪碧图 vtt 文件,并把其中的缩略图路径替换为图片 cdn 地址。
|
|
// 兼容现有 /laosiji 路径资源:laosiji 的 vtt 需移除 /laosiji 前缀后,从 lsjImageYuan 源站读取。
|
|
// imgCdn 图片 cdn 域名(缩略图访问地址)
|
|
// origDomain 普通媒资的源站域名
|
|
// lsjImageYuan 老司机图片源站域名(由 app/web 项目从配置 lsjMediaConf.imageYuan 传入)
|
|
func TransformVtt(name, imgCdn, origDomain, lsjImageYuan string) (buff []byte, err error) {
|
|
if name == "" {
|
|
err = errors.MakeWithMsg(errors.M3u8FileName, "vtt file name is empty")
|
|
return
|
|
}
|
|
if imgCdn == "" || origDomain == "" {
|
|
err = errors.MakeWithMsg(errors.DomainErr, "imgCdn or origDomain is empty")
|
|
return
|
|
}
|
|
|
|
mediaVersion := proxy.AppendsMediaS3Version(name)
|
|
if len(mediaVersion) > 0 {
|
|
name = mediaVersion + name
|
|
}
|
|
|
|
originName := name
|
|
if strings.Contains(name, "laosiji") {
|
|
if lsjImageYuan == "" {
|
|
err = errors.MakeWithMsg(errors.DomainErr, "lsjImageYuan is empty")
|
|
return
|
|
}
|
|
originName = stripLaosijiPrefix(name)
|
|
origDomain = lsjImageYuan
|
|
}
|
|
|
|
srcReader, err := readFromRedis(originName, origDomain)
|
|
if err != nil {
|
|
return
|
|
}
|
|
raw, err := io.ReadAll(srcReader)
|
|
if err != nil {
|
|
return nil, errors.MakeWithMsg(errors.M3u8Read, "read vtt reader fail: "+err.Error())
|
|
}
|
|
|
|
dirPath := utils.PathForInfo(name).Dir
|
|
buff = rewriteVttWithCDN(raw, imgCdn, dirPath)
|
|
return
|
|
}
|
|
|
|
func stripLaosijiPrefix(name string) string {
|
|
p := strings.TrimPrefix(name, "/")
|
|
p = strings.TrimPrefix(p, "laosiji")
|
|
p = strings.TrimPrefix(p, "/")
|
|
return p
|
|
}
|
|
|
|
func rewriteVttWithCDN(vttData []byte, imgCdn, dirPath string) []byte {
|
|
imgCdn = strings.TrimRight(strings.TrimSpace(imgCdn), "/")
|
|
|
|
var out bytes.Buffer
|
|
scanner := bufio.NewScanner(bytes.NewReader(vttData))
|
|
scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024)
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
trim := strings.TrimSpace(line)
|
|
|
|
if idx := strings.Index(trim, "#xywh="); idx >= 0 {
|
|
p := strings.TrimSpace(trim[:idx])
|
|
xywh := trim[idx:]
|
|
|
|
var newPath string
|
|
switch {
|
|
case strings.HasPrefix(p, "http://") || strings.HasPrefix(p, "https://"):
|
|
newPath = p
|
|
case strings.HasPrefix(p, "/"):
|
|
newPath = imgCdn + p
|
|
default:
|
|
newPath = utils.JoinUrlPath(utils.JoinUrlPath(imgCdn, strings.TrimRight(dirPath, "/")), p)
|
|
}
|
|
out.WriteString(newPath + xywh + "\n")
|
|
continue
|
|
}
|
|
|
|
out.WriteString(line + "\n")
|
|
}
|
|
|
|
return out.Bytes()
|
|
}
|