🏡 index : quine-global/quintodrome.git

package subsonic

import (
	"cmp"
	"net/http"
	"strings"
	"time"

	"github.com/navidrome/navidrome/conf"
	"github.com/navidrome/navidrome/model"
	"github.com/navidrome/navidrome/server/public"
	"github.com/navidrome/navidrome/server/subsonic/responses"
	"github.com/navidrome/navidrome/utils/req"
	"github.com/navidrome/navidrome/utils/slice"
)

func (api *Router) GetShares(r *http.Request) (*responses.Subsonic, error) {
	repo := api.share.Repository()
	shares, err := repo.GetAll(r.Context(), model.QueryOptions{Sort: "created_at desc"})
	if err != nil {
		return nil, err
	}

	response := newResponse()
	response.Shares = &responses.Shares{}
	for _, share := range shares {
		response.Shares.Share = append(response.Shares.Share, api.buildShare(r, share))
	}
	return response, nil
}

func (api *Router) buildShare(r *http.Request, share model.Share) responses.Share {
	resp := responses.Share{
		ID:          share.ID,
		Url:         public.ShareURL(r.Context(), share.ID),
		Description: share.Description,
		Username:    share.Username,
		Created:     share.CreatedAt,
		Expires:     share.ExpiresAt,
		LastVisited: share.LastVisitedAt,
		VisitCount:  int32(share.VisitCount),
	}
	if resp.Description == "" {
		resp.Description = share.Contents
	}
	if len(share.Albums) > 0 {
		resp.Entry = slice.MapWithArg(share.Albums, r.Context(), childFromAlbum)
	} else {
		resp.Entry = slice.MapWithArg(share.Tracks, r.Context(), childFromMediaFile)
	}
	return resp
}

func (api *Router) CreateShare(r *http.Request) (*responses.Subsonic, error) {
	p := req.Params(r)
	ids := p.Strings("id")
	if len(ids) == 0 {
		return nil, newError(responses.ErrorMissingParameter, "missing parameter: 'id'")
	}

	description, _ := p.String("description")
	repo := api.share.Repository()
	share := &model.Share{
		Description:  description,
		Downloadable: p.BoolOr("downloadable", conf.Server.DefaultDownloadableShare && conf.Server.EnableDownloads),
		ExpiresAt:    new(p.TimeOr("expires", time.Time{})),
		ResourceIDs:  strings.Join(ids, ","),
	}

	id, err := repo.Save(r.Context(), share)
	if err != nil {
		return nil, err
	}

	share, err = repo.Get(r.Context(), id)
	if err != nil {
		return nil, err
	}

	response := newResponse()
	response.Shares = &responses.Shares{Share: []responses.Share{api.buildShare(r, *share)}}
	return response, nil
}

func (api *Router) UpdateShare(r *http.Request) (*responses.Subsonic, error) {
	p := req.Params(r)
	id, err := p.String("id")
	if err != nil {
		return nil, err
	}

	repo := api.share.Repository()

	// The update always writes description and downloadable, so read back the
	// stored value for whichever one the client omitted.
	description := p.StringPtr("description")
	downloadable := p.BoolPtr("downloadable")
	if description == nil || downloadable == nil {
		cur, err := repo.Read(r.Context(), id)
		if err != nil {
			return nil, err
		}
		description = cmp.Or(description, &cur.Description)
		downloadable = cmp.Or(downloadable, &cur.Downloadable)
	}

	share := &model.Share{
		ID:           id,
		Description:  *description,
		Downloadable: *downloadable,
		ExpiresAt:    new(p.TimeOr("expires", time.Time{})),
	}

	err = repo.Update(r.Context(), id, *share)
	if err != nil {
		return nil, err
	}

	return newResponse(), nil
}

func (api *Router) DeleteShare(r *http.Request) (*responses.Subsonic, error) {
	p := req.Params(r)
	id, err := p.String("id")
	if err != nil {
		return nil, err
	}

	repo := api.share.Repository()
	err = repo.Delete(r.Context(), id)
	if err != nil {
		return nil, err
	}

	return newResponse(), nil
}