Added way to handle disabled audio. Moved to channels/goroutines
This commit is contained in:
parent
b37a312b18
commit
354bbbf7df
@ -1,14 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"m3u8-downloader/pkg/downloader"
|
||||
"m3u8-downloader/pkg/media"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
//Stream URL
|
||||
masterUrl := "https://d17cyqyz9yhmep.cloudfront.net/streams/234945/playlist_1752291107574_1752292056713.m3u8"
|
||||
masterUrl := "https://d17cyqyz9yhmep.cloudfront.net/streams/234951/playlist_vo_1752978025523_1752978954944.m3u8"
|
||||
|
||||
//Download Service
|
||||
service := downloader.GetDownloadService()
|
||||
@ -21,15 +22,17 @@ func main() {
|
||||
}
|
||||
|
||||
//Select best quality streams
|
||||
audio, video := stream.Master.SelectBestQualityStreams()
|
||||
video, audio := stream.Master.SelectBestQualityStreams()
|
||||
|
||||
//Populate Segment Lists
|
||||
if !(audio == nil) {
|
||||
audio_segments, err := service.ParseSegmentPlaylist(stream.BuildSegmentURL(audio.URL))
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
audio.Segments = *audio_segments
|
||||
}
|
||||
//Populate Segment Lists
|
||||
|
||||
video_segments, err := service.ParseSegmentPlaylist(stream.BuildSegmentURL(video.URL))
|
||||
|
||||
@ -38,45 +41,38 @@ func main() {
|
||||
}
|
||||
video.Segments = *video_segments
|
||||
|
||||
//Download Segment Playlists
|
||||
for _, segment := range video.Segments.SegmentList {
|
||||
err := service.DownloadFile(stream.BuildSegmentURL(segment.URL))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
audioChan := make(chan media.Segment, 10)
|
||||
videoChan := make(chan media.Segment, 10)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
if !(audio == nil) {
|
||||
for i := 1; i <= 2; i++ {
|
||||
wg.Add(1)
|
||||
go service.DownloadWorker(i, audioChan, &wg)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 1; i <= 4; i++ {
|
||||
wg.Add(1)
|
||||
go service.DownloadWorker(i, videoChan, &wg)
|
||||
}
|
||||
|
||||
if !(audio == nil) {
|
||||
go func() {
|
||||
for _, segment := range audio.Segments.SegmentList {
|
||||
err := service.DownloadFile(stream.BuildSegmentURL(segment.URL))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
audioChan <- segment
|
||||
}
|
||||
close(audioChan)
|
||||
}()
|
||||
}
|
||||
fmt.Println(stream)
|
||||
|
||||
//stream, err := media.ParseMasterPlaylist(masterUrl)
|
||||
//if err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
//
|
||||
//audio, video, err := stream.FetchSegmentPlaylists()
|
||||
//if err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
//
|
||||
//videoPlaylist := media.ParseMediaPlaylist(video)
|
||||
//audioPlaylist := media.ParseMediaPlaylist(audio)
|
||||
//
|
||||
//for _, segment := range videoPlaylist.SegmentList {
|
||||
// fmt.Println(segment.URL)
|
||||
//}
|
||||
//
|
||||
//for _, segment := range audioPlaylist.SegmentList {
|
||||
// err := http.DownloadFile(stream.BuildSegmentURL(segment.URL), media.OutputDirPath)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
//}
|
||||
go func() {
|
||||
for _, segment := range video.Segments.SegmentList {
|
||||
videoChan <- segment
|
||||
}
|
||||
close(videoChan)
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
HTTPUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0"
|
||||
HTTPUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
|
||||
HTTPPrefix = "http://"
|
||||
HTTPSPrefix = "https://"
|
||||
REFERRER = "https://www.flomarching.com"
|
||||
)
|
||||
|
||||
21
pkg/downloader/worker.go
Normal file
21
pkg/downloader/worker.go
Normal file
@ -0,0 +1,21 @@
|
||||
package downloader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"m3u8-downloader/pkg/media"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func (s *DownloadService) DownloadWorker(id int, segmentChan <-chan media.Segment, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
for segment := range segmentChan {
|
||||
|
||||
fmt.Printf("[Worker %d] Downloading: %s\n", id, segment.URL)
|
||||
err := s.DownloadFile(segment.URL)
|
||||
if err != nil {
|
||||
fmt.Printf("[Worker %d] Error: %s\n", id, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,5 +60,6 @@ var DefaultClient = &HTTPWrapper{
|
||||
client: &http.Client{},
|
||||
headers: map[string]string{
|
||||
"User-Agent": constants.HTTPUserAgent,
|
||||
"Referer": constants.REFERRER,
|
||||
},
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ type VideoPlaylist struct {
|
||||
}
|
||||
|
||||
func NewVideoStream(streamInfo, url string) (*VideoPlaylist, error) {
|
||||
hasAudio := strings.Contains(strings.ToLower(streamInfo), "audio")
|
||||
if !strings.HasPrefix(streamInfo, constants.ExtXStreamInf) {
|
||||
return nil, errors.New("invalid stream info line")
|
||||
}
|
||||
@ -28,7 +29,7 @@ func NewVideoStream(streamInfo, url string) (*VideoPlaylist, error) {
|
||||
matches := reg.FindAllStringSubmatch(streamInfo, -1)
|
||||
|
||||
if len(matches) < 5 {
|
||||
return nil, errors.New("insufficient stream attributes")
|
||||
fmt.Println("Less than 5 stream attributes found - audio likely disabled")
|
||||
}
|
||||
|
||||
bandwidth, err := strconv.Atoi(matches[0][2])
|
||||
@ -36,6 +37,7 @@ func NewVideoStream(streamInfo, url string) (*VideoPlaylist, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if hasAudio {
|
||||
return &VideoPlaylist{
|
||||
URL: url,
|
||||
Bandwidth: bandwidth,
|
||||
@ -46,6 +48,16 @@ func NewVideoStream(streamInfo, url string) (*VideoPlaylist, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &VideoPlaylist{
|
||||
URL: url,
|
||||
Bandwidth: bandwidth,
|
||||
Codecs: StripQuotes(matches[1][2]),
|
||||
Resolution: StripQuotes(matches[2][2]),
|
||||
FrameRate: StripQuotes(matches[3][2]),
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (v *VideoPlaylist) BuildPlaylistURL(filename string) string {
|
||||
return fmt.Sprintf("%s%s", constants.HTTPSPrefix, v.URL+"/a/5000/"+filename)
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ type SegmentPlaylist struct {
|
||||
//}
|
||||
|
||||
func (s *StreamSet) BuildSegmentURL(filename string) string {
|
||||
return fmt.Sprintf("%s%s", constants.HTTPSPrefix, s.Metadata.Domain+"/streams/"+s.Metadata.StreamID+"/a/5000/"+filename)
|
||||
return fmt.Sprintf("%s%s", constants.HTTPSPrefix, s.Metadata.Domain+"/streams/"+s.Metadata.StreamID+"/"+filename)
|
||||
}
|
||||
|
||||
func ParseMediaPlaylist(content string) *SegmentPlaylist {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user