Skip to content

Commit

Permalink
spotify mp3 and lyrics page
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeltikhonovsky committed Feb 24, 2025
1 parent 2905d99 commit 86f8c9e
Show file tree
Hide file tree
Showing 5 changed files with 397 additions and 0 deletions.
Binary file modified bun.lockb
Binary file not shown.
27 changes: 27 additions & 0 deletions src/app/api/spotify/download/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
try {
const { url } = await request.json();

const response = await fetch(
"https://zylalabs.com/api/4117/spotify+track+download+api/4970/download",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MUSIC_DOWNLOAD_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ url }),
},
);

const data = await response.json();
return NextResponse.json(data);
} catch (error) {
return NextResponse.json(
{ error: "Failed to download track" },
{ status: 500 },
);
}
}
83 changes: 83 additions & 0 deletions src/app/api/spotify/lyrics/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { name, artists } = body;

const searchResponse = await fetch(
`https://api.genius.com/search?q=${encodeURIComponent(
`${name} ${artists[0].name}`,
)}`,
{
headers: {
Authorization: `Bearer ${process.env.GENIUS_ACCESS_TOKEN}`,
},
},
);

const searchData = await searchResponse.json();

if (!searchData.response.hits.length) {
return NextResponse.json({ error: "No lyrics found" });
}

const songHit = searchData.response.hits.find((hit: any) => {
const result = hit.result;
return (
result.title.toLowerCase().includes(name.toLowerCase()) ||
name.toLowerCase().includes(result.title.toLowerCase())
);
});

if (!songHit) {
return NextResponse.json({ error: "No matching song lyrics found" });
}

const hit = songHit.result;

const lyricsResponse = await fetch(hit.url);
const html = await lyricsResponse.text();

const lyricsMatch = html.match(
/data-lyrics-container[^>]*>([\s\S]*?)<\/div>|class="lyrics"[^>]*>([\s\S]*?)<\/div>/g,
);

if (!lyricsMatch) {
return NextResponse.json({
lyrics: `Unable to extract lyrics automatically.\nView lyrics at: ${hit.url}`,
title: hit.title,
artist: hit.primary_artist.name,
url: hit.url,
});
}

const lyrics = lyricsMatch
.join("\n")
.replace(/<br\s*\/?>/g, "\n")
.replace(/<[^>]*>/g, "")
.replace(/\n{3,}/g, "\n\n")
.replace(/&amp;/g, "&")
.replace(/&quot;/g, '"')
.replace(/&#x27;/g, "'")
.replace(/&lt;/g, "<")
.replace(/&gt;/g, ">")
.replace(/data-lyrics-container="true" class="Lyrics-sc-[^"]*">/g, "")
.replace(/\[Produced by[^\n]*\]/g, "")
.trim();

return NextResponse.json({
lyrics,
title: hit.title,
artist: hit.primary_artist.name,
url: hit.url,
});
} catch (error) {
console.error("Lyrics fetch error:", error);
return NextResponse.json(
{ error: "Failed to fetch lyrics" },
{ status: 500 },
);
}
}
55 changes: 55 additions & 0 deletions src/app/api/spotify/search/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { NextRequest, NextResponse } from "next/server";

async function getSpotifyAccessToken() {
const client_id = process.env.SPOTIFY_CLIENT_ID!;
const client_secret = process.env.SPOTIFY_CLIENT_SECRET!;

const response = await fetch("https://accounts.spotify.com/api/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(
`${client_id}:${client_secret}`,
).toString("base64")}`,
},
body: new URLSearchParams({
grant_type: "client_credentials",
}),
});

const data = await response.json();
return data.access_token;
}

export async function GET(request: NextRequest) {
try {
const query = request.nextUrl.searchParams.get("q");
if (!query) {
return NextResponse.json(
{ error: "No search query provided" },
{ status: 400 },
);
}

const accessToken = await getSpotifyAccessToken();

const response = await fetch(
`https://api.spotify.com/v1/search?q=${encodeURIComponent(
query,
)}&type=track&limit=5`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
},
);

const data = await response.json();
return NextResponse.json(data);
} catch (error) {
return NextResponse.json(
{ error: "Failed to search tracks" },
{ status: 500 },
);
}
}
Loading

0 comments on commit 86f8c9e

Please # to comment.