diff --git a/cantaloupe_sync.py b/cantaloupe_sync.py
index 906e2d4..f118777 100644
--- a/cantaloupe_sync.py
+++ b/cantaloupe_sync.py
@@ -419,9 +419,10 @@ async def run_sync(
# Try subprocess call to cantaloupe export
try:
import subprocess
+ import sys
cantaloupe_dir = os.path.expanduser("~/projects/cantaloupe-downloader")
result = subprocess.run(
- ["python", "-m", "cantaloupe", "export", "--scheduled"],
+ [sys.executable, "-m", "cantaloupe", "export", "--scheduled"],
capture_output=True, text=True, timeout=120,
cwd=cantaloupe_dir,
)
diff --git a/static/index.html b/static/index.html
index 141a0c3..30d39e8 100644
--- a/static/index.html
+++ b/static/index.html
@@ -864,6 +864,8 @@
Cantaloupe Sync
+
+
@@ -2320,6 +2322,28 @@ async function runSync() {
}
}
+// ── Upload Excel File ──
+async function uploadSyncFile(event) {
+ const file = event.target.files?.[0];
+ if (!file) return;
+ const fd = new FormData();
+ fd.append('file', file);
+ const btn = document.getElementById('csSyncBtn');
+ btn.disabled = true;
+ btn.innerHTML = ' Uploading...';
+ try {
+ const result = await api('/api/admin/cantaloupe/sync', { method: 'POST', body: fd });
+ showToast('Upload processed — batch #' + result.id);
+ await loadCantaloupeSync();
+ } catch (e) {
+ showToast('Upload failed: ' + e.message, true);
+ } finally {
+ btn.disabled = false;
+ btn.innerHTML = '🔄 Sync Now';
+ event.target.value = ''; // reset so same file can be re-picked
+ }
+}
+
// ── Approve / Reject ──
async function approveBatch(batchId) {
const confirmed = await showModal('Approve Batch',