diff --git a/dist/urbm-2026.06.21.r011-x86_64-1.txz.sha256 b/dist/urbm-2026.06.21.r011-x86_64-1.txz.sha256 deleted file mode 100644 index 3ecc458..0000000 --- a/dist/urbm-2026.06.21.r011-x86_64-1.txz.sha256 +++ /dev/null @@ -1 +0,0 @@ -ccd839060bbcc55fe1c634eb64869d3e98e2e56f3e8c878d04dc28cbee761d74 urbm-2026.06.21.r011-x86_64-1.txz diff --git a/dist/urbm-2026.06.21.r011-x86_64-1.txz b/dist/urbm-2026.06.21.r012-x86_64-1.txz similarity index 56% rename from dist/urbm-2026.06.21.r011-x86_64-1.txz rename to dist/urbm-2026.06.21.r012-x86_64-1.txz index 226bca4..9129b72 100644 Binary files a/dist/urbm-2026.06.21.r011-x86_64-1.txz and b/dist/urbm-2026.06.21.r012-x86_64-1.txz differ diff --git a/dist/urbm-2026.06.21.r012-x86_64-1.txz.sha256 b/dist/urbm-2026.06.21.r012-x86_64-1.txz.sha256 new file mode 100644 index 0000000..34b8861 --- /dev/null +++ b/dist/urbm-2026.06.21.r012-x86_64-1.txz.sha256 @@ -0,0 +1 @@ +9c909e42cbe12ca04b7e27661f4f7c1152ca66904f39083d7782fd31c19701ef urbm-2026.06.21.r012-x86_64-1.txz diff --git a/dist/urbm.plg b/dist/urbm.plg index f2cf982..97b41ff 100644 --- a/dist/urbm.plg +++ b/dist/urbm.plg @@ -2,13 +2,17 @@ - + - + ]> +### 2026.06.21.r012 +- Add emoji-labelled fields to Unraid and Gotify backup notifications. +- Shorten long Restic snapshot IDs in notifications to keep mobile notification cards readable. + ### 2026.06.21.r011 - Increase spacing between folder disclosure controls and checkboxes in all selectable tree browsers. diff --git a/internal/service/notification_test.go b/internal/service/notification_test.go index 32a93c8..88a7656 100644 --- a/internal/service/notification_test.go +++ b/internal/service/notification_test.go @@ -11,9 +11,9 @@ import ( func TestNotificationMessageIncludesBackupStatistics(t *testing.T) { started := time.Date(2026, 6, 14, 12, 0, 0, 0, time.UTC) finished := started.Add(2*time.Minute + 8*time.Second) - run := model.Run{TaskType: "backup", Status: "success", StartedAt: &started, FinishedAt: &finished, SnapshotID: "abc123", BytesAdded: 1536, FilesNew: 7, FilesChanged: 2, BytesProcessed: 5 * 1024 * 1024, FilesProcessed: 120} + run := model.Run{TaskType: "backup", Status: "success", StartedAt: &started, FinishedAt: &finished, SnapshotID: "abc123456789abcdef", BytesAdded: 1536, FilesNew: 7, FilesChanged: 2, BytesProcessed: 5 * 1024 * 1024, FilesProcessed: 120} message := notificationMessage("Freigaben", "LV-426", run, finished) - for _, expected := range []string{"📊 URBM-Zusammenfassung", "Status: Erfolgreich", "Job: Freigaben", "Repository: LV-426", "Dauer: 2 Min. 8 Sek.", "Snapshot: abc123", "Verarbeitete Daten: 5.0 MiB", "Verarbeitete Dateien: 120", "Neu gespeichert: 1.5 KiB", "Neue Dateien: 7", "Geänderte Dateien: 2"} { + for _, expected := range []string{"📊 Backup-Zusammenfassung", "📦 Repository: LV-426", "🗂️ Job: Freigaben", "📸 Snapshot: abc123456789", "⏱️ Dauer: 2 Min. 8 Sek.", "📂 Dateien: 120 verarbeitet", "💾 Verarbeitet: 5.0 MiB", "➕ Neu: 7 Dateien", "✏️ Geändert: 2 Dateien", "📤 Neu gespeichert: 1.5 KiB", "🔐 Ziel: Restic Repository", "✅ Status: Erfolgreich"} { if !strings.Contains(message, expected) { t.Errorf("message %q does not contain %q", message, expected) } diff --git a/internal/service/service.go b/internal/service/service.go index 72413c0..a8469c4 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -795,12 +795,15 @@ func notificationMessage(name, repository string, run model.Run, now time.Time) if status == "" { status = run.Status } - lines := []string{"📊 URBM-Zusammenfassung", "", "Status: " + status} - if name != "" { - lines = append(lines, "Job: "+name) - } + lines := []string{"📊 Backup-Zusammenfassung", ""} if repository != "" { - lines = append(lines, "Repository: "+repository) + lines = append(lines, "📦 Repository: "+repository) + } + if name != "" { + lines = append(lines, "🗂️ Job: "+name) + } + if run.TaskType == "backup" && run.SnapshotID != "" { + lines = append(lines, "📸 Snapshot: "+shortID(run.SnapshotID)) } if run.StartedAt != nil { finished := now @@ -808,33 +811,66 @@ func notificationMessage(name, repository string, run model.Run, now time.Time) finished = *run.FinishedAt } if duration := finished.Sub(*run.StartedAt); duration >= 0 { - lines = append(lines, "Dauer: "+formatDuration(duration)) + lines = append(lines, "", "⏱️ Dauer: "+formatDuration(duration)) } } if (run.TaskType == "backup" || run.TaskType == "rsync") && (run.Status == "success" || run.Status == "warning") { - if run.TaskType == "backup" && run.SnapshotID != "" { - lines = append(lines, "Snapshot: "+run.SnapshotID) - } lines = append(lines, - "Verarbeitete Daten: "+formatBytes(run.BytesProcessed), - fmt.Sprintf("Verarbeitete Dateien: %d", run.FilesProcessed), + fmt.Sprintf("📂 Dateien: %d verarbeitet", run.FilesProcessed), + "💾 Verarbeitet: "+formatBytes(run.BytesProcessed), ) if run.TaskType == "backup" { lines = append(lines, - "Neu gespeichert: "+formatBytes(run.BytesAdded), - fmt.Sprintf("Neue Dateien: %d", run.FilesNew), - fmt.Sprintf("Geänderte Dateien: %d", run.FilesChanged), + fmt.Sprintf("➕ Neu: %d Dateien", run.FilesNew), + fmt.Sprintf("✏️ Geändert: %d Dateien", run.FilesChanged), + "📤 Neu gespeichert: "+formatBytes(run.BytesAdded), ) } else { - lines = append(lines, "Kopierte Daten: "+formatBytes(run.BytesAdded)) + lines = append(lines, "📤 Kopiert: "+formatBytes(run.BytesAdded)) } } + lines = append(lines, "", "🔐 Ziel: "+notificationTargetLabel(run.TaskType), statusIcon(run.Status)+" Status: "+status) if run.Message != "" && run.Message != "backup completed" && run.Message != "rsync completed" { - lines = append(lines, "Details: "+run.Message) + lines = append(lines, "⚠️ Details: "+run.Message) } return strings.Join(lines, "\n") } +func statusIcon(status string) string { + switch status { + case "success": + return "✅" + case "warning": + return "⚠️" + case "failed": + return "❌" + default: + return "ℹ️" + } +} + +func notificationTargetLabel(taskType string) string { + switch taskType { + case "backup": + return "Restic Repository" + case "rsync": + return "Rsync Ziel" + case "restore": + return "Restore Ziel" + case "check", "prune": + return "Restic Repository" + default: + return "URBM" + } +} + +func shortID(value string) string { + if len(value) <= 12 { + return value + } + return value[:12] +} + func formatBytes(value int64) string { const unit = int64(1024) if value < unit { diff --git a/plugin/urbm.plg b/plugin/urbm.plg index 13356f1..8a5388a 100644 --- a/plugin/urbm.plg +++ b/plugin/urbm.plg @@ -2,13 +2,17 @@ - + ]> +### 2026.06.21.r012 +- Add emoji-labelled fields to Unraid and Gotify backup notifications. +- Shorten long Restic snapshot IDs in notifications to keep mobile notification cards readable. + ### 2026.06.21.r011 - Increase spacing between folder disclosure controls and checkboxes in all selectable tree browsers. diff --git a/webgui/URBM.page b/webgui/URBM.page index 65db42f..d9613e4 100644 --- a/webgui/URBM.page +++ b/webgui/URBM.page @@ -9,12 +9,12 @@ Tag="URBM Unraid Restic Backup Manager backup snapshots restore" - +
- -

URBM 2026.06.21.r011

Restic Backup Manager für Unraid

+ +

URBM 2026.06.21.r012

Restic Backup Manager für Unraid

Verbindung wird hergestellt...
@@ -32,4 +32,4 @@ $pluginRoot = '/plugins/urbm';
- +