Compare commits
2 Commits
b92330863a
...
ce33617aa6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce33617aa6 | ||
|
|
d71dd3af0b |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "real-debrid-downloader",
|
||||
"version": "1.7.136",
|
||||
"version": "1.7.137",
|
||||
"description": "Desktop downloader",
|
||||
"main": "build/main/main/main.js",
|
||||
"author": "Sucukdeluxe",
|
||||
|
||||
@ -2149,12 +2149,14 @@ export class DownloadManager extends EventEmitter {
|
||||
}
|
||||
|
||||
private resetSessionTotalsIfQueueEmpty(force = false): void {
|
||||
// Cheap O(1) check via cached counters covers the common case.
|
||||
// The Object.keys() cross-check below was redundant — itemCount and
|
||||
// packageOrder are kept in sync with session.items / session.packages
|
||||
// by every mutation site, so the second check just allocated two
|
||||
// arrays per call without ever changing the outcome.
|
||||
if (this.itemCount > 0 || this.session.packageOrder.length > 0) {
|
||||
return;
|
||||
}
|
||||
if (Object.keys(this.session.items).length > 0 || Object.keys(this.session.packages).length > 0) {
|
||||
return;
|
||||
}
|
||||
if (!force && (this.sessionDownloadedBytes > 0 || this.sessionCompletedFiles > 0 || this.itemContributedBytes.size > 0)) {
|
||||
return;
|
||||
}
|
||||
@ -7566,22 +7568,25 @@ export class DownloadManager extends EventEmitter {
|
||||
let changed = false;
|
||||
const waitSeconds = Math.max(0, Math.ceil((this.session.reconnectUntil - nowMs()) / 1000));
|
||||
const waitText = `Reconnect-Wait (${waitSeconds}s)`;
|
||||
const itemIds = this.runItemIds.size > 0 ? this.runItemIds : Object.keys(this.session.items);
|
||||
for (const itemId of itemIds) {
|
||||
// Iterate without allocating an Object.keys() array (called every 900ms
|
||||
// during reconnect; with 5000+ items that's a 5000-string allocation per tick).
|
||||
const updateItem = (itemId: string): void => {
|
||||
const item = this.session.items[itemId];
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
if (!item) return;
|
||||
const pkg = this.session.packages[item.packageId];
|
||||
if (!pkg || pkg.cancelled || !pkg.enabled) {
|
||||
continue;
|
||||
}
|
||||
if (!pkg || pkg.cancelled || !pkg.enabled) return;
|
||||
if (item.status === "queued") {
|
||||
item.status = "reconnect_wait";
|
||||
item.fullStatus = waitText;
|
||||
item.updatedAt = nowMs();
|
||||
changed = true;
|
||||
}
|
||||
};
|
||||
if (this.runItemIds.size > 0) {
|
||||
for (const itemId of this.runItemIds) updateItem(itemId);
|
||||
} else {
|
||||
// for-in iterates own enumerable string keys without allocating an array
|
||||
for (const itemId in this.session.items) updateItem(itemId);
|
||||
}
|
||||
if (changed) {
|
||||
this.emitState();
|
||||
|
||||
@ -1673,15 +1673,22 @@ export function App(): ReactElement {
|
||||
showToast("Accounts-Spalten zurückgesetzt", 1800);
|
||||
}, []);
|
||||
|
||||
// Sync column order from settings (value-based comparison to avoid reference issues)
|
||||
const columnOrderJson = JSON.stringify(snapshot.settings.columnOrder);
|
||||
// Sync column order from settings. Avoid JSON.stringify on every render
|
||||
// (which was a 7-element array stringify per snapshot tick). A simple
|
||||
// join() is one O(n) string concat without Object/Array allocation overhead,
|
||||
// and useMemo caches the resulting key so React only sees a new dep when the
|
||||
// contents actually changed.
|
||||
const columnOrderKey = useMemo(
|
||||
() => (snapshot.settings.columnOrder || []).join("|"),
|
||||
[snapshot.settings.columnOrder]
|
||||
);
|
||||
useEffect(() => {
|
||||
const order = snapshot.settings.columnOrder;
|
||||
if (order && order.length > 0) {
|
||||
setColumnOrder(order);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [columnOrderJson]);
|
||||
}, [columnOrderKey]);
|
||||
|
||||
const currentCollectorTab = collectorTabs.find((t) => t.id === activeCollectorTab) ?? collectorTabs[0];
|
||||
|
||||
@ -2057,14 +2064,25 @@ export function App(): ReactElement {
|
||||
const hiddenPackageCount = shouldLimitPackageRendering
|
||||
? Math.max(0, totalPackageCount - packages.length)
|
||||
: 0;
|
||||
// The sort-by-progress logic only runs when the session is running AND auto-sort
|
||||
// is enabled AND there's more than one package. When any of those isn't true,
|
||||
// the items reference is irrelevant — passing null here makes useMemo skip the
|
||||
// re-evaluation that previously fired on EVERY item update (progress, status,
|
||||
// speed) even when the sort would have returned the original `packages` array.
|
||||
const sortRelevantItems = (snapshot.session.running && settingsDraft.autoSortPackagesByProgress && packages.length > 1)
|
||||
? snapshot.session.items
|
||||
: null;
|
||||
const visiblePackages = useMemo(() => {
|
||||
if (!sortRelevantItems) {
|
||||
return packages;
|
||||
}
|
||||
return sortPackagesForDisplay(
|
||||
packages,
|
||||
snapshot.session.items,
|
||||
snapshot.session.running,
|
||||
settingsDraft.autoSortPackagesByProgress
|
||||
sortRelevantItems,
|
||||
true,
|
||||
true
|
||||
);
|
||||
}, [packages, settingsDraft.autoSortPackagesByProgress, snapshot.session.running, snapshot.session.items]);
|
||||
}, [packages, sortRelevantItems]);
|
||||
|
||||
const hasSavedAllDebridAccount = Boolean(snapshot.settings.allDebridUseWebLogin || snapshot.settings.allDebridToken.trim());
|
||||
const allDebridSettingsDirty = snapshot.settings.allDebridUseWebLogin !== settingsDraft.allDebridUseWebLogin
|
||||
@ -6164,6 +6182,12 @@ const ItemRow = memo(function ItemRow({ item, packageId, isSelected, sessionRunn
|
||||
e.stopPropagation();
|
||||
onContextMenu(packageId, item.id, e.clientX, e.clientY);
|
||||
}, [packageId, item.id, onContextMenu]);
|
||||
// Memoize the date string so it doesn't get re-formatted on every re-render
|
||||
// when only progress/speed changed but createdAt is stable.
|
||||
const formattedCreatedAt = useMemo(() => formatDateTime(item.createdAt), [item.createdAt]);
|
||||
// Memoize the displayed status so we don't compute it twice (title + body)
|
||||
const displayStatus = useMemo(() => computeDisplayedItemStatus(item, sessionRunning), [item, sessionRunning]);
|
||||
const statusTitle = displayStatus ? (item.retries > 0 ? `${displayStatus} ? R${item.retries}` : displayStatus) : "";
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -6213,17 +6237,13 @@ const ItemRow = memo(function ItemRow({ item, packageId, isSelected, sessionRunn
|
||||
case "hoster": { const h = extractHoster(item.url) || ""; return <span key={col} className="pkg-col pkg-col-hoster" title={h}>{h}</span>; }
|
||||
case "account": return <span key={col} className="pkg-col pkg-col-account">{item.providerLabel || (item.provider ? providerLabels[item.provider] : "")}</span>;
|
||||
case "prio": return <span key={col} className="pkg-col pkg-col-prio"></span>;
|
||||
case "status": {
|
||||
const displayStatus = computeDisplayedItemStatus(item, sessionRunning);
|
||||
const title = !displayStatus ? "" : (item.retries > 0 ? `${displayStatus} ? R${item.retries}` : displayStatus);
|
||||
return (
|
||||
<span key={col} className="pkg-col pkg-col-status" title={title}>
|
||||
{displayStatus}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
case "status": return (
|
||||
<span key={col} className="pkg-col pkg-col-status" title={statusTitle}>
|
||||
{displayStatus}
|
||||
</span>
|
||||
);
|
||||
case "speed": return <span key={col} className="pkg-col pkg-col-speed">{item.speedBps > 0 ? formatSpeedMbps(item.speedBps) : ""}</span>;
|
||||
case "added": return <span key={col} className="pkg-col pkg-col-added">{formatDateTime(item.createdAt)}</span>;
|
||||
case "added": return <span key={col} className="pkg-col pkg-col-added">{formattedCreatedAt}</span>;
|
||||
default: return null;
|
||||
}
|
||||
})}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user