Notifications, and automatic cleanup of empty folders
Settings → Notifications sends a message to Discord, Pushover, ntfy, Gotify or a JSON webhook when a scan finds songs that newly need review, when auto-link replaced identical files, and when an automatic cleanup ran. Each event can be turned off and each service tested; an optional Playlink address adds a link back to the right page. A new per-pair option removes empty slave folders after each scan. Only folders with no file at all inside are removed (into the quarantine, recorded in History); folders holding any file wait in Cleanup, folders changed within the settle time are skipped, and dry run removes nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
590b8abe08
commit
faebc5dfb0
17 files changed
+1086
-26
No files matched your search
@@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cdnutter/playlink/internal/fsops"
|
||||
"github.com/cdnutter/playlink/internal/notify"
|
||||
"github.com/cdnutter/playlink/internal/probe"
|
||||
"github.com/cdnutter/playlink/internal/store"
|
||||
)
|
||||
@@ -42,6 +43,7 @@ type Engine struct {
|
||||
mu sync.Mutex
|
||||
|
||||
beforeAction func(ctx context.Context, reason string) error
|
||||
notify func(ctx context.Context, ev notify.Event)
|
||||
|
||||
emptyMu sync.Mutex
|
||||
empty map[int64]*NoMusicScan // latest scan for folders without music, per pair
|
||||
@@ -366,6 +368,40 @@ func (e *Engine) SetBeforeAction(f func(ctx context.Context, reason string) erro
|
||||
e.beforeAction = f
|
||||
}
|
||||
|
||||
// SetNotify installs the hook that tells the user about things that
|
||||
// happened without them (see the notify package).
|
||||
func (e *Engine) SetNotify(f func(ctx context.Context, ev notify.Event)) {
|
||||
e.notify = f
|
||||
}
|
||||
|
||||
func (e *Engine) emit(ctx context.Context, l *libs, ev notify.Event) {
|
||||
if e.notify == nil {
|
||||
return
|
||||
}
|
||||
ev.PairID, ev.Pair = l.pair.ID, l.pair.Name
|
||||
e.notify(ctx, ev)
|
||||
}
|
||||
|
||||
func plural(n int, one, many string) string {
|
||||
if n == 1 {
|
||||
return "1 " + one
|
||||
}
|
||||
return fmt.Sprintf("%d %s", n, many)
|
||||
}
|
||||
|
||||
func formatBytes(n int64) string {
|
||||
const unit = 1024
|
||||
if n < unit {
|
||||
return fmt.Sprintf("%d B", n)
|
||||
}
|
||||
div, exp := int64(unit), 0
|
||||
for m := n / unit; m >= unit; m /= unit {
|
||||
div *= unit
|
||||
exp++
|
||||
}
|
||||
return fmt.Sprintf("%.1f %cB", float64(n)/float64(div), "KMGTPE"[exp])
|
||||
}
|
||||
|
||||
// BeforeAction runs the pre-action backup, once per user action (not per
|
||||
// file). It does nothing in dry run, where no files change. An error means
|
||||
// the action must not run.
|
||||
|
||||
Reference in new issue
Block a user