Media build part 2 (unreleased): drive wiring in every app (R-1024/R-1037), old-install repair (R-1047), drive events notice + real restart now/later + stream check, file browser lets go of dead/removed drives and recreates on return (R-1038), safe removal keeps the drive (R-1044), Plex claim on the running server + probe accept (R-1028/R-1045)
gates / gates (push) Successful in 45s

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
admin committed 2026-10-15 09:54:49 +02:00
1 parent 78c894234c
commit f580d88a14
46 files changed
+3700 -8

No files matched your search

+12
View File
@@ -333,6 +333,8 @@ type Manager struct {
isMountPoint func(string) bool
// mediaDrivesFn replaces the enrolled-drive read of media_library.go (tests); nil in production.
mediaDrivesFn func() []MediaDrive
// onMediaUp runs after a media app's successful `compose up` (the drive wiring, R-1024); nil = nothing.
onMediaUp func(name string)
// mediaEnsureDirFn replaces appbackup.EnsureUserdataDir for the per-drive media folder (tests); nil in production.
mediaEnsureDirFn func(string) error
@@ -1685,9 +1687,19 @@ func (m *Manager) composeExecCustomEnv(dir string, env []string, args ...string)
}
m.logger.Printf("[DEBUG] Command completed: %s %s (took %.1fs)", m.composeCmd, strings.Join(args, " "), time.Since(start).Seconds())
// R-1024: a media app that came up (installed, started, restarted) gets the drives wired in (idempotent; the web
// side debounces). Never for a stack without the marker.
if len(args) > 0 && args[0] == "up" && m.onMediaUp != nil {
if meta := LoadMetadata(dir); meta.MediaLibrary != nil {
m.onMediaUp(filepath.Base(dir))
}
}
return stdout.String(), nil
}
// SetOnMediaUp registers the callback run after a media app's successful `compose up` (main.go: the wiring).
func (m *Manager) SetOnMediaUp(f func(name string)) { m.onMediaUp = f }
func (m *Manager) execCommand(name string, args ...string) (string, error) {
// execFn is the process-boundary seam (nil in production). It exists so R-51 can be proven
// through the REAL refreshStatusLocked path — docker ps → aggregateState → docker inspect —