feat: add keyboard shortcuts (Del/S) and download statistics bar

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
xRangerDE 2026-03-20 09:40:39 +01:00
parent c96fd13aff
commit 2481230983
3 changed files with 60 additions and 0 deletions

View File

@ -218,6 +218,7 @@
<button class="btn btn-clear" id="btnClear" onclick="clearCompleted()">Leeren</button>
</div>
</div>
<div class="stats-bar" id="statsBar"></div>
</aside>
<main class="main">

View File

@ -96,6 +96,10 @@ async function init(): Promise<void> {
byId('mergeProgressText').textContent = Math.round(percent) + '%';
});
// Update stats bar
updateStatsBar();
setInterval(updateStatsBar, 5000);
if (config.client_id && config.client_secret) {
await connect();
} else {
@ -119,9 +123,56 @@ async function init(): Promise<void> {
scheduleQueueSync(document.hidden ? 600 : 150);
});
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
// Skip if user is typing in an input field
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || e.target instanceof HTMLSelectElement) return;
if (e.key === 'Delete' && selectedQueueIds.length > 0) {
// Delete selected queue items
const idsToRemove = [...selectedQueueIds];
selectedQueueIds = [];
(async () => {
for (const id of idsToRemove) {
queue = await window.api.removeFromQueue(id);
}
renderQueue();
})();
}
if ((e.key === 's' || e.key === 'S') && !e.ctrlKey && !e.altKey && !e.metaKey) {
e.preventDefault();
toggleDownload();
}
});
scheduleQueueSync(QUEUE_SYNC_DEFAULT_MS);
}
function formatBytesRenderer(bytes: number): string {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
}
function formatSpeedRenderer(bytesPerSec: number): string {
if (bytesPerSec < 1024) return `${bytesPerSec.toFixed(0)} B/s`;
if (bytesPerSec < 1024 * 1024) return `${(bytesPerSec / 1024).toFixed(1)} KB/s`;
return `${(bytesPerSec / (1024 * 1024)).toFixed(1)} MB/s`;
}
async function updateStatsBar(): Promise<void> {
try {
const metrics = await window.api.getRuntimeMetrics();
const bar = byId('statsBar');
if (!bar) return;
const totalDL = formatBytesRenderer(metrics.downloadedBytesTotal);
const avgSpeed = metrics.avgSpeedBytesPerSec > 0 ? formatSpeedRenderer(metrics.avgSpeedBytesPerSec) : '-';
bar.textContent = `${totalDL} | ${avgSpeed} avg | ${metrics.downloadsCompleted} done | ${metrics.downloadsFailed} failed`;
} catch { }
}
let toastHideTimer: number | null = null;
let queueSyncTimer: number | null = null;
let queueSyncInFlight = false;

View File

@ -386,6 +386,14 @@ body {
flex-shrink: 0;
}
.stats-bar {
padding: 6px 15px;
font-size: 10px;
color: var(--text-secondary);
border-top: 1px solid rgba(255,255,255,0.1);
flex-shrink: 0;
}
.btn {
flex: 1;
padding: 10px;