mirror of
https://github.com/navidrome/navidrome.git
synced 2026-04-17 21:19:22 -04:00
* feat(config): make max image upload size configurable Let max image upload size be set from config or environment instead of a fixed 10 MB cap. The upload handler still falls back to 10 MB when MaxImageUploadSize is not set. Signed-off-by: M8te <38794725+m8tec@users.noreply.github.com> * feat(config): support human-readable MaxImageUploadSize values Max image upload size can now be configured as a readable string like 10MB or 1GB instead of raw bytes. The config load validates it at startup, and the upload handler parses it before applying request limits (10MB fallback if it fails). + MaxImageUploadSize as human-readable string + removed redundant max(1, ...) to address code review + cap memory usage of ParseMultipartForm to 10MB (address code review) Signed-off-by: M8te <38794725+m8tec@users.noreply.github.com> * refactor(config): consolidate MaxImageUploadSize default and add tests Move the "10MB" default constant to consts.DefaultMaxImageUploadSize so both the viper default and the runtime fallback share a single source of truth. Improve the validator error message with fmt.Errorf wrapping to match the project convention (e.g. validatePurgeMissingOption). Add unit tests for validateMaxImageUploadSize (valid/invalid inputs) and maxImageUploadSize (configured, empty, invalid, raw bytes). Compute maxImageSize once at handler creation rather than per request. --------- Signed-off-by: M8te <38794725+m8tec@users.noreply.github.com> Co-authored-by: Deluan Quintão <deluan@navidrome.org>
204 lines
6.6 KiB
Go
204 lines
6.6 KiB
Go
package consts
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/navidrome/navidrome/model/id"
|
|
)
|
|
|
|
const (
|
|
AppName = "navidrome"
|
|
|
|
DefaultDbPath = "navidrome.db?cache=shared&_busy_timeout=15000&_journal_mode=WAL&_foreign_keys=on&synchronous=normal"
|
|
InitialSetupFlagKey = "InitialSetup"
|
|
FullScanAfterMigrationFlagKey = "FullScanAfterMigration"
|
|
LastScanErrorKey = "LastScanError"
|
|
LastScanTypeKey = "LastScanType"
|
|
LastScanStartTimeKey = "LastScanStartTime"
|
|
|
|
UIAuthorizationHeader = "X-ND-Authorization"
|
|
UIClientUniqueIDHeader = "X-ND-Client-Unique-Id"
|
|
JWTSecretKey = "JWTSecret"
|
|
JWTIssuer = "ND"
|
|
DefaultSessionTimeout = 48 * time.Hour
|
|
CookieExpiry = 365 * 24 * 3600 // One year
|
|
|
|
OptimizeDBSchedule = "@every 24h"
|
|
|
|
// DefaultEncryptionKey This is the encryption key used if none is specified in the `PasswordEncryptionKey` option
|
|
// Never ever change this! Or it will break all Navidrome installations that don't set the config option
|
|
DefaultEncryptionKey = "just for obfuscation"
|
|
PasswordsEncryptedKey = "PasswordsEncryptedKey"
|
|
PasswordAutogenPrefix = "__NAVIDROME_AUTOGEN__" //nolint:gosec
|
|
|
|
DevInitialUserName = "admin"
|
|
DevInitialName = "Dev Admin"
|
|
|
|
URLPathUI = "/app"
|
|
URLPathNativeAPI = "/api"
|
|
URLPathSubsonicAPI = "/rest"
|
|
URLPathPublic = "/share"
|
|
URLPathPublicImages = URLPathPublic + "/img"
|
|
|
|
// DefaultUILoginBackgroundURL uses Navidrome curated background images collection,
|
|
// available at https://unsplash.com/collections/20072696/navidrome
|
|
DefaultUILoginBackgroundURL = "/backgrounds"
|
|
|
|
// DefaultUILoginBackgroundOffline Background image used in case external integrations are disabled
|
|
DefaultUILoginBackgroundOffline = "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAABGdBTUEAALGPC/xhBQAAAiJJREFUeF7t0IEAAAAAw6D5Ux/khVBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwMDDVlwABBWcSrQAAAABJRU5ErkJggg=="
|
|
DefaultUILoginBackgroundURLOffline = "data:image/png;base64," + DefaultUILoginBackgroundOffline
|
|
DefaultMaxSidebarPlaylists = 100
|
|
|
|
RequestThrottleBacklogLimit = 100
|
|
RequestThrottleBacklogTimeout = time.Minute
|
|
|
|
ServerReadHeaderTimeout = 3 * time.Second
|
|
|
|
DefaultInfoLanguage = "en"
|
|
|
|
ArtistInfoTimeToLive = 24 * time.Hour
|
|
AlbumInfoTimeToLive = 7 * 24 * time.Hour
|
|
UpdateLastAccessFrequency = time.Minute
|
|
UpdatePlayerFrequency = time.Minute
|
|
|
|
I18nFolder = "i18n"
|
|
ScanIgnoreFile = ".ndignore"
|
|
ArtworkFolder = "artwork"
|
|
|
|
PlaceholderArtistArt = "artist-placeholder.webp"
|
|
PlaceholderAlbumArt = "album-placeholder.webp"
|
|
PlaceholderAvatar = "logo-192x192.png"
|
|
DefaultUIVolume = 100
|
|
DefaultUISearchDebounceMs = 200
|
|
|
|
DefaultHttpClientTimeOut = 10 * time.Second
|
|
|
|
DefaultListenBrainzBaseURL = "https://api.listenbrainz.org/1/"
|
|
DefaultListenBrainzArtistAlgorithm = "session_based_days_9000_session_300_contribution_5_threshold_15_limit_50_skip_30"
|
|
DefaultListenBrainzTrackAlgorithm = "session_based_days_9000_session_300_contribution_5_threshold_15_limit_50_skip_30"
|
|
|
|
DefaultScannerExtractor = "taglib"
|
|
DefaultWatcherWait = 5 * time.Second
|
|
Zwsp = string('\u200b')
|
|
)
|
|
|
|
const (
|
|
DefaultUICoverArtSize = 300
|
|
DefaultMaxImageUploadSize = "10MB"
|
|
)
|
|
|
|
// Prometheus options
|
|
const (
|
|
PrometheusDefaultPath = "/metrics"
|
|
PrometheusAuthUser = "navidrome"
|
|
)
|
|
|
|
// Cache options
|
|
const (
|
|
TranscodingCacheDir = "transcoding"
|
|
DefaultTranscodingCacheMaxItems = 0 // Unlimited
|
|
|
|
ImageCacheDir = "images"
|
|
DefaultImageCacheMaxItems = 0 // Unlimited
|
|
|
|
DefaultCacheSize = 100 * 1024 * 1024 // 100MB
|
|
DefaultCacheCleanUpInterval = 10 * time.Minute
|
|
)
|
|
|
|
// Entity types
|
|
const (
|
|
EntityArtist = "artist"
|
|
EntityPlaylist = "playlist"
|
|
EntityRadio = "radio"
|
|
)
|
|
|
|
const (
|
|
AlbumPlayCountModeAbsolute = "absolute"
|
|
AlbumPlayCountModeNormalized = "normalized"
|
|
)
|
|
|
|
const (
|
|
//DefaultAlbumPID = "album_legacy"
|
|
DefaultAlbumPID = "musicbrainz_albumid|albumartistid,album,albumversion,releasedate"
|
|
DefaultTrackPID = "musicbrainz_trackid|albumid,discnumber,tracknumber,title"
|
|
PIDAlbumKey = "PIDAlbum"
|
|
PIDTrackKey = "PIDTrack"
|
|
)
|
|
|
|
const (
|
|
InsightsIDKey = "InsightsID"
|
|
InsightsEndpoint = "https://insights.navidrome.org/collect"
|
|
InsightsUpdateInterval = 24 * time.Hour
|
|
InsightsInitialDelay = 30 * time.Minute
|
|
)
|
|
|
|
const (
|
|
PurgeMissingNever = "never"
|
|
PurgeMissingAlways = "always"
|
|
PurgeMissingFull = "full"
|
|
)
|
|
|
|
var (
|
|
DefaultDownsamplingFormat = "opus"
|
|
DefaultTranscodings = []struct {
|
|
Name string
|
|
TargetFormat string
|
|
DefaultBitRate int
|
|
Command string
|
|
}{
|
|
{
|
|
Name: "mp3 audio",
|
|
TargetFormat: "mp3",
|
|
DefaultBitRate: 192,
|
|
Command: "ffmpeg -i %s -ss %t -map 0:a:0 -b:a %bk -v 0 -f mp3 -",
|
|
},
|
|
{
|
|
Name: "opus audio",
|
|
TargetFormat: "opus",
|
|
DefaultBitRate: 128,
|
|
Command: "ffmpeg -i %s -ss %t -map 0:a:0 -b:a %bk -v 0 -c:a libopus -f opus -",
|
|
},
|
|
{
|
|
Name: "aac audio",
|
|
TargetFormat: "aac",
|
|
DefaultBitRate: 256,
|
|
Command: "ffmpeg -i %s -ss %t -map 0:a:0 -b:a %bk -v 0 -c:a aac -f adts -",
|
|
},
|
|
{
|
|
Name: "flac audio",
|
|
TargetFormat: "flac",
|
|
DefaultBitRate: 0,
|
|
Command: "ffmpeg -i %s -ss %t -map 0:a:0 -v 0 -c:a flac -f flac -",
|
|
},
|
|
}
|
|
)
|
|
|
|
var HTTPUserAgent = "Navidrome" + "/" + Version
|
|
|
|
var (
|
|
VariousArtists = "Various Artists"
|
|
// TODO This will be dynamic when using disambiguation
|
|
VariousArtistsID = "63sqASlAfjbGMuLP4JhnZU"
|
|
UnknownAlbum = "[Unknown Album]"
|
|
UnknownArtist = "[Unknown Artist]"
|
|
// TODO This will be dynamic when using disambiguation
|
|
UnknownArtistID = id.NewHash(strings.ToLower(UnknownArtist))
|
|
VariousArtistsMbzId = "89ad4ac3-39f7-470e-963a-56509c546377"
|
|
|
|
ArtistJoiner = " • "
|
|
)
|
|
|
|
var (
|
|
ServerStart = time.Now()
|
|
|
|
InContainer = func() bool {
|
|
// Check if the /.nddockerenv file exists
|
|
if _, err := os.Stat("/.nddockerenv"); err == nil {
|
|
return true
|
|
}
|
|
return false
|
|
}()
|
|
)
|