From 233601035fff22af0b9dde9a9a0e8ac0c0a3a26d Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 11 Jan 2026 21:04:13 +0100 Subject: [PATCH] Fix download: use proxy URL instead of directUrl --- mod.ts | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/mod.ts b/mod.ts index 356abb8..72126e6 100644 --- a/mod.ts +++ b/mod.ts @@ -256,7 +256,7 @@ async function handler(req: Request): Promise { return proxyAudio(audioUrl, req); } - // Download audio as MP3 + // Download audio as M4A if (pathname === "/api/download") { const id = searchParams.get("id"); const title = searchParams.get("title") || "audio"; @@ -269,14 +269,14 @@ async function handler(req: Request): Promise { const piped = await fetchFromPiped(id); if (piped.success && piped.streamingUrls) { - // Check for mimeType or type field, and quality or audioQuality + // Find best audio - prefer mp4/m4a with MEDIUM quality const audio = piped.streamingUrls.find((s: any) => - (s.mimeType?.includes("audio") || s.type?.includes("audio")) && - (s.quality === "AUDIO_QUALITY_MEDIUM" || s.audioQuality === "AUDIO_QUALITY_MEDIUM") - ) || piped.streamingUrls.find((s: any) => s.mimeType?.includes("audio") || s.type?.includes("audio")); + s.type?.includes("audio/mp4") && s.audioQuality === "AUDIO_QUALITY_MEDIUM" + ) || piped.streamingUrls.find((s: any) => s.type?.includes("audio")); if (audio) { - audioUrl = audio.url || audio.directUrl; - contentType = audio.mimeType || audio.type || "audio/mp4"; + // Use proxy URL (url field) - directUrl is IP-locked + audioUrl = audio.url; + contentType = audio.type?.split(";")[0] || "audio/mp4"; } } @@ -284,36 +284,28 @@ async function handler(req: Request): Promise { const invidious = await fetchFromInvidious(id); if (invidious.success && invidious.streamingUrls) { const audio = invidious.streamingUrls.find((s: any) => - (s.mimeType?.includes("audio") || s.type?.includes("audio")) && - (s.quality === "AUDIO_QUALITY_MEDIUM" || s.audioQuality === "AUDIO_QUALITY_MEDIUM") - ) || invidious.streamingUrls.find((s: any) => s.mimeType?.includes("audio") || s.type?.includes("audio")); + s.type?.includes("audio/mp4") && s.audioQuality === "AUDIO_QUALITY_MEDIUM" + ) || invidious.streamingUrls.find((s: any) => s.type?.includes("audio")); if (audio) { - audioUrl = audio.url || audio.directUrl; - contentType = audio.mimeType || audio.type || "audio/mp4"; + audioUrl = audio.url; + contentType = audio.type?.split(";")[0] || "audio/mp4"; } } } if (!audioUrl) return json({ success: false, error: "No audio stream found" }, 404); - // Create filename - use m4a for mp4 audio, webm for webm + // Create filename const ext = contentType.includes("webm") ? ".webm" : ".m4a"; const filename = `${artist ? artist + " - " : ""}${title}`.replace(/[<>:"/\\|?*]/g, "").trim() + ext; try { - const response = await fetch(audioUrl, { - headers: { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", - "Referer": "https://www.youtube.com/", - "Origin": "https://www.youtube.com", - }, - }); - - if (!response.ok) return json({ success: false, error: "Failed to fetch audio" }, 502); + const response = await fetch(audioUrl); + if (!response.ok) return json({ success: false, error: "Failed to fetch audio: " + response.status }, 502); return new Response(response.body, { headers: { - "Content-Type": "audio/mp4", + "Content-Type": contentType, "Content-Disposition": `attachment; filename="${encodeURIComponent(filename)}"`, "Access-Control-Allow-Origin": "*", "Access-Control-Expose-Headers": "Content-Disposition",