Skip to content

Commit

Permalink
Read Content-Length from HTTP response if information is missing in v…
Browse files Browse the repository at this point in the history
…ideo

closes #246
  • Loading branch information
corny committed May 5, 2022
1 parent 46ebe0a commit 28b8133
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 16 deletions.
52 changes: 36 additions & 16 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io"
"log"
"net/http"
"strconv"
)

// Client offers methods to download video metadata and video streams.
Expand Down Expand Up @@ -235,13 +236,45 @@ func (c *Client) GetStreamContext(ctx context.Context, video *Video, format *For
}

r, w := io.Pipe()
contentLength := format.ContentLength

go c.download(req, w, format)
if contentLength == 0 {
// some videos don't have length information
contentLength = c.downloadOnce(req, w, format)
} else {
// we have length information, let's download by chunks!
go c.downloadChunked(req, w, format)
}

return r, contentLength, nil
}

func (c *Client) downloadOnce(req *http.Request, w *io.PipeWriter, format *Format) int64 {
resp, err := c.httpDo(req)
if err != nil {
//nolint:errcheck
w.CloseWithError(err)
return 0
}

go func() {
defer resp.Body.Close()
_, err := io.Copy(w, resp.Body)
if err == nil {
w.Close()
} else {
//nolint:errcheck
w.CloseWithError(err)
}
}()

return r, format.ContentLength, nil
contentLength := resp.Header.Get("Content-Length")
len, _ := strconv.ParseInt(contentLength, 10, 64)

return len
}

func (c *Client) download(req *http.Request, w *io.PipeWriter, format *Format) {
func (c *Client) downloadChunked(req *http.Request, w *io.PipeWriter, format *Format) {
const chunkSize int64 = 10_000_000
// Loads a chunk a returns the written bytes.
// Downloading in multiple chunks is much faster:
Expand All @@ -263,19 +296,6 @@ func (c *Client) download(req *http.Request, w *io.PipeWriter, format *Format) {
}

defer w.Close()
//nolint:revive,errcheck
if format.ContentLength == 0 {
resp, err := c.httpDo(req)
if err != nil {
w.CloseWithError(err)
return
}

defer resp.Body.Close()

io.Copy(w, resp.Body)
return
}

//nolint:revive,errcheck
// load all the chunks
Expand Down
12 changes: 12 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,23 @@ func TestGetVideoWithManifestURL(t *testing.T) {
require.NoError(err)
require.NotNil(video)

assert.NotEmpty(video.Formats)
assert.NotEmpty(video.Thumbnails)
assert.Greater(len(video.Thumbnails), 0)
assert.NotEmpty(video.Thumbnails[0].URL)
assert.NotEmpty(video.HLSManifestURL)
assert.NotEmpty(video.DASHManifestURL)

// no size available?
format := video.Formats[0]
assert.Zero(format.ContentLength)

// We should get a size now
r, size, err := testClient.GetStream(video, &format)
if assert.NoError(err) {
r.Close()
}
assert.NotZero(size)
}

func TestGetStream(t *testing.T) {
Expand Down

0 comments on commit 28b8133

Please sign in to comment.