feat(transcode): add a generic transcoding package for encoding/decoding/caching
This commit is contained in:
59
server/ctrlsubsonic/httprange/httprange.go
Normal file
59
server/ctrlsubsonic/httprange/httprange.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package httprange
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Unit string
|
||||
|
||||
const (
|
||||
UnitBytes Unit = "bytes"
|
||||
)
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var (
|
||||
reg = regexp.MustCompile(`^(?P<unit>\w+)=(?P<start>(?:\d+)?)\s*-\s*(?P<end>(?:\d+)?)$`)
|
||||
unit = reg.SubexpIndex("unit")
|
||||
start = reg.SubexpIndex("start")
|
||||
end = reg.SubexpIndex("end")
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidRange = fmt.Errorf("invalid range")
|
||||
ErrUnknownUnit = fmt.Errorf("unknown range")
|
||||
)
|
||||
|
||||
type Range struct {
|
||||
Start, End, Length int // bytes
|
||||
Partial bool
|
||||
}
|
||||
|
||||
func Parse(in string, fullLength int) (Range, error) {
|
||||
parts := reg.FindStringSubmatch(in)
|
||||
if len(parts)-1 != reg.NumSubexp() {
|
||||
return Range{0, fullLength - 1, fullLength, false}, nil
|
||||
}
|
||||
|
||||
switch unit := parts[unit]; Unit(unit) {
|
||||
case UnitBytes:
|
||||
default:
|
||||
return Range{}, fmt.Errorf("%q: %w", unit, ErrUnknownUnit)
|
||||
}
|
||||
|
||||
start, _ := strconv.Atoi(parts[start])
|
||||
end, _ := strconv.Atoi(parts[end])
|
||||
length := fullLength
|
||||
partial := false
|
||||
|
||||
switch {
|
||||
case end > 0 && end < length:
|
||||
length = end - start + 1
|
||||
partial = true
|
||||
case end == 0 && length > 0:
|
||||
end = length - 1
|
||||
}
|
||||
|
||||
return Range{start, end, length, partial}, nil
|
||||
}
|
||||
30
server/ctrlsubsonic/httprange/httprange_test.go
Normal file
30
server/ctrlsubsonic/httprange/httprange_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package httprange_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/matryer/is"
|
||||
"go.senan.xyz/gonic/server/ctrlsubsonic/httprange"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
full := func(start, end, length int) httprange.Range {
|
||||
return httprange.Range{Start: start, End: end, Length: length}
|
||||
}
|
||||
partial := func(start, end, length int) httprange.Range {
|
||||
return httprange.Range{Start: start, End: end, Length: length, Partial: true}
|
||||
}
|
||||
parse := func(in string, length int) httprange.Range {
|
||||
is.Helper()
|
||||
rrange, err := httprange.Parse(in, length)
|
||||
is.NoErr(err)
|
||||
return rrange
|
||||
}
|
||||
|
||||
is.Equal(parse("bytes=0-0", 0), full(0, 0, 0))
|
||||
is.Equal(parse("bytes=0-", 10), full(0, 9, 10))
|
||||
is.Equal(parse("bytes=0-49", 50), partial(0, 49, 50))
|
||||
is.Equal(parse("bytes=50-99", 100), partial(50, 99, 50))
|
||||
}
|
||||
Reference in New Issue
Block a user