feat: stop every download at once
A stop button appears beside Download all whenever anything is
downloading or waiting to, and disappears when nothing is. It kills the
running processes, marks everything the database still calls queued or
running as cancelled, and clears the part files. Downloads already
finished are untouched.
That also covers two cases a per-video Cancel cannot reach: a download
parked on a slot, which stands down when its turn comes, and a row left
"running" by a crash that no process backs any more.
Cancelling no longer reports itself as a failure. download_video
returned Err("Download was cancelled.") when it found its child gone,
which the caller turned into an error dialog — pressing Stop all would
have raised one per download. Stopping something is a normal outcome:
the state is already recorded and the event already sent, so it returns
cleanly.
This commit is contained in:
+26
-1
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
cancelDownload, deleteAllDownloads, deleteDownload, downloadVideo,
|
||||
cancelAllDownloads, cancelDownload, deleteAllDownloads, deleteDownload, downloadVideo,
|
||||
fetchDurations, onRefreshProgress, refreshFeeds, setCookieSource,
|
||||
} from "./api";
|
||||
import Player from "./components/Player";
|
||||
@@ -253,6 +253,29 @@ export default function App() {
|
||||
return () => clearInterval(id);
|
||||
}, [online, refreshing, playingIndex, doRefresh]);
|
||||
|
||||
// Anything in flight, whether or not it is currently listed — a download
|
||||
// started on one channel keeps running while you look at another.
|
||||
const activeDownloads = useMemo(() => {
|
||||
const ids = new Set<string>();
|
||||
for (const [id, l] of Object.entries(live)) {
|
||||
if (l.state === "queued" || l.state === "running") ids.add(id);
|
||||
}
|
||||
for (const i of items) {
|
||||
const state = live[i.id]?.state ?? i.state;
|
||||
if (state === "queued" || state === "running") ids.add(i.id);
|
||||
}
|
||||
return ids.size;
|
||||
}, [live, items]);
|
||||
|
||||
const stopAll = useCallback(() => {
|
||||
cancelAllDownloads()
|
||||
.then((n) => {
|
||||
reload();
|
||||
say(n === 1 ? "Stopped 1 download" : `Stopped ${n} downloads`);
|
||||
})
|
||||
.catch((e) => setFailure(String(e)));
|
||||
}, [reload, say]);
|
||||
|
||||
// Everything listed that is not already here or on its way.
|
||||
const pendingDownloads = useMemo(
|
||||
() =>
|
||||
@@ -420,6 +443,8 @@ export default function App() {
|
||||
onDownloadAll={online && bulkTargets.length > 0 ? downloadAll : undefined}
|
||||
downloadAllCount={bulkTargets.length}
|
||||
downloadAllTotal={pendingDownloads.length}
|
||||
onStopAll={activeDownloads > 0 ? stopAll : undefined}
|
||||
stopAllCount={activeDownloads}
|
||||
sidebarHidden={sidebarHidden}
|
||||
onShowSidebar={() => { setSidebarHidden(false); setSidebarPeek(false); }}
|
||||
titleBarInset={titleBarInset}
|
||||
|
||||
Reference in New Issue
Block a user