88 lines
2.6 KiB
Go
88 lines
2.6 KiB
Go
|
|
package config
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"os"
|
||
|
|
"strconv"
|
||
|
|
)
|
||
|
|
|
||
|
|
// v1.0.6: single source of truth for upload-size limits. Previously the same
|
||
|
|
// values were duplicated in track/service.go, handlers/upload.go,
|
||
|
|
// handlers/education_handler.go, apps/web/.../upload-modal/constants.ts, and
|
||
|
|
// apps/web/.../CloudUploadModal.tsx — a drift waiting to happen. The frontend
|
||
|
|
// now consumes these via GET /api/v1/upload/limits and the backend reads them
|
||
|
|
// from env with sane defaults.
|
||
|
|
|
||
|
|
const (
|
||
|
|
// DefaultAudioMaxMB is the default upper bound for uploaded audio tracks.
|
||
|
|
DefaultAudioMaxMB = 100
|
||
|
|
// DefaultImageMaxMB is the default upper bound for cover art / avatars.
|
||
|
|
DefaultImageMaxMB = 10
|
||
|
|
// DefaultVideoMaxMB is the default upper bound for education videos.
|
||
|
|
DefaultVideoMaxMB = 500
|
||
|
|
)
|
||
|
|
|
||
|
|
// UploadLimitMB represents a single category's limit and its environment
|
||
|
|
// variable override. The bytes form is the authoritative value used for
|
||
|
|
// validation; the human form is what we send back to the UI.
|
||
|
|
type UploadLimitMB struct {
|
||
|
|
Category string
|
||
|
|
EnvVar string
|
||
|
|
DefaultMB int
|
||
|
|
AllowedMIMEs []string
|
||
|
|
}
|
||
|
|
|
||
|
|
// AudioLimit, ImageLimit, VideoLimit expose the category definitions used by
|
||
|
|
// both the upload handler and the track service. Values are resolved lazily
|
||
|
|
// from the environment (no global state) so config changes take effect on
|
||
|
|
// the next request without a rebuild.
|
||
|
|
var (
|
||
|
|
AudioLimit = UploadLimitMB{
|
||
|
|
Category: "audio",
|
||
|
|
EnvVar: "MAX_UPLOAD_AUDIO_MB",
|
||
|
|
DefaultMB: DefaultAudioMaxMB,
|
||
|
|
AllowedMIMEs: []string{
|
||
|
|
"audio/mpeg",
|
||
|
|
"audio/mp3",
|
||
|
|
"audio/wav",
|
||
|
|
"audio/flac",
|
||
|
|
"audio/aac",
|
||
|
|
"audio/ogg",
|
||
|
|
"audio/m4a",
|
||
|
|
},
|
||
|
|
}
|
||
|
|
ImageLimit = UploadLimitMB{
|
||
|
|
Category: "image",
|
||
|
|
EnvVar: "MAX_UPLOAD_IMAGE_MB",
|
||
|
|
DefaultMB: DefaultImageMaxMB,
|
||
|
|
AllowedMIMEs: []string{"image/jpeg", "image/png", "image/gif", "image/webp"},
|
||
|
|
}
|
||
|
|
VideoLimit = UploadLimitMB{
|
||
|
|
Category: "video",
|
||
|
|
EnvVar: "MAX_UPLOAD_VIDEO_MB",
|
||
|
|
DefaultMB: DefaultVideoMaxMB,
|
||
|
|
AllowedMIMEs: []string{"video/mp4", "video/webm", "video/ogg", "video/avi"},
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
// Bytes returns the category's current byte limit, honoring the env override.
|
||
|
|
// Invalid or negative env values fall back to the compile-time default.
|
||
|
|
func (l UploadLimitMB) Bytes() int64 {
|
||
|
|
return int64(l.MB()) * 1024 * 1024
|
||
|
|
}
|
||
|
|
|
||
|
|
// MB returns the category's current megabyte limit, honoring the env override.
|
||
|
|
func (l UploadLimitMB) MB() int {
|
||
|
|
if raw := os.Getenv(l.EnvVar); raw != "" {
|
||
|
|
if v, err := strconv.Atoi(raw); err == nil && v > 0 {
|
||
|
|
return v
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return l.DefaultMB
|
||
|
|
}
|
||
|
|
|
||
|
|
// HumanReadable renders the limit in "%dMB" form for UI consumption.
|
||
|
|
func (l UploadLimitMB) HumanReadable() string {
|
||
|
|
return fmt.Sprintf("%dMB", l.MB())
|
||
|
|
}
|