From 3186dfb942ba8571bd6340c4610a96b702a80aa3 Mon Sep 17 00:00:00 2001 From: wander Date: Mon, 5 Jan 2026 08:06:52 -0500 Subject: [PATCH] feat: Add Batch Recovery button --- templates/dashboard.html | 47 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/templates/dashboard.html b/templates/dashboard.html index 8860da1..1571cea 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -245,8 +245,12 @@
-

Files found on disk but missing from TubeArchivist. Recover - them to restore your library.

+
+

Files found on disk but missing from TubeArchivist. + Recover them to restore your library.

+ +
@@ -744,6 +748,45 @@ document.getElementById('status-filter').addEventListener('change', () => { fetchStatus(); }); + + async function recoverAll(type) { + if (!confirm("Are you sure you want to BATCH RECOVER all items in '" + type + "'?\n\nThis will process them one by one. Please do not close this tab.")) return; + + const tbody = document.getElementById('tbody-' + type); + // Select all buttons that trigger recovery + const buttons = Array.from(tbody.querySelectorAll('button[onclick*="startRecovery"]')); + + if (buttons.length === 0) { + alert("No items to recover!"); + return; + } + + let successCount = 0; + + for (const btn of buttons) { + if (btn.disabled) continue; // Skip if already processing + + // Visual scroll to item + btn.scrollIntoView({ behavior: 'smooth', block: 'center' }); + + // Parse the path + const onClickText = btn.getAttribute('onclick'); + const match = onClickText.match(/startRecovery\('(.+?)'/); + + if (match) { + const path = match[1]; + try { + await startRecovery(path, btn); + successCount++; + } catch (e) { + console.error("Batch error for " + path, e); + } + // Pace it + await new Promise(r => setTimeout(r, 500)); + } + } + alert("Batch Complete! Processed: " + buttons.length); + }