saving
This commit is contained in:
parent
3f7bd2ec1c
commit
424873e7b0
|
|
@ -72,9 +72,11 @@ h3 { font-size: 0.8rem; color: #666; margin-bottom: 0.3rem; text-transform: uppe
|
|||
.task-item.complete .task-bar { background: #4e8; }
|
||||
.slow-queue-section { margin-top: 0.5rem; border-top: 1px solid #333; padding-top: 0.5rem; }
|
||||
.slow-queue-section.hidden { display: none; }
|
||||
.slow-queue-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.3rem; padding: 0 0.2rem; }
|
||||
.slow-queue-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.3rem; padding: 0 0.2rem; gap: 0.5rem; }
|
||||
.slow-queue-title { font-size: 0.75rem; color: #888; font-weight: 500; }
|
||||
.slow-queue-timer { font-size: 0.7rem; color: #6af; }
|
||||
.slow-queue-timer { font-size: 0.7rem; color: #6af; flex: 1; }
|
||||
.slow-queue-cancel-all { background: none; border: 1px solid #633; color: #a66; font-size: 0.65rem; padding: 0.15rem 0.4rem; border-radius: 3px; cursor: pointer; transition: all 0.15s; }
|
||||
.slow-queue-cancel-all:hover { background: #422; border-color: #844; color: #e88; }
|
||||
.slow-queue-list { display: flex; flex-direction: column; gap: 0.15rem; max-height: 200px; overflow-y: auto; }
|
||||
.slow-queue-playlist-header { font-size: 0.7rem; color: #888; padding: 0.3rem 0.2rem 0.15rem; margin-top: 0.2rem; border-top: 1px solid #2a2a2a; }
|
||||
.slow-queue-playlist-header:first-child { border-top: none; margin-top: 0; }
|
||||
|
|
|
|||
|
|
@ -222,10 +222,27 @@
|
|||
<div class="slow-queue-header">
|
||||
<span class="slow-queue-title">Playlist Queue</span>
|
||||
<span class="slow-queue-timer"></span>
|
||||
<button class="slow-queue-cancel-all" title="Cancel all">Cancel All</button>
|
||||
</div>
|
||||
<div class="slow-queue-list"></div>
|
||||
`;
|
||||
|
||||
// Wire up cancel all button
|
||||
slowQueueSection.querySelector(".slow-queue-cancel-all").onclick = async () => {
|
||||
try {
|
||||
const res = await fetch("/api/fetch", { method: "DELETE" });
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
M.showToast(data.message);
|
||||
pollSlowQueue();
|
||||
} else {
|
||||
M.showToast("Failed to cancel", "error");
|
||||
}
|
||||
} catch (e) {
|
||||
M.showToast("Failed to cancel", "error");
|
||||
}
|
||||
};
|
||||
|
||||
// Insert before tasks-empty
|
||||
tasksEmpty.parentNode.insertBefore(slowQueueSection, tasksEmpty);
|
||||
return slowQueueSection;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
addToSlowQueue,
|
||||
getQueues,
|
||||
cancelSlowQueueItem,
|
||||
cancelAllSlowQueueItems,
|
||||
} from "../ytdlp";
|
||||
import { getOrCreateUser } from "./helpers";
|
||||
import { createPlaylist, generateUniquePlaylistName } from "../db";
|
||||
|
|
@ -133,3 +134,14 @@ export function handleCancelFetchItem(req: Request, server: any, itemId: string)
|
|||
return Response.json({ error: "Cannot cancel item (not found, not owned, or already downloading)" }, { status: 400, headers });
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE /api/fetch - cancel all slow queue items for user
|
||||
export function handleCancelAllFetchItems(req: Request, server: any): Response {
|
||||
const { user, headers } = getOrCreateUser(req, server);
|
||||
if (!user) {
|
||||
return Response.json({ error: "Authentication required" }, { status: 401 });
|
||||
}
|
||||
|
||||
const cancelled = cancelAllSlowQueueItems(user.id);
|
||||
return Response.json({ message: `Cancelled ${cancelled} items`, cancelled }, { headers });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import {
|
|||
handleFetchConfirm,
|
||||
handleGetFetchQueue,
|
||||
handleCancelFetchItem,
|
||||
handleCancelAllFetchItems,
|
||||
} from "./fetch";
|
||||
|
||||
// Playlist routes
|
||||
|
|
@ -150,6 +151,9 @@ export function createRouter() {
|
|||
if (path === "/api/fetch" && req.method === "GET") {
|
||||
return handleGetFetchQueue(req, server);
|
||||
}
|
||||
if (path === "/api/fetch" && req.method === "DELETE") {
|
||||
return handleCancelAllFetchItems(req, server);
|
||||
}
|
||||
const fetchCancelMatch = path.match(/^\/api\/fetch\/([^/]+)$/);
|
||||
if (fetchCancelMatch && req.method === "DELETE") {
|
||||
return handleCancelFetchItem(req, server, fetchCancelMatch[1]);
|
||||
|
|
|
|||
30
ytdlp.ts
30
ytdlp.ts
|
|
@ -518,6 +518,36 @@ export function cancelSlowQueueItem(id: string, userId: number): boolean {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Cancel all queued items in slow queue for a user
|
||||
export function cancelAllSlowQueueItems(userId: number): number {
|
||||
const items = slowQueue.filter(i => i.userId === userId && i.status === "queued");
|
||||
let cancelled = 0;
|
||||
|
||||
for (const item of items) {
|
||||
item.status = "cancelled";
|
||||
item.completedAt = Date.now();
|
||||
|
||||
updateSlowQueueItem(item.id, {
|
||||
status: "cancelled",
|
||||
completedAt: Math.floor(item.completedAt / 1000)
|
||||
});
|
||||
|
||||
notifyProgress(item);
|
||||
cancelled++;
|
||||
}
|
||||
|
||||
// Remove all cancelled items after brief delay
|
||||
setTimeout(() => {
|
||||
for (let i = slowQueue.length - 1; i >= 0; i--) {
|
||||
if (slowQueue[i].status === "cancelled") {
|
||||
slowQueue.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
// Notify progress callback
|
||||
function notifyProgress(item: QueueItem): void {
|
||||
if (onProgress) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue