import { config, DEFAULT_CONFIG } from "../config"; import { isAvailable as isYtdlpAvailable, checkUrl, addToFastQueue, addToSlowQueue, getQueues, cancelSlowQueueItem, } from "../ytdlp"; import { getOrCreateUser } from "./helpers"; import { createPlaylist, generateUniquePlaylistName } from "../db"; const ytdlpConfig = config.ytdlp || DEFAULT_CONFIG.ytdlp!; // POST /api/fetch - fetch from URL (yt-dlp) export async function handleFetch(req: Request, server: any): Promise { const { user, headers } = getOrCreateUser(req, server); if (!user) { return Response.json({ error: "Authentication required" }, { status: 401 }); } if (user.is_guest) { return Response.json({ error: "Guests cannot fetch from URLs" }, { status: 403 }); } if (!ytdlpConfig.enabled) { return Response.json({ error: "Feature disabled" }, { status: 403 }); } if (!isYtdlpAvailable()) { return Response.json({ error: "yt-dlp not available" }, { status: 503 }); } try { const { url } = await req.json(); if (!url || typeof url !== "string") { return Response.json({ error: "URL is required" }, { status: 400 }); } console.log(`[Fetch] ${user.username} checking URL: ${url}`); const info = await checkUrl(url); if (info.type === "playlist") { if (!ytdlpConfig.allowPlaylists) { return Response.json({ error: "Playlist downloads are disabled" }, { status: 403 }); } return Response.json(info, { headers }); } else { const item = addToFastQueue(info.url, info.title, user.id); console.log(`[Fetch] ${user.username} queued: ${info.title} (id=${item.id})`); return Response.json({ type: "single", id: item.id, title: item.title, queueType: "fast" }, { headers }); } } catch (e: any) { console.error("[Fetch] Error:", e); return Response.json({ error: e.message || "Invalid request" }, { status: 400 }); } } // POST /api/fetch/confirm - confirm playlist download export async function handleFetchConfirm(req: Request, server: any): Promise { const { user, headers } = getOrCreateUser(req, server); if (!user) { return Response.json({ error: "Authentication required" }, { status: 401 }); } if (user.is_guest) { return Response.json({ error: "Guests cannot fetch from URLs" }, { status: 403 }); } if (!ytdlpConfig.enabled || !isYtdlpAvailable()) { return Response.json({ error: "Feature not available" }, { status: 503 }); } try { const { items, playlistTitle } = await req.json(); if (!Array.isArray(items) || items.length === 0) { return Response.json({ error: "Items required" }, { status: 400 }); } // Auto-create playlist with unique name const baseName = playlistTitle || "Imported Playlist"; const uniqueName = generateUniquePlaylistName(baseName, user.id); const playlist = createPlaylist(uniqueName, user.id, `Imported from URL (${items.length} tracks)`); console.log(`[Fetch] ${user.username} created playlist: ${uniqueName} (id=${playlist.id})`); const queueItems = addToSlowQueue(items, user.id, { id: playlist.id, name: uniqueName }); const estimatedMinutes = Math.ceil(queueItems.length * ytdlpConfig.slowQueueInterval / 60); const hours = Math.floor(estimatedMinutes / 60); const mins = estimatedMinutes % 60; const estimatedTime = hours > 0 ? `${hours}h ${mins}m` : `${mins}m`; console.log(`[Fetch] ${user.username} confirmed playlist: ${queueItems.length} items`); return Response.json({ message: `Added ${queueItems.length} items to queue`, queueType: "slow", estimatedTime, playlistId: playlist.id, playlistName: uniqueName, items: queueItems.map(i => ({ id: i.id, title: i.title })) }, { headers }); } catch (e) { console.error("[Fetch] Confirm error:", e); return Response.json({ error: "Invalid request" }, { status: 400 }); } } // GET /api/fetch - get fetch queue status (all users see all tasks) export function handleGetFetchQueue(req: Request, server: any): Response { const { user, headers } = getOrCreateUser(req, server); if (!user) { return Response.json({ error: "Authentication required" }, { status: 401 }); } const queues = getQueues(); // Return all queues, not filtered by user return Response.json(queues, { headers }); } // DELETE /api/fetch/:id - cancel a slow queue item export function handleCancelFetchItem(req: Request, server: any, itemId: string): Response { const { user, headers } = getOrCreateUser(req, server); if (!user) { return Response.json({ error: "Authentication required" }, { status: 401 }); } const success = cancelSlowQueueItem(itemId, user.id); if (success) { return Response.json({ message: "Item cancelled" }, { headers }); } else { return Response.json({ error: "Cannot cancel item (not found, not owned, or already downloading)" }, { status: 400, headers }); } }