From a634fa43b9d1524531febb762fbfca0ff320247a Mon Sep 17 00:00:00 2001 From: LumePart Date: Sun, 14 Jun 2026 12:57:30 +0300 Subject: [PATCH 1/5] don't quote variables with spaces --- src/web/backend/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/backend/server.go b/src/web/backend/server.go index ffa1403..7043f72 100644 --- a/src/web/backend/server.go +++ b/src/web/backend/server.go @@ -689,7 +689,7 @@ func formatEnvValue(v string) string { return v } - if strings.ContainsAny(v, `"$#?' `) { + if strings.ContainsAny(v, `"$#?'`) { // escape single quotes inside value v = strings.ReplaceAll(v, `'`, `'\''`) return fmt.Sprintf(`'%s'`, v) From 38876c5a4ce959a94bc655d93903240a38701bdf Mon Sep 17 00:00:00 2001 From: LumePart Date: Sun, 14 Jun 2026 12:59:05 +0300 Subject: [PATCH 2/5] clear cronjobs before initializing --- docker/start.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker/start.sh b/docker/start.sh index b11dddc..6910c8a 100644 --- a/docker/start.sh +++ b/docker/start.sh @@ -11,6 +11,9 @@ echo "[setup] Web UI available at http://localhost:${WEB_ADDR##*:}" echo "[setup] Initializing cron jobs..." +# Start with a clean crontab +: > /etc/crontabs/root + # Load *_SCHEDULE and *_FLAGS from .env if not already set in the environment. # This allows the web UI to configure schedules by writing to the .env file. _cfg="${WEB_ENV_PATH:-/opt/explo/.env}" From dd9ff1b72ebd903add7d6ed38d245e0316bb751d Mon Sep 17 00:00:00 2001 From: LumePart Date: Sun, 14 Jun 2026 14:20:55 +0300 Subject: [PATCH 3/5] print out log instead of returning error --- src/downloader/monitor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/downloader/monitor.go b/src/downloader/monitor.go index beb87a8..79d10de 100644 --- a/src/downloader/monitor.go +++ b/src/downloader/monitor.go @@ -89,7 +89,7 @@ func (c *DownloadClient) MonitorDownloads(tracks []*models.Track, m Monitor) err track.File, path = parsePath(track.File) if monCfg.MigrateDownload { if err = c.MoveDownload(monCfg.FromDir, monCfg.ToDir, path, track); err != nil { - return fmt.Errorf("error while moving file: %w", err) + slog.Error("error while moving file", "err", err.Error()) } else { slog.Info("track moved successfully", "service", monCfg.Service) } From 2a7013ea808f3a02c8c2583d01778c87f72fdc7a Mon Sep 17 00:00:00 2001 From: LumePart Date: Sun, 14 Jun 2026 14:56:32 +0300 Subject: [PATCH 4/5] don't start webserver if playlist flag is set --- src/config/config.go | 1 + src/config/flags.go | 2 ++ src/main/main.go | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/config/config.go b/src/config/config.go index a68b6ce..9d1cdce 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -34,6 +34,7 @@ type Flags struct { CfgPath string CfgSet bool Playlist string + PlaylistSet bool DownloadMode string ExcludeLocal bool Persist bool diff --git a/src/config/flags.go b/src/config/flags.go index 7059331..81e8188 100644 --- a/src/config/flags.go +++ b/src/config/flags.go @@ -42,6 +42,7 @@ func (cfg *Config) GetFlags() error { } persistSet := flag.Lookup("persist").Changed cfgSet := flag.Lookup("config").Changed + playlistSet := flag.Lookup("playlist").Changed @@ -59,6 +60,7 @@ func (cfg *Config) GetFlags() error { cfg.Flags.CfgPath = configPath cfg.Flags.CfgSet = cfgSet cfg.Flags.Playlist = playlist + cfg.Flags.PlaylistSet = playlistSet cfg.Flags.DownloadMode = downloadMode cfg.Flags.ExcludeLocal = excludeLocal cfg.Flags.Persist = persist diff --git a/src/main/main.go b/src/main/main.go index 32ad062..e34f64b 100644 --- a/src/main/main.go +++ b/src/main/main.go @@ -138,13 +138,22 @@ func main() { return } + if cfg.Flags.RefreshOnly { + if err := client.TriggerRefresh(&cfg); err != nil { + slog.Error("refresh-only failed", "err", err.Error()) + os.Exit(1) + } + slog.Info("library refresh triggered") + return + } + slog.Info("Starting Explo...") if err := os.MkdirAll(cfg.DownloadCfg.Youtube.CoversDir, 0755); err != nil { slog.Error("failed making directory", "msg", err.Error()) } - if cfg.ServerCfg.Enabled { + if cfg.ServerCfg.Enabled || !cfg.Flags.PlaylistSet { exploPath, err := os.Executable() if err != nil { @@ -156,15 +165,6 @@ func main() { log.Fatal(srv.Start()) } - if cfg.Flags.RefreshOnly { - if err := client.TriggerRefresh(&cfg); err != nil { - slog.Error("refresh-only failed", "err", err.Error()) - os.Exit(1) - } - slog.Info("library refresh triggered") - return - } - var tracks []*models.Track var err error if strings.HasPrefix(cfg.Flags.Playlist, "custom-") { From 18f74de5d3f1bb673d11d1d96021371b0444a146 Mon Sep 17 00:00:00 2001 From: LumePart Date: Sun, 14 Jun 2026 17:29:16 +0300 Subject: [PATCH 5/5] handle The prefix when generating artist wildcard --- src/downloader/slskd.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/downloader/slskd.go b/src/downloader/slskd.go index 15ec5a4..c6ff741 100644 --- a/src/downloader/slskd.go +++ b/src/downloader/slskd.go @@ -445,6 +445,11 @@ func parsePath(p string) (string, string) { // parse filepath to downloaded form } func wildcardArtist(artist string) string { + prefix := "" + if len(artist) >= 4 && strings.EqualFold(artist[:4], "the ") { + prefix = artist[:4] + artist = strings.TrimSpace(artist[4:]) +} r := []rune(strings.TrimSpace(artist)) if len(r) < 3 { @@ -452,7 +457,7 @@ func wildcardArtist(artist string) string { } r[0] = '*' - return string(r) + return prefix + string(r) } // different failure states slskd has (format is "Completed,Rejected", "Errored,Cancelled" etc..)