StreamRecorder/pkg/media/media_playlist.go

140 lines
3.3 KiB
Go

package media
import (
"errors"
"fmt"
"m3u8-downloader/pkg/constants"
"regexp"
"strconv"
"strings"
)
type VideoPlaylist struct {
URL string
Bandwidth int
Codecs string
Resolution string
FrameRate string
AudioGroup string
Segments SegmentPlaylist
}
func NewVideoStream(streamInfo, url string) (*VideoPlaylist, error) {
if !strings.HasPrefix(streamInfo, constants.ExtXStreamInf) {
return nil, errors.New("invalid stream info line")
}
reg := regexp.MustCompile(`([A-Z0-9-]+)=(".*?"|[^,]*)`)
matches := reg.FindAllStringSubmatch(streamInfo, -1)
if len(matches) < 5 {
return nil, errors.New("insufficient stream attributes")
}
bandwidth, err := strconv.Atoi(matches[0][2])
if err != nil {
return nil, err
}
return &VideoPlaylist{
URL: url,
Bandwidth: bandwidth,
Codecs: StripQuotes(matches[1][2]),
Resolution: StripQuotes(matches[2][2]),
FrameRate: StripQuotes(matches[3][2]),
AudioGroup: StripQuotes(matches[4][2]),
}, nil
}
func (v *VideoPlaylist) BuildPlaylistURL(filename string) string {
return fmt.Sprintf("%s%s", constants.HTTPSPrefix, v.URL+"/a/5000/"+filename)
}
type AudioPlaylist struct {
URL string
MediaType string
GroupID string
Name string
IsDefault bool
AutoSelect bool
Segments SegmentPlaylist
}
func (a *AudioPlaylist) BuildPlaylistURL(filename string) string {
return fmt.Sprintf("%s%s", constants.HTTPSPrefix, a.URL+"/a/5000/"+filename)
}
func NewAudioStream(mediaInfo string) (*AudioPlaylist, error) {
if !strings.HasPrefix(mediaInfo, constants.ExtXMedia) {
return nil, errors.New("invalid downloader info line")
}
attributes := ParseMediaAttributes(mediaInfo)
return &AudioPlaylist{
URL: StripQuotes(attributes["URI"]),
MediaType: StripQuotes(attributes["TYPE"]),
GroupID: StripQuotes(attributes["GROUP-ID"]),
Name: StripQuotes(attributes["NAME"]),
IsDefault: attributes["DEFAULT"] == "YES",
AutoSelect: attributes["AUTOSELECT"] == "YES",
}, nil
}
type PlaylistMetadata struct {
URL string
Domain string
StreamID string
}
func GetPlaylistMetadata(masterURL string) *PlaylistMetadata {
strippedURL := strings.Replace(masterURL, constants.HTTPSPrefix, "", 1)
strippedURL = strings.Replace(strippedURL, constants.HTTPPrefix, "", 1)
urlPrefix := strings.Split(strippedURL, "/")[0]
return &PlaylistMetadata{
URL: masterURL,
Domain: urlPrefix,
StreamID: strings.Split(strippedURL, "/")[2],
}
}
func ParsePlaylistLines(content string) ([]VideoPlaylist, []AudioPlaylist) {
lines := strings.Split(content, "\n")
var videoStreams []VideoPlaylist
var audioStreams []AudioPlaylist
for i, line := range lines {
if strings.HasPrefix(line, constants.ExtXStreamInf) && i+1 < len(lines) {
if video, err := NewVideoStream(line, lines[i+1]); err == nil {
videoStreams = append(videoStreams, *video)
}
} else if strings.HasPrefix(line, constants.ExtXMedia) {
if audio, err := NewAudioStream(line); err == nil {
audioStreams = append(audioStreams, *audio)
}
}
}
return videoStreams, audioStreams
}
func ResolutionToPixels(resolution string) int {
parts := strings.Split(resolution, "x")
if len(parts) != 2 {
return 0
}
width, err := strconv.Atoi(parts[0])
if err != nil {
return 0
}
height, err := strconv.Atoi(parts[1])
if err != nil {
return 0
}
return width * height
}