From 5574b50d20ff5156bb69e73d709d9d8521a741f0 Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Wed, 4 Mar 2026 00:23:20 +0100 Subject: [PATCH] Add visual online/offline status dot indicator for Rapidgator links Co-Authored-By: Claude Opus 4.6 --- package.json | 2 +- src/main/download-manager.ts | 9 ++++++--- src/renderer/App.tsx | 5 ++++- src/renderer/styles.css | 27 +++++++++++++++++++++++++++ src/shared/types.ts | 1 + 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ba39211..bbe7aa8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "real-debrid-downloader", - "version": "1.5.83", + "version": "1.5.84", "description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)", "main": "build/main/main/main.js", "author": "Sucukdeluxe", diff --git a/src/main/download-manager.ts b/src/main/download-manager.ts index aad7715..58ac44c 100644 --- a/src/main/download-manager.ts +++ b/src/main/download-manager.ts @@ -1527,8 +1527,12 @@ export class DownloadManager extends EventEmitter { for (const itemId of itemIds) { const item = this.session.items[itemId]; if (!item || item.status !== "queued") continue; + item.onlineStatus = "checking"; itemsToCheck.push({ itemId, url: item.url }); } + if (itemsToCheck.length > 0) { + this.emitState(); + } const uniqueUrls = [...new Set(itemsToCheck.map(i => i.url))]; const concurrency = 4; @@ -1555,16 +1559,15 @@ export class DownloadManager extends EventEmitter { item.status = "failed"; item.fullStatus = "Offline"; item.lastError = "Datei nicht gefunden auf Rapidgator"; + item.onlineStatus = "offline"; item.updatedAt = nowMs(); changed = true; } else { if (result.fileName && looksLikeOpaqueFilename(item.fileName)) { item.fileName = sanitizeFilename(result.fileName); this.assignItemTargetPath(item, path.join(this.session.packages[item.packageId]?.outputDir || this.settings.outputDir, item.fileName)); - item.updatedAt = nowMs(); - changed = true; } - item.fullStatus = "Online"; + item.onlineStatus = "online"; item.updatedAt = nowMs(); changed = true; } diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 0b49664..9c93b83 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -3029,7 +3029,10 @@ const PackageCard = memo(function PackageCard({ pkg, items, packageSpeed, isFirs {!collapsed && items.map((item) => (
{ e.stopPropagation(); onSelect(item.id, e.ctrlKey); }} onMouseDown={(e) => { e.stopPropagation(); onSelectMouseDown(item.id, e); }} onMouseEnter={() => onSelectMouseEnter(item.id)} onContextMenu={(e) => { e.preventDefault(); e.stopPropagation(); onContextMenu(pkg.id, item.id, e.clientX, e.clientY); }}> - {item.fileName} + + {item.onlineStatus && } + {item.fileName} + {(() => { const total = item.totalBytes || item.downloadedBytes || 0; const dl = item.downloadedBytes || 0; diff --git a/src/renderer/styles.css b/src/renderer/styles.css index be068bb..ad72eb8 100644 --- a/src/renderer/styles.css +++ b/src/renderer/styles.css @@ -1315,6 +1315,33 @@ td { padding-left: 32px; } +.link-status-dot { + display: inline-block; + width: 8px; + height: 8px; + border-radius: 50%; + margin-right: 6px; + flex-shrink: 0; + vertical-align: middle; +} +.link-status-dot.online { + background: #22c55e; + box-shadow: 0 0 4px #22c55e80; +} +.link-status-dot.offline { + background: #ef4444; + box-shadow: 0 0 4px #ef444480; +} +.link-status-dot.checking { + background: #f59e0b; + box-shadow: 0 0 4px #f59e0b80; + animation: pulse-dot 1s ease-in-out infinite; +} +@keyframes pulse-dot { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.4; } +} + .item-remove { background: none; border: none; diff --git a/src/shared/types.ts b/src/shared/types.ts index c8cd1ce..8844b37 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -101,6 +101,7 @@ export interface DownloadItem { fullStatus: string; createdAt: number; updatedAt: number; + onlineStatus?: "online" | "offline" | "checking"; } export interface PackageEntry {