|
|
@@ -16,17 +16,34 @@ import ( |
|
|
|
) |
|
|
|
|
|
|
|
const baseScheme = "http" |
|
|
|
const MASTER = "master" |
|
|
|
const PLAYLIST = "playlist" |
|
|
|
|
|
|
|
type m3u8Json struct { |
|
|
|
master *m3u8.MasterPlaylist |
|
|
|
playlist []*m3u8.MediaPlaylist |
|
|
|
URL string |
|
|
|
BaseUrl string |
|
|
|
Type string |
|
|
|
Manifest interface{} |
|
|
|
} |
|
|
|
|
|
|
|
func nilIndex(input []*m3u8.MediaSegment) int { |
|
|
|
output := -1 |
|
|
|
|
|
|
|
for i := range input { |
|
|
|
if input[i] == nil { |
|
|
|
return i |
|
|
|
} |
|
|
|
} |
|
|
|
return output |
|
|
|
} |
|
|
|
|
|
|
|
func main() { |
|
|
|
isUrl := false |
|
|
|
var data *bufio.Reader |
|
|
|
var baseUrl string |
|
|
|
var outputJson m3u8Json |
|
|
|
recursive := flag.Bool("r", false, "Recursive download master and playlists") |
|
|
|
abs := flag.Bool("a", false, "make URI absolute") |
|
|
|
baseUrl := flag.String("b", "", "Base URL") |
|
|
|
flag.Parse() |
|
|
|
inputs := flag.Args() |
|
|
|
if len(inputs) != 1 { |
|
|
@@ -44,19 +61,28 @@ func main() { |
|
|
|
} |
|
|
|
|
|
|
|
if !isUrl { |
|
|
|
f, err := os.Open("playlist.m3u8") |
|
|
|
if err != nil { |
|
|
|
log.Fatal(err) |
|
|
|
var f *os.File |
|
|
|
var err error |
|
|
|
if input == "-" { |
|
|
|
data = bufio.NewReader(os.Stdin) |
|
|
|
} else { |
|
|
|
f, err = os.Open(input) |
|
|
|
if err != nil { |
|
|
|
log.Fatal(err) |
|
|
|
} |
|
|
|
data = bufio.NewReader(f) |
|
|
|
} |
|
|
|
fmt.Println("ok") |
|
|
|
data = bufio.NewReader(f) |
|
|
|
fmt.Println("ok2") |
|
|
|
|
|
|
|
} else { |
|
|
|
baseUrl = fmt.Sprintf("%v://%v%v", u.Scheme, u.Host, path.Dir(u.EscapedPath())) |
|
|
|
if *baseUrl == "" { |
|
|
|
*baseUrl = fmt.Sprintf("%v://%v%v", u.Scheme, u.Host, path.Dir(u.EscapedPath())) |
|
|
|
} |
|
|
|
r, err := http.Get(u.String()) |
|
|
|
if err != nil { |
|
|
|
log.Fatal(err) |
|
|
|
} |
|
|
|
outputJson.URL = u.String() |
|
|
|
outputJson.BaseUrl = *baseUrl |
|
|
|
data = bufio.NewReader(r.Body) |
|
|
|
} |
|
|
|
|
|
|
@@ -66,26 +92,63 @@ func main() { |
|
|
|
} |
|
|
|
switch listType { |
|
|
|
case m3u8.MEDIA: |
|
|
|
mediapl := p.(*m3u8.MediaPlaylist) |
|
|
|
fmt.Printf("%+v\n", mediapl) |
|
|
|
output, err := json.MarshalIndent(mediapl, "", " ") |
|
|
|
if err != nil { |
|
|
|
log.Fatal(err) |
|
|
|
outputJson.Type = PLAYLIST |
|
|
|
playlist := p.(*m3u8.MediaPlaylist) |
|
|
|
playlist.Segments = playlist.Segments[:nilIndex(playlist.Segments)] |
|
|
|
for _, entry := range playlist.Segments { |
|
|
|
u, err := url.Parse(entry.URI) |
|
|
|
if err != nil { |
|
|
|
log.Fatal("not a valid URL") |
|
|
|
} |
|
|
|
if *abs && !u.IsAbs() && *baseUrl != "" { |
|
|
|
entry.URI = *baseUrl + "/" + entry.URI |
|
|
|
} |
|
|
|
} |
|
|
|
fmt.Printf("%s", output) |
|
|
|
outputJson.Manifest = playlist |
|
|
|
case m3u8.MASTER: |
|
|
|
outputJson.master = p.(*m3u8.MasterPlaylist) |
|
|
|
fmt.Printf("%+v\n", outputJson.master) |
|
|
|
for _, entry := range outputJson.master.Variants { |
|
|
|
fmt.Println(entry.Resolution) |
|
|
|
if isUrl { |
|
|
|
fmt.Printf("%v/%v\n", baseUrl, entry.URI) |
|
|
|
outputJson.Type = MASTER |
|
|
|
master := p.(*m3u8.MasterPlaylist) |
|
|
|
for _, entry := range master.Variants { |
|
|
|
var chunckUrl string |
|
|
|
u, err := url.Parse(entry.URI) |
|
|
|
if err != nil { |
|
|
|
log.Fatal("not a valid URL") |
|
|
|
} |
|
|
|
if !u.IsAbs() { |
|
|
|
chunckUrl = *baseUrl + "/" + entry.URI |
|
|
|
if *abs && *baseUrl != "" { |
|
|
|
entry.URI = chunckUrl |
|
|
|
} |
|
|
|
} else { |
|
|
|
chunckUrl = entry.URI |
|
|
|
} |
|
|
|
if isUrl && *recursive { |
|
|
|
clist, err := http.Get(chunckUrl) |
|
|
|
if err != nil { |
|
|
|
log.Fatal(err) |
|
|
|
} |
|
|
|
cdata := bufio.NewReader(clist.Body) |
|
|
|
p, _, _ := m3u8.DecodeFrom(cdata, true) |
|
|
|
playlist := p.(*m3u8.MediaPlaylist) |
|
|
|
playlist.Segments = playlist.Segments[:nilIndex(playlist.Segments)] |
|
|
|
for _, entry := range playlist.Segments { |
|
|
|
u, err := url.Parse(entry.URI) |
|
|
|
if err != nil { |
|
|
|
log.Fatal("not a valid URL") |
|
|
|
} |
|
|
|
if *abs && !u.IsAbs() { |
|
|
|
entry.URI = *baseUrl + "/" + entry.URI |
|
|
|
} |
|
|
|
} |
|
|
|
entry.Chunklist = playlist |
|
|
|
} |
|
|
|
} |
|
|
|
output, err := json.MarshalIndent(outputJson.master, "", " ") |
|
|
|
if err != nil { |
|
|
|
log.Fatal(err) |
|
|
|
} |
|
|
|
fmt.Printf("%s", output) |
|
|
|
outputJson.Manifest = master |
|
|
|
} |
|
|
|
|
|
|
|
output, err := json.MarshalIndent(outputJson, "", " ") |
|
|
|
if err != nil { |
|
|
|
log.Fatal(err) |
|
|
|
} |
|
|
|
fmt.Printf("%s", output) |
|
|
|
} |