From 1311fb3b62b08747f6f3ef6ba2900fae5de0b20a Mon Sep 17 00:00:00 2001 From: LumePart Date: Sun, 19 Jul 2026 15:41:48 +0300 Subject: [PATCH 1/8] env prefix uses ID when saving custom schedule; fix settings --- src/web/backend/playlist/handlers.go | 56 -------------------- src/web/backend/playlist/playlist.go | 4 +- src/web/backend/settings/handlers.go | 14 ++--- src/web/frontend/src/components/Settings.jsx | 10 ++-- src/web/frontend/src/lib/api.js | 4 +- 5 files changed, 18 insertions(+), 70 deletions(-) diff --git a/src/web/backend/playlist/handlers.go b/src/web/backend/playlist/handlers.go index b1af52e..49ff8fa 100644 --- a/src/web/backend/playlist/handlers.go +++ b/src/web/backend/playlist/handlers.go @@ -318,62 +318,6 @@ func (p *Playlist) HandleDeleteCustomPlaylist(w http.ResponseWriter, r *http.Req w.WriteHeader(http.StatusNoContent) } -// handleSaveSchedule updates a single playlist's schedule in the .env file. -func (p *Playlist) HandleSaveSchedule(w http.ResponseWriter, r *http.Request) { - var body struct { - Name string `json:"name"` - Enabled bool `json:"enabled"` - Day int `json:"day"` // 0=Sun…6=Sat, -1=every day - Hour int `json:"hour"` - Minute int `json:"minute"` - } - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - http.Error(w, "invalid JSON: "+err.Error(), http.StatusBadRequest) - return - } - - var envPrefix string - var defaultFlags string - - if def, ok := defs.PlaylistDefs[body.Name]; ok { - envPrefix = def.EnvPrefix - defaultFlags = def.DefaultFlags - } else if defs.CustomIDRe.MatchString(body.Name) { - envPrefix = util.CustomEnvPrefix(body.Name) - defaultFlags = "--playlist " + body.Name - } else { - http.Error(w, "unknown playlist name", http.StatusBadRequest) - return - } - - updates := map[string]string{} - if !body.Enabled { - // Toggle off — truly disable, regardless of day value carried over from state - updates[envPrefix+"_SCHEDULE"] = "" - updates[envPrefix+"_FLAGS"] = "" - } else if body.Day == -2 { - // "Never" — keep playlist active for manual runs but remove auto-schedule - updates[envPrefix+"_SCHEDULE"] = "" - updates[envPrefix+"_FLAGS"] = defaultFlags - } else { - dom := "*" - dow := "*" - if body.Day == 100 { - dom = "1" - } else if body.Day >= 0 { - dow = fmt.Sprintf("%d", body.Day) - } - updates[envPrefix+"_SCHEDULE"] = fmt.Sprintf("%d %d %s * %s", body.Minute, body.Hour, dom, dow) - updates[envPrefix+"_FLAGS"] = defaultFlags - } - - if err := p.settings.UpdateEnvKeys(updates, web.SampleEnv); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusOK) -} - // handleGetPlaylist serves the tracklist cache written by explo during its last run. // Returns an empty track list if no cache exists yet. func (p *Playlist) HandleGetPlaylist(w http.ResponseWriter, r *http.Request) { diff --git a/src/web/backend/playlist/playlist.go b/src/web/backend/playlist/playlist.go index 1847f9d..88b2618 100644 --- a/src/web/backend/playlist/playlist.go +++ b/src/web/backend/playlist/playlist.go @@ -50,7 +50,9 @@ var validPlaylistTypes = func() map[string]bool { }() func NewPlaylist(cfg app.Config, settings *settings.Settings) *Playlist { - return &Playlist{cfg: cfg} + return &Playlist{ + cfg: cfg, + settings: settings} } // isValidPlaylistID accepts built-in playlist types and custom-* IDs (blocks path traversal). diff --git a/src/web/backend/settings/handlers.go b/src/web/backend/settings/handlers.go index f7c3627..c040077 100644 --- a/src/web/backend/settings/handlers.go +++ b/src/web/backend/settings/handlers.go @@ -94,6 +94,7 @@ func (s *Settings) HandleResetConfig(w http.ResponseWriter, r *http.Request) { // handleSaveSchedule updates a single playlist's schedule in the .env file. func (s *Settings) HandleSaveSchedule(w http.ResponseWriter, r *http.Request) { var body struct { + ID string `json:"id"` Name string `json:"name"` Enabled bool `json:"enabled"` Day int `json:"day"` // 0=Sun…6=Sat, -1=every day @@ -108,12 +109,12 @@ func (s *Settings) HandleSaveSchedule(w http.ResponseWriter, r *http.Request) { var envPrefix string var defaultFlags string - if def, ok := defs.PlaylistDefs[body.Name]; ok { + if def, ok := defs.PlaylistDefs[body.ID]; ok { envPrefix = def.EnvPrefix defaultFlags = def.DefaultFlags - } else if defs.CustomIDRe.MatchString(body.Name) { + } else if defs.CustomIDRe.MatchString(body.ID) { envPrefix = util.CustomEnvPrefix(body.Name) - defaultFlags = "--playlist " + body.Name + defaultFlags = "--playlist " + body.ID } else { http.Error(w, "unknown playlist name", http.StatusBadRequest) return @@ -211,6 +212,7 @@ func (s *Settings) HandleSaveEnrichMetadata(w http.ResponseWriter, r *http.Reque // HandleSaveReplacePlaylist injects or removes --replace-playlist=false from a playlist's FLAGS env var. func (s *Settings) HandleSaveReplacePlaylist(w http.ResponseWriter, r *http.Request) { var body struct { + ID string `json:"id"` Name string `json:"name"` Replace bool `json:"replace"` } @@ -221,12 +223,12 @@ func (s *Settings) HandleSaveReplacePlaylist(w http.ResponseWriter, r *http.Requ var envPrefix string var defaultFlags string - if def, ok := defs.PlaylistDefs[body.Name]; ok { + if def, ok := defs.PlaylistDefs[body.ID]; ok { envPrefix = def.EnvPrefix defaultFlags = def.DefaultFlags - } else if defs.CustomIDRe.MatchString(body.Name) { + } else if defs.CustomIDRe.MatchString(body.ID) { envPrefix = util.CustomEnvPrefix(body.Name) - defaultFlags = "--playlist " + body.Name + defaultFlags = "--playlist " + body.ID } else { http.Error(w, "unknown playlist name", http.StatusBadRequest) return diff --git a/src/web/frontend/src/components/Settings.jsx b/src/web/frontend/src/components/Settings.jsx index 35b1181..e65fffc 100644 --- a/src/web/frontend/src/components/Settings.jsx +++ b/src/web/frontend/src/components/Settings.jsx @@ -243,10 +243,10 @@ function HomeSection() { } for (const cp of customList) { s[cp.id] = cp.schedule - ? { enabled: true, editing: false, ...cronToFields(cp.schedule) } + ? { name: cp.name, enabled: true, editing: false, ...cronToFields(cp.schedule) } : cp.flags - ? { enabled: true, editing: false, day: -2, hour: 4, minute: 0 } - : { enabled: false, day: -1, hour: 4, minute: 0, editing: false } + ? { name: cp.name, enabled: true, editing: false, day: -2, hour: 4, minute: 0 } + : { name: cp.name, enabled: false, day: -1, hour: 4, minute: 0, editing: false } } setSchedules(s) }) @@ -300,7 +300,7 @@ function HomeSection() { scheduleSaveStatus: scheduleSaveStatus[id] || '', onToggle: v => { setSchedules(prev => ({ ...prev, [id]: { ...prev[id], enabled: v } })) - saveSchedule(id, v, s.day, s.hour, s.minute) + saveSchedule(id, s.name, v, s.day, s.hour, s.minute) .then(() => flashStatus(id, 'Saved.')) .catch(() => flashStatus(id, 'Error saving.')) }, @@ -308,7 +308,7 @@ function HomeSection() { ...prev, [id]: { ...prev[id], editing: !prev[id].editing } })), onSave: () => { - saveSchedule(id, s.enabled, s.day, s.hour, s.minute) + saveSchedule(id, s.name, s.enabled, s.day, s.hour, s.minute) .then(() => flashStatus(id, 'Saved.')) .catch(() => flashStatus(id, 'Error saving.')) setSchedules(prev => ({ ...prev, [id]: { ...prev[id], editing: false } })) diff --git a/src/web/frontend/src/lib/api.js b/src/web/frontend/src/lib/api.js index 7a81134..cc3455a 100644 --- a/src/web/frontend/src/lib/api.js +++ b/src/web/frontend/src/lib/api.js @@ -73,11 +73,11 @@ export async function resetConfig() { if (!res.ok) throw new Error(await res.text()) } -export async function saveSchedule(name, enabled, day, hour, minute) { +export async function saveSchedule(id, name, enabled, day, hour, minute) { const res = await apiFetch('/api/ui/config/schedules', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name, enabled, day, hour, minute }), + body: JSON.stringify({ id, name, enabled, day, hour, minute }), }) if (!res.ok) throw new Error(await res.text()) } From 45c11d90a5fe3bb6524b6a192839eb4b9fd2d914 Mon Sep 17 00:00:00 2001 From: LumePart Date: Sun, 19 Jul 2026 16:00:04 +0300 Subject: [PATCH 2/8] hide copyURL button when using http --- src/web/frontend/src/components/ui/PlaylistCard.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/frontend/src/components/ui/PlaylistCard.jsx b/src/web/frontend/src/components/ui/PlaylistCard.jsx index 35e2e63..a340117 100644 --- a/src/web/frontend/src/components/ui/PlaylistCard.jsx +++ b/src/web/frontend/src/components/ui/PlaylistCard.jsx @@ -639,7 +639,7 @@ export function PlaylistCard({ boxShadow: '0 8px 24px #00000088', }} > - {sourceUrl && ( + {sourceUrl && window.isSecureContext && (