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()) }