package m3u8 import ( "bytes" "fmt" "io" "stat/common/enum/redisconst" "stat/common/errors" "stat/common/http" "stat/common/log" "stat/common/redis" "stat/common/utils" "strings" "github.com/grafov/m3u8" ) const ( keyUri = "/api/stat/media/enkey" AuthKey = "fT5xSg4hltHpzVy6aV9rVECDJ1J1pN" ) var headerMediaPlayList *m3u8.MediaPlaylist // TransFormWithSafely 被检查权限的播放列表 // 主要检查用户是否有观看该视频的权限 // apiType(1:app,2:h5app,3:web) func TransFormWithSafely(req *Req, cdnDomain, origDomain string, needHeader bool, apiType int) (*m3u8.MediaPlaylist, *bytes.Buffer, error) { if req.Name == "" { return nil, nil, errors.MakeWithMsg(errors.M3u8FileName, "file name is empty") } if cdnDomain == "" || origDomain == "" { return nil, nil, errors.MakeWithMsg(errors.DomainErr, "cdnDomain or origDomain is empty") } return transform(req.Name, cdnDomain, origDomain, needHeader, apiType) } func AppendsMediaS3Version(name string) string { // 默认使用V1 if name != "" && !strings.HasPrefix(name, "v2/") && !strings.HasPrefix(name, "v1/") && !strings.HasPrefix(name, "v3/") && !strings.HasPrefix(name, "/v2") && !strings.HasPrefix(name, "/v1") && !strings.HasPrefix(name, "/v3") { return "/v1" } return "" } // transform m3u8文件转换,将不正确的m3u8文件,替换为正确的m3u8文件 func transform(name string, cdnDomain, origDomain string, needHeader bool, apiType int) (media *m3u8.MediaPlaylist, buff *bytes.Buffer, err error) { 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 } tmptKeyurl := keyUri fmt.Println("<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>") switch t { case m3u8.MEDIA: pl := p.(*m3u8.MediaPlaylist) dirPath := utils.PathForInfo(name).Dir media, err = newMediaPlayList(pl, cdnDomain, origDomain, dirPath, tmptKeyurl, needHeader) 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 } //func readFromCDN(name, domain string) (reader io.Reader, err error) { // requestUrl := utils.JoinUrlPath(domain, name) // resp, err := http.GetLargeFile(requestUrl, nil) // if err != nil { // return // } // if resp.StatusCode != 200 { // msg := fmt.Sprintf("read m3u8 fail, url: %s, status code %d", requestUrl, resp.StatusCode) // err = errors.MakeWithMsg(errors.M3u8Read, msg) // return // } // reader = bytes.NewReader(resp.Data) // return //} // 从redis缓存中读取 func readFromRedis(name, domain string) (reader io.Reader, err error) { m3u8Key := redisconst.MediaM3U8Key(name) data, err := redis.StatRds.GetBytes(m3u8Key) if err == nil && len(data) > 0 { reader = bytes.NewReader(data) return } requestUrl := utils.JoinUrlPath(domain, name) resp, err := http.GetLargeFile(requestUrl, nil) if err != nil { //fmt.Println("requestUrl111", requestUrl) return } if resp.StatusCode != 200 { msg := fmt.Sprintf("read m3u8 fail, url: %s, status code %d", requestUrl, resp.StatusCode) //fmt.Println(msg) err = errors.MakeWithMsg(errors.M3u8Read, msg) return } if err := redis.StatRds.Set(m3u8Key, resp.Data, redisconst.MediaM3U8CacheExpire); err != nil { log.Info("m3u8:readFromRedis redis set err", log.E(err)) } reader = bytes.NewReader(resp.Data) return } func GetHeaderMediaSegUrls() []string { urls := make([]string, 0) if headerMediaPlayList == nil { return urls } for _, segment := range headerMediaPlayList.Segments { if segment == nil { continue } urls = append(urls, segment.URI) } return urls }