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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"m3u8-downloader/pkg/downloader"
|
"m3u8-downloader/pkg/downloader"
|
||||||
|
"m3u8-downloader/pkg/media"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
//Stream URL
|
//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
|
//Download Service
|
||||||
service := downloader.GetDownloadService()
|
service := downloader.GetDownloadService()
|
||||||
@ -21,15 +22,17 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Select best quality streams
|
//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))
|
audio_segments, err := service.ParseSegmentPlaylist(stream.BuildSegmentURL(audio.URL))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
}
|
||||||
|
audio.Segments = *audio_segments
|
||||||
}
|
}
|
||||||
audio.Segments = *audio_segments
|
//Populate Segment Lists
|
||||||
|
|
||||||
video_segments, err := service.ParseSegmentPlaylist(stream.BuildSegmentURL(video.URL))
|
video_segments, err := service.ParseSegmentPlaylist(stream.BuildSegmentURL(video.URL))
|
||||||
|
|
||||||
@ -38,45 +41,38 @@ func main() {
|
|||||||
}
|
}
|
||||||
video.Segments = *video_segments
|
video.Segments = *video_segments
|
||||||
|
|
||||||
//Download Segment Playlists
|
audioChan := make(chan media.Segment, 10)
|
||||||
for _, segment := range video.Segments.SegmentList {
|
videoChan := make(chan media.Segment, 10)
|
||||||
err := service.DownloadFile(stream.BuildSegmentURL(segment.URL))
|
|
||||||
if err != nil {
|
var wg sync.WaitGroup
|
||||||
fmt.Println(err)
|
|
||||||
return
|
if !(audio == nil) {
|
||||||
|
for i := 1; i <= 2; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go service.DownloadWorker(i, audioChan, &wg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, segment := range audio.Segments.SegmentList {
|
for i := 1; i <= 4; i++ {
|
||||||
err := service.DownloadFile(stream.BuildSegmentURL(segment.URL))
|
wg.Add(1)
|
||||||
if err != nil {
|
go service.DownloadWorker(i, videoChan, &wg)
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fmt.Println(stream)
|
|
||||||
|
|
||||||
//stream, err := media.ParseMasterPlaylist(masterUrl)
|
if !(audio == nil) {
|
||||||
//if err != nil {
|
go func() {
|
||||||
// panic(err)
|
for _, segment := range audio.Segments.SegmentList {
|
||||||
//}
|
audioChan <- segment
|
||||||
//
|
}
|
||||||
//audio, video, err := stream.FetchSegmentPlaylists()
|
close(audioChan)
|
||||||
//if err != nil {
|
}()
|
||||||
// panic(err)
|
}
|
||||||
//}
|
|
||||||
//
|
go func() {
|
||||||
//videoPlaylist := media.ParseMediaPlaylist(video)
|
for _, segment := range video.Segments.SegmentList {
|
||||||
//audioPlaylist := media.ParseMediaPlaylist(audio)
|
videoChan <- segment
|
||||||
//
|
}
|
||||||
//for _, segment := range videoPlaylist.SegmentList {
|
close(videoChan)
|
||||||
// fmt.Println(segment.URL)
|
}()
|
||||||
//}
|
|
||||||
//
|
wg.Wait()
|
||||||
//for _, segment := range audioPlaylist.SegmentList {
|
|
||||||
// err := http.DownloadFile(stream.BuildSegmentURL(segment.URL), media.OutputDirPath)
|
|
||||||
// if err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
const (
|
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://"
|
HTTPPrefix = "http://"
|
||||||
HTTPSPrefix = "https://"
|
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{},
|
client: &http.Client{},
|
||||||
headers: map[string]string{
|
headers: map[string]string{
|
||||||
"User-Agent": constants.HTTPUserAgent,
|
"User-Agent": constants.HTTPUserAgent,
|
||||||
|
"Referer": constants.REFERRER,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ type VideoPlaylist struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewVideoStream(streamInfo, url string) (*VideoPlaylist, error) {
|
func NewVideoStream(streamInfo, url string) (*VideoPlaylist, error) {
|
||||||
|
hasAudio := strings.Contains(strings.ToLower(streamInfo), "audio")
|
||||||
if !strings.HasPrefix(streamInfo, constants.ExtXStreamInf) {
|
if !strings.HasPrefix(streamInfo, constants.ExtXStreamInf) {
|
||||||
return nil, errors.New("invalid stream info line")
|
return nil, errors.New("invalid stream info line")
|
||||||
}
|
}
|
||||||
@ -28,7 +29,7 @@ func NewVideoStream(streamInfo, url string) (*VideoPlaylist, error) {
|
|||||||
matches := reg.FindAllStringSubmatch(streamInfo, -1)
|
matches := reg.FindAllStringSubmatch(streamInfo, -1)
|
||||||
|
|
||||||
if len(matches) < 5 {
|
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])
|
bandwidth, err := strconv.Atoi(matches[0][2])
|
||||||
@ -36,14 +37,25 @@ func NewVideoStream(streamInfo, url string) (*VideoPlaylist, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hasAudio {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
return &VideoPlaylist{
|
return &VideoPlaylist{
|
||||||
URL: url,
|
URL: url,
|
||||||
Bandwidth: bandwidth,
|
Bandwidth: bandwidth,
|
||||||
Codecs: StripQuotes(matches[1][2]),
|
Codecs: StripQuotes(matches[1][2]),
|
||||||
Resolution: StripQuotes(matches[2][2]),
|
Resolution: StripQuotes(matches[2][2]),
|
||||||
FrameRate: StripQuotes(matches[3][2]),
|
FrameRate: StripQuotes(matches[3][2]),
|
||||||
AudioGroup: StripQuotes(matches[4][2]),
|
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VideoPlaylist) BuildPlaylistURL(filename string) string {
|
func (v *VideoPlaylist) BuildPlaylistURL(filename string) string {
|
||||||
|
|||||||
@ -46,7 +46,7 @@ type SegmentPlaylist struct {
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
func (s *StreamSet) BuildSegmentURL(filename string) string {
|
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 {
|
func ParseMediaPlaylist(content string) *SegmentPlaylist {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user