Skip to content

Commit 2dcd739

Browse files
committed
WIP: Add httpchunksize option
Used to make youtube-dl do random range request around a specificed chunk size
1 parent b249570 commit 2dcd739

File tree

5 files changed

+113
-14
lines changed

5 files changed

+113
-14
lines changed

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/wader/ydls
22

3-
go 1.12
3+
go 1.13
44

55
require (
66
// bump: leaktest /github.com\/fortytw2\/leaktest v(.*)/ git:https://github.com/fortytw2/leaktest.git|^1
@@ -19,3 +19,5 @@ require (
1919
// bump: sync command go get -d golang.org/x/sync && go mod tidy
2020
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
2121
)
22+
23+
replace github.com/wader/goutubedl => /Users/wader/src/goutubedl

internal/humnum/humnum.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package humnum
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
"strings"
7+
"unicode"
8+
)
9+
10+
func Atoi(s string) (int, error) {
11+
i := strings.IndexFunc(s, func(r rune) bool {
12+
return !unicode.IsDigit(r)
13+
})
14+
if i == -1 {
15+
i = len(s)
16+
}
17+
18+
prefix, suffix := s[0:i], s[i:]
19+
n, _ := strconv.Atoi(prefix)
20+
m := 1
21+
if suffix != "" {
22+
switch strings.ToLower(suffix) {
23+
case "k":
24+
m = 1000
25+
case "ki", "kibi":
26+
m = 1024
27+
case "m":
28+
m = 1000 * 1000
29+
case "mi", "mibi":
30+
m = 1024 * 1024
31+
case "g":
32+
m = 1000 * 1000 * 1000
33+
case "gi", "gibi":
34+
m = 1024 * 1024 * 1024
35+
default:
36+
return 9, fmt.Errorf("unknown suffix %q", suffix)
37+
}
38+
}
39+
40+
return n * m, nil
41+
}

internal/humnum/numnum_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package humnum_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/wader/ydls/internal/humnum"
7+
)
8+
9+
func TestAtoi(t *testing.T) {
10+
testCases := []struct {
11+
s string
12+
expectedN int
13+
expectedErr string
14+
}{
15+
{s: "", expectedN: 0},
16+
{s: "1000", expectedN: 1000},
17+
{s: "1K", expectedN: 1000},
18+
{s: "1k", expectedN: 1000},
19+
{s: "1M", expectedN: 1000_000},
20+
{s: "1G", expectedN: 1000_000_000},
21+
{s: "1Ki", expectedN: 1024},
22+
{s: "1Mi", expectedN: 1024 * 1024},
23+
{s: "1Gi", expectedN: 1024 * 1024 * 1024},
24+
{s: "1Kibi", expectedN: 1024},
25+
{s: "1Mibi", expectedN: 1024 * 1024},
26+
{s: "1Gibi", expectedN: 1024 * 1024 * 1024},
27+
{s: "123abc", expectedErr: `unknown suffix "abc"`},
28+
}
29+
for _, tC := range testCases {
30+
t.Run(tC.s, func(t *testing.T) {
31+
actualN, actualErr := humnum.Atoi(tC.s)
32+
if (tC.expectedErr != "" && (actualErr == nil || tC.expectedErr != actualErr.Error())) && actualN != tC.expectedN {
33+
t.Errorf("expected %v (%v), got %v (%v)", tC.expectedN, tC.expectedErr, actualN, actualErr)
34+
}
35+
})
36+
}
37+
}

internal/ydls/requestoptions.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@ import (
66
"strconv"
77
"strings"
88

9+
"github.com/wader/ydls/internal/humnum"
910
"github.com/wader/ydls/internal/timerange"
1011
)
1112

1213
// RequestOptions request options
1314
type RequestOptions struct {
14-
MediaRawURL string // youtubedl media URL
15-
Format *Format // output format
16-
Codecs []string // force codecs
17-
Retranscode bool // force retranscode even if same input codec
18-
TimeRange timerange.TimeRange // time range limit
19-
Items uint // feed item count limit
15+
MediaRawURL string // youtubedl media URL
16+
Format *Format // output format
17+
Codecs []string // force codecs
18+
Retranscode bool // force retranscode even if same input codec
19+
TimeRange timerange.TimeRange // time range limit
20+
Items uint // feed item count limit
21+
HTTPChunkSize uint // youtubedl http chunk size option
2022
}
2123

2224
// NewRequestOptionsFromQuery /?url=...&format=...
@@ -70,13 +72,24 @@ func NewRequestOptionsFromQuery(v url.Values, formats Formats) (RequestOptions,
7072
items = uint(itemsN)
7173
}
7274

75+
httpChunkSize := uint(0)
76+
httpChunkSizeStr := v.Get("httpchunksize")
77+
if httpChunkSizeStr != "" {
78+
httpChunkSizeN, httpChunkSizeNErr := humnum.Atoi(httpChunkSizeStr)
79+
if httpChunkSizeNErr != nil {
80+
return RequestOptions{}, fmt.Errorf("invalid HTTP chunk size")
81+
}
82+
httpChunkSize = uint(httpChunkSizeN)
83+
}
84+
7385
return RequestOptions{
74-
MediaRawURL: mediaRawURL,
75-
Format: format,
76-
Codecs: codecs,
77-
Retranscode: v.Get("retranscode") != "",
78-
TimeRange: timeRange,
79-
Items: items,
86+
MediaRawURL: mediaRawURL,
87+
Format: format,
88+
Codecs: codecs,
89+
Retranscode: v.Get("retranscode") != "",
90+
TimeRange: timeRange,
91+
Items: items,
92+
HTTPChunkSize: httpChunkSize,
8093
}, nil
8194
}
8295

@@ -173,7 +186,6 @@ func NewRequestOptionsFromOpts(opts []string, formats Formats) (RequestOptions,
173186
return RequestOptions{}, fmt.Errorf("invalid items count")
174187
}
175188
r.Items = uint(itemsN)
176-
strconv.ParseUint("", 10, 32)
177189
} else if _, ok := codecNames[opt]; ok {
178190
r.Codecs = append(r.Codecs, opt)
179191
} else if tr, trErr := timerange.NewTimeRangeFromString(opt); trErr == nil {
@@ -206,5 +218,8 @@ func (r RequestOptions) QueryValues() url.Values {
206218
if r.Items > 0 {
207219
v.Set("items", strconv.Itoa(int(r.Items)))
208220
}
221+
if r.HTTPChunkSize != 0 {
222+
v.Set("httpchunksize", strconv.Itoa(int(r.HTTPChunkSize)))
223+
}
209224
return v
210225
}

internal/ydls/ydls.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,10 @@ func (ydls *YDLS) download(ctx context.Context, options DownloadOptions, attempt
427427
}
428428
}
429429

430+
if options.RequestOptions.HTTPChunkSize != 0 {
431+
ydlOptions.HTTPChunkSize = options.RequestOptions.HTTPChunkSize
432+
}
433+
430434
ydlResult, err := goutubedl.New(ctx, options.RequestOptions.MediaRawURL, ydlOptions)
431435
if err != nil {
432436
log.Printf("Failed to download: %s", err)

0 commit comments

Comments
 (0)