put helpers last

This commit is contained in:
sentriz
2023-10-01 03:19:07 +01:00
parent e9accfb71f
commit ae82153d79
7 changed files with 232 additions and 235 deletions

View File

@@ -23,6 +23,12 @@ import (
"go.senan.xyz/gonic/transcode"
)
func TestMain(m *testing.M) {
gonic.Version = ""
log.SetOutput(io.Discard)
os.Exit(m.Run())
}
var testCamelExpr = regexp.MustCompile("([a-z0-9])([A-Z])")
const (
@@ -156,9 +162,3 @@ func makec(tb testing.TB, roots []string, audio bool) *Controller {
return contr
}
func TestMain(m *testing.M) {
gonic.Version = ""
log.SetOutput(io.Discard)
os.Exit(m.Run())
}

View File

@@ -30,43 +30,46 @@ import (
// b) return a non-nil spec.Response
// _but not both_
func streamGetTransodePreference(dbc *db.DB, userID int, client string) (*db.TranscodePreference, error) {
var pref db.TranscodePreference
err := dbc.
Where("user_id=?", userID).
Where("client COLLATE NOCASE IN (?)", []string{"*", client}).
Order("client DESC"). // ensure "*" is last if it's there
First(&pref).
Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("find transcode preference: %w", err)
}
return &pref, nil
}
func streamGetTranscodeMeta(dbc *db.DB, userID int, client string) spec.TranscodeMeta {
pref, _ := streamGetTransodePreference(dbc, userID, client)
if pref == nil {
return spec.TranscodeMeta{}
}
profile, ok := transcode.UserProfiles[pref.Profile]
if !ok {
return spec.TranscodeMeta{}
}
return spec.TranscodeMeta{
TranscodedContentType: profile.MIME(),
TranscodedSuffix: profile.Suffix(),
}
}
const (
coverDefaultSize = 600
coverCacheFormat = "png"
)
func (c *Controller) ServeGetCoverArt(w http.ResponseWriter, r *http.Request) *spec.Response {
params := r.Context().Value(CtxParams).(params.Params)
id, err := params.GetID("id")
if err != nil {
return spec.NewError(10, "please provide an `id` parameter")
}
size := params.GetOrInt("size", coverDefaultSize)
cachePath := filepath.Join(
c.cacheCoverPath,
fmt.Sprintf("%s-%d.%s", id.String(), size, coverCacheFormat),
)
_, err = os.Stat(cachePath)
switch {
case os.IsNotExist(err):
reader, err := coverFor(c.dbc, c.artistInfoCache, id)
if err != nil {
return spec.NewError(10, "couldn't find cover `%s`: %v", id, err)
}
defer reader.Close()
if err := coverScaleAndSave(reader, cachePath, size); err != nil {
log.Printf("error scaling cover: %v", err)
return nil
}
case err != nil:
log.Printf("error stating `%s`: %v", cachePath, err)
return nil
}
w.Header().Set("Cache-Control", "public, max-age=3600")
http.ServeFile(w, r, cachePath)
return nil
}
var (
errCoverNotFound = errors.New("could not find a cover with that id")
errCoverEmpty = errors.New("no cover found")
@@ -163,41 +166,6 @@ func coverScaleAndSave(reader io.Reader, cachePath string, size int) error {
return nil
}
func (c *Controller) ServeGetCoverArt(w http.ResponseWriter, r *http.Request) *spec.Response {
params := r.Context().Value(CtxParams).(params.Params)
id, err := params.GetID("id")
if err != nil {
return spec.NewError(10, "please provide an `id` parameter")
}
size := params.GetOrInt("size", coverDefaultSize)
cachePath := filepath.Join(
c.cacheCoverPath,
fmt.Sprintf("%s-%d.%s", id.String(), size, coverCacheFormat),
)
_, err = os.Stat(cachePath)
switch {
case os.IsNotExist(err):
reader, err := coverFor(c.dbc, c.artistInfoCache, id)
if err != nil {
return spec.NewError(10, "couldn't find cover `%s`: %v", id, err)
}
defer reader.Close()
if err := coverScaleAndSave(reader, cachePath, size); err != nil {
log.Printf("error scaling cover: %v", err)
return nil
}
case err != nil:
log.Printf("error stating `%s`: %v", cachePath, err)
return nil
}
w.Header().Set("Cache-Control", "public, max-age=3600")
http.ServeFile(w, r, cachePath)
return nil
}
func (c *Controller) ServeStream(w http.ResponseWriter, r *http.Request) *spec.Response {
params := r.Context().Value(CtxParams).(params.Params)
user := r.Context().Value(CtxUser).(*db.User)
@@ -268,3 +236,35 @@ func (c *Controller) ServeGetAvatar(w http.ResponseWriter, r *http.Request) *spe
http.ServeContent(w, r, "", time.Now(), bytes.NewReader(reqUser.Avatar))
return nil
}
func streamGetTransodePreference(dbc *db.DB, userID int, client string) (*db.TranscodePreference, error) {
var pref db.TranscodePreference
err := dbc.
Where("user_id=?", userID).
Where("client COLLATE NOCASE IN (?)", []string{"*", client}).
Order("client DESC"). // ensure "*" is last if it's there
First(&pref).
Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("find transcode preference: %w", err)
}
return &pref, nil
}
func streamGetTranscodeMeta(dbc *db.DB, userID int, client string) spec.TranscodeMeta {
pref, _ := streamGetTransodePreference(dbc, userID, client)
if pref == nil {
return spec.TranscodeMeta{}
}
profile, ok := transcode.UserProfiles[pref.Profile]
if !ok {
return spec.TranscodeMeta{}
}
return spec.TranscodeMeta{
TranscodedContentType: profile.MIME(),
TranscodedSuffix: profile.Suffix(),
}
}

View File

@@ -37,96 +37,6 @@ import (
var ErrNoValues = errors.New("no values provided")
// some thin wrappers
// may be needed when cleaning up parse() below
func parseStr(in string) (string, error) { return in, nil }
func parseInt(in string) (int, error) { return strconv.Atoi(in) }
func parseFloat(in string) (float64, error) { return strconv.ParseFloat(in, 64) }
func parseID(in string) (specid.ID, error) { return specid.New(in) }
func parseBool(in string) (bool, error) { return strconv.ParseBool(in) }
func parseTime(in string) (time.Time, error) {
ms, err := strconv.Atoi(in)
if err != nil {
return time.Time{}, err
}
ns := int64(ms) * 1e6
return time.Unix(0, ns), nil
}
func parse(values []string, i interface{}) error {
if len(values) == 0 {
return ErrNoValues
}
var err error
switch v := i.(type) {
// *T
case *string:
*v, err = parseStr(values[0])
case *int:
*v, err = parseInt(values[0])
case *float64:
*v, err = parseFloat(values[0])
case *specid.ID:
*v, err = parseID(values[0])
case *bool:
*v, err = parseBool(values[0])
case *time.Time:
*v, err = parseTime(values[0])
// *[]T
case *[]string:
for _, value := range values {
parsed, err := parseStr(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
case *[]int:
for _, value := range values {
parsed, err := parseInt(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
case *[]float64:
for _, value := range values {
parsed, err := parseFloat(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
case *[]specid.ID:
for _, value := range values {
parsed, err := parseID(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
case *[]bool:
for _, value := range values {
parsed, err := parseBool(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
case *[]time.Time:
for _, value := range values {
parsed, err := parseTime(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
}
return err
}
type Params url.Values
func New(r *http.Request) Params {
@@ -461,3 +371,93 @@ func (p Params) GetFirstOrTime(or time.Time, keys ...string) time.Time {
}
return or
}
// some thin wrappers
// may be needed when cleaning up parse() below
func parseStr(in string) (string, error) { return in, nil }
func parseInt(in string) (int, error) { return strconv.Atoi(in) }
func parseFloat(in string) (float64, error) { return strconv.ParseFloat(in, 64) }
func parseID(in string) (specid.ID, error) { return specid.New(in) }
func parseBool(in string) (bool, error) { return strconv.ParseBool(in) }
func parseTime(in string) (time.Time, error) {
ms, err := strconv.Atoi(in)
if err != nil {
return time.Time{}, err
}
ns := int64(ms) * 1e6
return time.Unix(0, ns), nil
}
func parse(values []string, i interface{}) error {
if len(values) == 0 {
return ErrNoValues
}
var err error
switch v := i.(type) {
// *T
case *string:
*v, err = parseStr(values[0])
case *int:
*v, err = parseInt(values[0])
case *float64:
*v, err = parseFloat(values[0])
case *specid.ID:
*v, err = parseID(values[0])
case *bool:
*v, err = parseBool(values[0])
case *time.Time:
*v, err = parseTime(values[0])
// *[]T
case *[]string:
for _, value := range values {
parsed, err := parseStr(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
case *[]int:
for _, value := range values {
parsed, err := parseInt(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
case *[]float64:
for _, value := range values {
parsed, err := parseFloat(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
case *[]specid.ID:
for _, value := range values {
parsed, err := parseID(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
case *[]bool:
for _, value := range values {
parsed, err := parseBool(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
case *[]time.Time:
for _, value := range values {
parsed, err := parseTime(value)
if err != nil {
return err
}
*v = append(*v, parsed)
}
}
return err
}