🏡 index : quine-global/quintodrome.git

package publicurl

import (
	"cmp"
	"context"
	"net/url"
	"path"
	"strconv"
	"strings"

	"github.com/navidrome/navidrome/conf"
	"github.com/navidrome/navidrome/consts"
	"github.com/navidrome/navidrome/core/auth"
	"github.com/navidrome/navidrome/log"
	"github.com/navidrome/navidrome/model"
	"github.com/navidrome/navidrome/model/request"
	"github.com/navidrome/navidrome/utils/gg"
)

// ImageURL generates a public URL for artwork images.
// It creates a signed token for the artwork ID and builds a complete public URL.
func ImageURL(ctx context.Context, artID model.ArtworkID, size int) string {
	token, _ := auth.CreatePublicToken(auth.Claims{ID: artID.String()})
	uri := path.Join(consts.URLPathPublicImages, token)
	params := url.Values{}
	if size > 0 {
		params.Add("size", strconv.Itoa(size))
	}
	return PublicURL(ctx, uri, params)
}

// PublicURL builds a full URL for public-facing resources.
// It uses ShareURL from config if available, otherwise falls back to the address the
// client used to reach the server, recorded in the context.
func PublicURL(ctx context.Context, u string, params url.Values) string {
	if conf.Server.ShareURL == "" {
		return AbsoluteURL(ctx, u, params)
	}
	shareUrl, err := url.Parse(conf.Server.ShareURL)
	if err != nil {
		return AbsoluteURL(ctx, u, params)
	}
	buildUrl, err := url.Parse(u)
	if err != nil {
		return AbsoluteURL(ctx, u, params)
	}
	buildUrl.Scheme = shareUrl.Scheme
	buildUrl.Host = shareUrl.Host
	if basePath := strings.TrimRight(shareUrl.Path, "/"); basePath != "" {
		buildUrl.Path = path.Join(basePath, buildUrl.Path)
	}
	if len(params) > 0 {
		buildUrl.RawQuery = params.Encode()
	}
	return buildUrl.String()
}

// AbsoluteURL builds an absolute URL from a relative path.
// It uses BaseHost/BaseScheme from config if available, otherwise the address the client
// used to reach the server, recorded in the context by the server's address middleware.
func AbsoluteURL(ctx context.Context, u string, params url.Values) string {
	buildUrl, err := url.Parse(u)
	if err != nil {
		log.Error(ctx, "Failed to parse URL path", "url", u, err)
		return ""
	}
	if strings.HasPrefix(u, "/") {
		buildUrl.Path = path.Join(conf.Server.BasePath, buildUrl.Path)
		if conf.Server.BaseHost != "" {
			buildUrl.Scheme = cmp.Or(conf.Server.BaseScheme, "http")
			buildUrl.Host = conf.Server.BaseHost
		} else if scheme, host, ok := request.ServerAddressFrom(ctx); ok {
			buildUrl.Scheme = scheme
			buildUrl.Host = host
		} else {
			log.Debug(ctx, "Building a public URL with no public address available; set ShareURL to make it reachable", "url", u)
			buildUrl.Scheme = gg.If(conf.Server.TLSEnabled(), "https", "http")
			buildUrl.Host = "localhost:" + strconv.Itoa(conf.Server.Port)
		}
	}
	if len(params) > 0 {
		buildUrl.RawQuery = params.Encode()
	}
	return buildUrl.String()
}