feat: auto-configure FileBrowser sidebar with per-drive sources

Generate config.yaml with a separate source per registered storage path.
Each source uses the drive's label as its display name, making it appear
automatically in FileBrowser's sidebar. The config.yaml is bind-mounted
into the container (read-only) alongside the data volume.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-18 21:53:30 +01:00
parent 30110d3fca
commit b88c9c76e6
+76 -10
View File
@@ -1260,10 +1260,11 @@ func (s *Server) settingsStorageLabelHandler(w http.ResponseWriter, r *http.Requ
http.Redirect(w, r, "/settings?storage_msg=success&storage_detail="+url.QueryEscape("Megnevezés módosítva: "+label), http.StatusFound)
}
// syncFileBrowserMounts regenerates FileBrowser's docker-compose.yml
// with volume mounts for all registered storage paths, then recreates the container.
// syncFileBrowserMounts regenerates FileBrowser's docker-compose.yml and config.yaml
// with volume mounts and sources for all registered storage paths, then recreates the container.
func (s *Server) syncFileBrowserMounts() {
composePath := "/opt/docker/stacks/filebrowser/docker-compose.yml"
stackDir := "/opt/docker/stacks/filebrowser"
composePath := stackDir + "/docker-compose.yml"
// Check if FileBrowser stack exists
if _, err := os.Stat(composePath); os.IsNotExist(err) {
@@ -1275,7 +1276,7 @@ func (s *Server) syncFileBrowserMounts() {
paths := s.settings.GetStoragePaths()
// Read domain from .env
envPath := "/opt/docker/stacks/filebrowser/.env"
envPath := stackDir + "/.env"
domain := ""
if data, err := os.ReadFile(envPath); err == nil {
for _, line := range strings.Split(string(data), "\n") {
@@ -1298,10 +1299,16 @@ func (s *Server) syncFileBrowserMounts() {
storageMounts = append(storageMounts, line)
}
// Generate compose from template
compose := generateFileBrowserCompose(domain, storageMounts)
// Generate and write config.yaml (sources + sidebar entries per drive)
configPath := stackDir + "/config.yaml"
fbConfig := generateFileBrowserConfig(paths)
if err := os.WriteFile(configPath, []byte(fbConfig), 0644); err != nil {
s.logger.Printf("[ERROR] Failed to write FileBrowser config: %v", err)
return
}
// Write compose
// Generate and write compose (includes config.yaml mount)
compose := generateFileBrowserCompose(domain, storageMounts)
if err := os.WriteFile(composePath, []byte(compose), 0644); err != nil {
s.logger.Printf("[ERROR] Failed to write FileBrowser compose: %v", err)
return
@@ -1311,11 +1318,11 @@ func (s *Server) syncFileBrowserMounts() {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "docker", "compose", "up", "-d", "--remove-orphans")
cmd.Dir = filepath.Dir(composePath)
cmd.Dir = stackDir
if out, err := cmd.CombinedOutput(); err != nil {
s.logger.Printf("[ERROR] Failed to recreate FileBrowser: %s — %v", string(out), err)
} else {
s.logger.Printf("[INFO] FileBrowser mounts synced — %d storage path(s)", len(paths))
s.logger.Printf("[INFO] FileBrowser mounts synced — %d storage path(s), config updated", len(paths))
}
}
@@ -1341,7 +1348,8 @@ services:
environment:
- TZ=Europe/Budapest
volumes:
- filebrowser_data:/home/filebrowser/data%s
- filebrowser_data:/home/filebrowser/data
- ./config.yaml:/home/filebrowser/data/config.yaml:ro%s
networks:
- traefik-public
deploy:
@@ -1370,3 +1378,61 @@ networks:
external: true
`, domain, storageSection, domain)
}
// generateFileBrowserConfig returns a FileBrowser Quantum config.yaml with
// a separate source per registered storage path. Each source appears as a
// named sidebar entry in the FileBrowser UI.
func generateFileBrowserConfig(paths []settings.StoragePath) string {
var sources string
if len(paths) == 0 {
sources = ` - path: "/srv"
`
} else {
for _, sp := range paths {
mountName := filepath.Base(sp.Path)
label := sp.Label
if label == "" {
label = mountName
}
sources += fmt.Sprintf(" - path: \"/srv/%s\"\n name: %q\n config:\n defaultEnabled: true\n", mountName, label)
}
}
return fmt.Sprintf(`# FileBrowser Quantum — managed by felhom-controller
# WARNING: This file is auto-generated. Manual edits will be overwritten.
server:
port: 80
baseURL: "/"
logging:
- levels: "info|warning|error"
sources:
%suserDefaults:
stickySidebar: true
darkMode: true
viewMode: "normal"
showHidden: false
dateFormat: false
gallerySize: 3
themeColor: "var(--blue)"
preview:
disableHideSidebar: false
highQuality: true
image: true
video: true
motionVideoPreview: true
office: true
popup: true
autoplayMedia: true
folder: true
permissions:
api: false
admin: false
modify: false
share: false
realtime: false
delete: false
create: false
download: true
`, sources)
}