mirror of
https://github.com/Kirazul/Verome-API.git
synced 2026-03-08 00:05:22 +00:00
Fix download: proxy audio through server to bypass IP lock
This commit is contained in:
52
mod.ts
52
mod.ts
@@ -261,32 +261,34 @@ async function handler(req: Request): Promise<Response> {
|
|||||||
const id = searchParams.get("id");
|
const id = searchParams.get("id");
|
||||||
const title = searchParams.get("title") || "audio";
|
const title = searchParams.get("title") || "audio";
|
||||||
const artist = searchParams.get("artist") || "";
|
const artist = searchParams.get("artist") || "";
|
||||||
const redirect = searchParams.get("redirect") !== "0";
|
|
||||||
if (!id) return error("Missing id");
|
if (!id) return error("Missing id");
|
||||||
|
|
||||||
// Get stream URL - try piped first, then invidious
|
// Get stream URL - try invidious first (better proxy support)
|
||||||
let audioUrl = null;
|
let audioUrl = null;
|
||||||
let contentType = "audio/mp4";
|
let contentType = "audio/mp4";
|
||||||
|
let instance = "";
|
||||||
|
|
||||||
const piped = await fetchFromPiped(id);
|
const invidious = await fetchFromInvidious(id);
|
||||||
if (piped.success && piped.streamingUrls) {
|
if (invidious.success && invidious.streamingUrls) {
|
||||||
const audio = piped.streamingUrls.find((s: any) =>
|
const audio = invidious.streamingUrls.find((s: any) =>
|
||||||
s.type?.includes("audio/mp4") && s.audioQuality === "AUDIO_QUALITY_MEDIUM"
|
s.type?.includes("audio/mp4") && s.audioQuality === "AUDIO_QUALITY_MEDIUM"
|
||||||
) || piped.streamingUrls.find((s: any) => s.type?.includes("audio"));
|
) || invidious.streamingUrls.find((s: any) => s.type?.includes("audio"));
|
||||||
if (audio) {
|
if (audio) {
|
||||||
audioUrl = audio.url;
|
audioUrl = audio.url;
|
||||||
|
instance = invidious.instance || "";
|
||||||
contentType = audio.type?.split(";")[0] || "audio/mp4";
|
contentType = audio.type?.split(";")[0] || "audio/mp4";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!audioUrl) {
|
if (!audioUrl) {
|
||||||
const invidious = await fetchFromInvidious(id);
|
const piped = await fetchFromPiped(id);
|
||||||
if (invidious.success && invidious.streamingUrls) {
|
if (piped.success && piped.streamingUrls) {
|
||||||
const audio = invidious.streamingUrls.find((s: any) =>
|
const audio = piped.streamingUrls.find((s: any) =>
|
||||||
s.type?.includes("audio/mp4") && s.audioQuality === "AUDIO_QUALITY_MEDIUM"
|
s.type?.includes("audio/mp4") && s.audioQuality === "AUDIO_QUALITY_MEDIUM"
|
||||||
) || invidious.streamingUrls.find((s: any) => s.type?.includes("audio"));
|
) || piped.streamingUrls.find((s: any) => s.type?.includes("audio"));
|
||||||
if (audio) {
|
if (audio) {
|
||||||
audioUrl = audio.url;
|
audioUrl = audio.url;
|
||||||
|
instance = piped.instance || "";
|
||||||
contentType = audio.type?.split(";")[0] || "audio/mp4";
|
contentType = audio.type?.split(";")[0] || "audio/mp4";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,19 +299,31 @@ async function handler(req: Request): Promise<Response> {
|
|||||||
const ext = contentType.includes("webm") ? ".webm" : ".m4a";
|
const ext = contentType.includes("webm") ? ".webm" : ".m4a";
|
||||||
const filename = `${artist ? artist + " - " : ""}${title}`.replace(/[<>:"/\\|?*]/g, "").trim() + ext;
|
const filename = `${artist ? artist + " - " : ""}${title}`.replace(/[<>:"/\\|?*]/g, "").trim() + ext;
|
||||||
|
|
||||||
// Redirect to audio URL - browser will handle download
|
// Proxy the download through our server
|
||||||
if (redirect) {
|
try {
|
||||||
return new Response(null, {
|
const response = await fetch(audioUrl, {
|
||||||
status: 302,
|
|
||||||
headers: {
|
headers: {
|
||||||
"Location": audioUrl,
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
||||||
...corsHeaders,
|
"Accept": "*/*",
|
||||||
|
"Referer": instance || "https://www.youtube.com/",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Return URL for client to handle
|
if (!response.ok) {
|
||||||
return json({ success: true, url: audioUrl, filename, contentType });
|
return json({ success: false, error: `Failed to fetch audio: ${response.status}` }, 502);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(response.body, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": contentType,
|
||||||
|
"Content-Disposition": `attachment; filename="${encodeURIComponent(filename)}"`,
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
"Access-Control-Expose-Headers": "Content-Disposition",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
return json({ success: false, error: "Download failed: " + String(err) }, 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ LYRICS & INFO ============
|
// ============ LYRICS & INFO ============
|
||||||
|
|||||||
23
ui.ts
23
ui.ts
@@ -327,25 +327,12 @@ function render(f,append){
|
|||||||
else el.innerHTML=html;
|
else el.innerHTML=html;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function download(i){
|
function download(i){
|
||||||
var s=songs[i];if(!s||!s.videoId)return;
|
var s=songs[i];if(!s||!s.videoId)return;
|
||||||
var btn=document.querySelectorAll('.dl-btn')[i];
|
var title=encodeURIComponent(s.title||'audio');
|
||||||
if(btn){btn.textContent='...';btn.disabled=true;}
|
var artist=encodeURIComponent(s.artists?.map(a=>a.name).join(', ')||'');
|
||||||
try{
|
// Open download in new tab - server will proxy the audio
|
||||||
var res=await fetch('/api/download?id='+s.videoId+'&redirect=0');
|
window.open('/api/download?id='+s.videoId+'&title='+title+'&artist='+artist,'_blank');
|
||||||
var data=await res.json();
|
|
||||||
if(!data.success||!data.url){alert('Download failed: '+(data.error||'No URL'));return;}
|
|
||||||
// Create download link
|
|
||||||
var a=document.createElement('a');
|
|
||||||
a.href=data.url;
|
|
||||||
a.download=data.filename||'audio.m4a';
|
|
||||||
a.target='_blank';
|
|
||||||
a.rel='noopener';
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
document.body.removeChild(a);
|
|
||||||
}catch(e){alert('Download error');}
|
|
||||||
finally{if(btn){btn.textContent='↓';btn.disabled=false;}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function play(i){
|
function play(i){
|
||||||
|
|||||||
Reference in New Issue
Block a user