Skip to content

Commit

Permalink
feat(transcode): add a generic transcoding package for encoding/decod…
Browse files Browse the repository at this point in the history
…ing/caching
  • Loading branch information
sentriz committed Apr 13, 2022
1 parent fd211d7 commit 165904c
Show file tree
Hide file tree
Showing 25 changed files with 711 additions and 386 deletions.
5 changes: 3 additions & 2 deletions go.mod
Expand Up @@ -11,6 +11,7 @@ require (
github.com/disintegration/imaging v1.6.2
github.com/dustin/go-humanize v1.0.0
github.com/faiface/beep v1.1.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/mux v1.8.0
github.com/gorilla/securecookie v1.1.1
Expand All @@ -26,7 +27,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/lib/pq v1.3.0 // indirect
github.com/matryer/is v1.4.0
github.com/mattn/go-sqlite3 v1.14.11 // indirect
github.com/mattn/go-sqlite3 v1.14.11
github.com/mewkiz/pkg v0.0.0-20211102230744-16a6ce8f1b77 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mmcdole/gofeed v1.1.3
Expand All @@ -40,7 +41,7 @@ require (
github.com/sentriz/gormstore v0.0.0-20220105134332-64e31f7f6981
github.com/stretchr/testify v1.7.0 // indirect
golang.org/x/crypto v0.0.0-20220209155544-dad33157f4bf // indirect
golang.org/x/exp/shiny v0.0.0-20220209042442-160e291fcf24 // indirect
golang.org/x/exp/shiny v0.0.0-20220407100705-7b9b53b0aca4 // indirect
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
golang.org/x/mobile v0.0.0-20220112015953-858099ff7816 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
Expand Down
6 changes: 5 additions & 1 deletion go.sum
Expand Up @@ -22,7 +22,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
Expand Down Expand Up @@ -50,6 +49,8 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2V
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
Expand All @@ -76,6 +77,7 @@ github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lTo
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jezek/xgb v1.0.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk=
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
Expand Down Expand Up @@ -170,6 +172,8 @@ golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMD
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/exp/shiny v0.0.0-20220209042442-160e291fcf24 h1:jn6Q9FOmCn1Kk7ec3Qm9lfygAr7dv8J1YfEx6RQcRJQ=
golang.org/x/exp/shiny v0.0.0-20220209042442-160e291fcf24/go.mod h1:NtXcNtv5Wu0zUbBl574y/D5MMZvnQnV3sgjZxbs64Jo=
golang.org/x/exp/shiny v0.0.0-20220407100705-7b9b53b0aca4 h1:ywNGLBFk8tKaiu+GYZeoXWzrFoJ/a1LHYKy1lb3R9cM=
golang.org/x/exp/shiny v0.0.0-20220407100705-7b9b53b0aca4/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8=
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
Expand Down
4 changes: 2 additions & 2 deletions server/ctrladmin/handlers.go
Expand Up @@ -10,10 +10,10 @@ import (
"github.com/mmcdole/gofeed"

"go.senan.xyz/gonic/server/db"
"go.senan.xyz/gonic/server/encode"
"go.senan.xyz/gonic/server/scanner"
"go.senan.xyz/gonic/server/scrobble/lastfm"
"go.senan.xyz/gonic/server/scrobble/listenbrainz"
"go.senan.xyz/gonic/server/transcode"
)

func doScan(scanner *scanner.Scanner, opts scanner.ScanOptions) {
Expand Down Expand Up @@ -67,7 +67,7 @@ func (c *Controller) ServeHome(r *http.Request) *Response {
c.DB.
Where("user_id=?", user.ID).
Find(&data.TranscodePreferences)
for profile := range encode.Profiles() {
for profile := range transcode.UserProfiles {
data.TranscodeProfiles = append(data.TranscodeProfiles, profile)
}
// podcasts box
Expand Down
2 changes: 2 additions & 0 deletions server/ctrlsubsonic/ctrl.go
Expand Up @@ -15,6 +15,7 @@ import (
"go.senan.xyz/gonic/server/jukebox"
"go.senan.xyz/gonic/server/podcasts"
"go.senan.xyz/gonic/server/scrobble"
"go.senan.xyz/gonic/server/transcode"
)

type CtxKey int
Expand All @@ -34,6 +35,7 @@ type Controller struct {
Jukebox *jukebox.Jukebox
Scrobblers []scrobble.Scrobbler
Podcasts *podcasts.Podcasts
Transcoder transcode.Transcoder
}

type metaResponse struct {
Expand Down
67 changes: 55 additions & 12 deletions server/ctrlsubsonic/ctrl_test.go
Expand Up @@ -18,12 +18,22 @@ import (

"go.senan.xyz/gonic/server/ctrlbase"
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
"go.senan.xyz/gonic/server/db"
"go.senan.xyz/gonic/server/mockfs"
"go.senan.xyz/gonic/server/transcode"
)

var (
testDataDir = "testdata"
testCamelExpr = regexp.MustCompile("([a-z0-9])([A-Z])")
var testCamelExpr = regexp.MustCompile("([a-z0-9])([A-Z])")

const (
mockUsername = "admin"
mockPassword = "admin"
mockClientName = "test"
)

const (
audioPath5s = "testdata/audio/5s.flac" //nolint:deadcode,varcheck
audioPath10s = "testdata/audio/10s.flac" //nolint:deadcode,varcheck
)

type queryCase struct {
Expand All @@ -37,22 +47,43 @@ func makeGoldenPath(test string) string {
snake := testCamelExpr.ReplaceAllString(test, "${1}_${2}")
lower := strings.ToLower(snake)
relPath := strings.ReplaceAll(lower, "/", "_")
return path.Join(testDataDir, relPath)
return path.Join("testdata", relPath)
}

func makeHTTPMock(query url.Values) (*httptest.ResponseRecorder, *http.Request) {
// ensure the handlers give us json
query.Add("f", "json")
query.Add("u", mockUsername)
query.Add("p", mockPassword)
query.Add("v", "1")
query.Add("c", mockClientName)
// request from the handler in question
req, _ := http.NewRequest("", "", nil)
req.URL.RawQuery = query.Encode()
subParams := params.New(req)
withParams := context.WithValue(req.Context(), CtxParams, subParams)
ctx := req.Context()
ctx = context.WithValue(ctx, CtxParams, params.New(req))
ctx = context.WithValue(ctx, CtxUser, &db.User{})
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
req = req.WithContext(withParams)
return rr, req
}

func serveRaw(t *testing.T, contr *Controller, h handlerSubsonicRaw, rr *httptest.ResponseRecorder, req *http.Request) {
type middleware func(http.Handler) http.Handler
middlewares := []middleware{
contr.WithParams,
contr.WithRequiredParams,
contr.WithUser,
}

handler := contr.HR(h)
for _, m := range middlewares {
handler = m(handler)
}

handler.ServeHTTP(rr, req)
}

func runQueryCases(t *testing.T, contr *Controller, h handlerSubsonic, cases []*queryCase) {
t.Helper()
for _, qc := range cases {
Expand Down Expand Up @@ -96,28 +127,40 @@ func runQueryCases(t *testing.T, contr *Controller, h handlerSubsonic, cases []*
}
}

func makeController(t *testing.T) *Controller { return makec(t, []string{""}) }
func makeControllerRoots(t *testing.T, r []string) *Controller { return makec(t, r) }
func makeController(t *testing.T) *Controller { return makec(t, []string{""}, false) }
func makeControllerRoots(t *testing.T, r []string) *Controller { return makec(t, r, false) }
func makeControllerAudio(t *testing.T) *Controller { return makec(t, []string{""}, true) }

func makec(t *testing.T, roots []string) *Controller {
func makec(t *testing.T, roots []string, audio bool) *Controller {
t.Helper()

m := mockfs.NewWithDirs(t, roots)
for _, root := range roots {
m.AddItemsPrefixWithCovers(root)
if !audio {
continue
}
m.SetRealAudio(filepath.Join(root, "artist-0/album-0/track-0.flac"), 10, audioPath10s)
m.SetRealAudio(filepath.Join(root, "artist-0/album-0/track-1.flac"), 10, audioPath10s)
m.SetRealAudio(filepath.Join(root, "artist-0/album-0/track-2.flac"), 10, audioPath10s)
}

m.ScanAndClean()
m.ResetDates()
m.LogAlbums()

var absRoots []string
for _, root := range roots {
absRoots = append(absRoots, filepath.Join(m.TmpDir(), root))
}

base := &ctrlbase.Controller{DB: m.DB()}
return &Controller{Controller: base, MusicPaths: absRoots}
contr := &Controller{
Controller: base,
MusicPaths: absRoots,
Transcoder: transcode.NewFFmpegTranscoder(),
}

return contr
}

func TestMain(m *testing.M) {
Expand Down

0 comments on commit 165904c

Please sign in to comment.