From 423a761ff841095074b7f6cca3b0cb6308e33dbe Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Wed, 25 Dec 2013 23:14:44 -0500 Subject: [PATCH] version 1.0.3 --- CHANGELOG.md | 6 ++++++ README.md | 2 +- main.go | 56 ++++++++++++++++++++++++++++++++-------------------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5987dca..f41508c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +1.0.3 - 12/25/2013 + +* Improve logging +* Fix over-recording bug +* Unescape all URLs to reduce risk of duplicate segment downloads (e.g. China Central TV streams) + 1.0.2 - 12/25/2013 * Bypass URL parsing for absolute media segment URLs diff --git a/README.md b/README.md index 0581411..bdfa38e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ gohls - HTTP Live Streaming (HLS) downloader written in Golang -* Current version: **1.0.2** +* Current version: **1.0.3** * Author: Kevin Zhang * License: [GNU GPL version 3](http://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/main.go b/main.go index c3b1693..0871900 100644 --- a/main.go +++ b/main.go @@ -29,7 +29,7 @@ import "lru" // https://github.com/golang/groupcache/blob/master/lru/lru.go import "strings" import "github.com/grafov/m3u8" -const VERSION = "1.0.2" +const VERSION = "1.0.3" var USER_AGENT string @@ -41,14 +41,19 @@ func doRequest(c *http.Client, req *http.Request) (*http.Response, error) { return resp, err } -func downloadSegment(fn string, feed chan string) { +type Download struct { + URI string + totalDuration time.Duration +} + +func downloadSegment(fn string, dlc chan *Download, recTime time.Duration) { out, err := os.Create(fn) if err != nil { log.Fatal(err) } defer out.Close() - for v := range feed { - req, err := http.NewRequest("GET", v, nil) + for v := range dlc { + req, err := http.NewRequest("GET", v.URI, nil) if err != nil { log.Fatal(err) } @@ -62,13 +67,14 @@ func downloadSegment(fn string, feed chan string) { log.Fatal(err) } resp.Body.Close() - log.Printf("Downloaded %v\n", v) + log.Printf("Downloaded %v\n", v.URI) + log.Printf("Recorded %v of %v\n", v.totalDuration, recTime) } } -func getPlaylist(urlStr string, duration time.Duration, useLocalTime bool, feed chan string) { +func getPlaylist(urlStr string, recTime time.Duration, useLocalTime bool, dlc chan *Download) { startTime := time.Now() - var recTime time.Duration + var recDuration time.Duration = 0 cache := lru.New(64) playlistUrl, err := url.Parse(urlStr) if err != nil { @@ -95,35 +101,39 @@ func getPlaylist(urlStr string, duration time.Duration, useLocalTime bool, feed if v != nil { var msURI string if strings.HasPrefix(v.URI, "http") { - msURI = v.URI + msURI, err = url.QueryUnescape(v.URI) + if err != nil { + log.Fatal(err) + } } else { msUrl, err := playlistUrl.Parse(v.URI) if err != nil { log.Print(err) continue } - msURI = msUrl.String() + msURI, err = url.QueryUnescape(msUrl.String()) + if err != nil { + log.Fatal(err) + } } _, hit := cache.Get(msURI) if !hit { - feed <- msURI cache.Add(msURI, nil) - log.Printf("Queued %v\n", msURI) if useLocalTime { - recTime = time.Now().Sub(startTime) + recDuration = time.Now().Sub(startTime) } else { - recTime += time.Duration(int64(v.Duration * 1000000000)) + recDuration += time.Duration(int64(v.Duration * 1000000000)) } - log.Printf("Recorded %v of %v\n", recTime, duration) + dlc <- &Download{msURI, recDuration} + } + if recDuration != 0 && recDuration >= recTime { + close(dlc) + return } - } - if duration != 0 && recTime > duration { - close(feed) - return } } if mpl.Closed { - close(feed) + close(dlc) return } else { time.Sleep(time.Duration(int64(mpl.TargetDuration * 1000000000))) @@ -150,7 +160,11 @@ func main() { os.Exit(2) } - msChan := make(chan string, 1024) + if !strings.HasPrefix(flag.Arg(0), "http") { + log.Fatal("Media playlist url must begin with http/https") + } + + msChan := make(chan *Download, 1024) go getPlaylist(flag.Arg(0), *duration, *useLocalTime, msChan) - downloadSegment(flag.Arg(1), msChan) + downloadSegment(flag.Arg(1), msChan, *duration) } \ No newline at end of file