Add per-disk profiles with video transcoding support
Each disk stores .jukebox/profile.json with copy parameters (dest
folder, overwrite mode, file select, reserve space, auto-copy) and
optional transcoding limits for the target player (codec, resolution,
bitrate, FPS, audio channels, output format).
On copy, video files are probed with ffprobe; if they exceed the
profile limits they are transcoded via ffmpeg (-threads 0 for full
CPU usage), otherwise copied as-is. Scale filter never upscales.
New: internal/disk/profile.go, internal/transcoder/{detect,transcoder}.go
API: GET/PUT /api/disks/profile?mount_path=
UI: disk profile panel in dashboard for known disks
Dockerfile: adds ffmpeg to the runtime image
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,17 +13,25 @@ import (
|
||||
)
|
||||
|
||||
func (s *Server) copyOptions(cfg *config.Config, diskInfo disk.DiskInfo, overwriteMode config.OverwriteMode) copier.Options {
|
||||
return copier.Options{
|
||||
opts := copier.Options{
|
||||
DiskID: diskInfo.DiskID,
|
||||
MountPath: diskInfo.MountPath,
|
||||
MediaPath: cfg.MediaPath,
|
||||
DestFolder: cfg.DestFolder,
|
||||
SourceRules: cfg.Sources,
|
||||
AllowedExtensions: cfg.EffectiveAllowedExtensions(),
|
||||
ReserveFreeGB: cfg.ReserveFreeGB,
|
||||
OverwriteMode: overwriteMode,
|
||||
FileSelectMode: cfg.FileSelectMode,
|
||||
}
|
||||
if p := diskInfo.Profile; p != nil {
|
||||
opts.DestFolder = p.DestFolder
|
||||
opts.ReserveFreeGB = p.ReserveFreeGB
|
||||
opts.FileSelectMode = config.FileSelectMode(p.FileSelectMode)
|
||||
opts.Transcode = p.Transcode
|
||||
} else {
|
||||
opts.DestFolder = cfg.DestFolder
|
||||
opts.ReserveFreeGB = cfg.ReserveFreeGB
|
||||
opts.FileSelectMode = cfg.FileSelectMode
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
func hasEnabledSources(cfg *config.Config) bool {
|
||||
@@ -78,8 +86,11 @@ func (s *Server) handleCopyStart(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
reserveBytes := int64(cfg.ReserveFreeGB * 1e9)
|
||||
if diskInfo.FreeBytes <= reserveBytes {
|
||||
reserveGB := cfg.ReserveFreeGB
|
||||
if diskInfo.Profile != nil {
|
||||
reserveGB = diskInfo.Profile.ReserveFreeGB
|
||||
}
|
||||
if diskInfo.FreeBytes <= int64(reserveGB*1e9) {
|
||||
jsonErr(w, http.StatusUnprocessableEntity, "free space is below reserve threshold")
|
||||
return
|
||||
}
|
||||
@@ -137,8 +148,11 @@ func (s *Server) handleCopyStartSelected(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
reserveBytes := int64(cfg.ReserveFreeGB * 1e9)
|
||||
if diskInfo.FreeBytes <= reserveBytes {
|
||||
reserveGB := cfg.ReserveFreeGB
|
||||
if diskInfo.Profile != nil {
|
||||
reserveGB = diskInfo.Profile.ReserveFreeGB
|
||||
}
|
||||
if diskInfo.FreeBytes <= int64(reserveGB*1e9) {
|
||||
jsonErr(w, http.StatusUnprocessableEntity, "free space is below reserve threshold")
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user