Aurora SpotiRip desktop and web app
- Spotify playlist, library, album and artist browsing with in-app playback - Song, playlist and album downloads via spotdl with YouTube and Bandcamp fallbacks - Electron desktop app (castLabs Widevine) with a permanent sidebar layout - Linux and Windows packaging scripts
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import superjson from "superjson";
|
||||
import { schema, type OutputType } from "./identify_POST.schema";
|
||||
|
||||
type AudDResult = {
|
||||
artist?: string;
|
||||
title?: string;
|
||||
album?: string;
|
||||
release_date?: string;
|
||||
label?: string;
|
||||
timecode?: string;
|
||||
song_link?: string;
|
||||
spotify?: {
|
||||
uri?: string;
|
||||
track_number?: number;
|
||||
disc_number?: number;
|
||||
external_ids?: { isrc?: string };
|
||||
external_urls?: { spotify?: string };
|
||||
album?: { images?: Array<{ url?: string }> };
|
||||
};
|
||||
};
|
||||
|
||||
type AudDResponse = {
|
||||
status?: string;
|
||||
result?: AudDResult | null;
|
||||
error?: { error_message?: string };
|
||||
};
|
||||
|
||||
export async function handle(request: Request) {
|
||||
try {
|
||||
const apiToken = process.env.AUDD_API_TOKEN;
|
||||
if (!apiToken) {
|
||||
return new Response(
|
||||
superjson.stringify({ error: "Music recognition is not connected yet." }),
|
||||
{ status: 503 },
|
||||
);
|
||||
}
|
||||
|
||||
const incoming = await request.formData();
|
||||
const parsed = schema.parse({ file: incoming.get("file") });
|
||||
const file = parsed.file;
|
||||
|
||||
const outgoing = new FormData();
|
||||
outgoing.append("api_token", apiToken);
|
||||
outgoing.append("file", file, file.name);
|
||||
outgoing.append("return", "spotify,musicbrainz");
|
||||
|
||||
const response = await fetch("https://api.audd.io/", {
|
||||
method: "POST",
|
||||
body: outgoing,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return new Response(
|
||||
superjson.stringify({ error: `Recognition service returned HTTP ${response.status}.` }),
|
||||
{ status: 502 },
|
||||
);
|
||||
}
|
||||
|
||||
const body = (await response.json()) as AudDResponse;
|
||||
if (body.status !== "success") {
|
||||
const detail = body.error?.error_message || "";
|
||||
if (detail.toLowerCase().includes("audio fingerprint")) {
|
||||
return new Response(superjson.stringify({ matched: false } satisfies OutputType));
|
||||
}
|
||||
return new Response(
|
||||
superjson.stringify({
|
||||
error: detail || "Recognition service could not process this file.",
|
||||
}),
|
||||
{ status: 502 },
|
||||
);
|
||||
}
|
||||
|
||||
if (!body.result) {
|
||||
return new Response(superjson.stringify({ matched: false } satisfies OutputType));
|
||||
}
|
||||
|
||||
const match = body.result;
|
||||
const artworkUrl = match.spotify?.album?.images?.find((image) => image.url)?.url;
|
||||
const result: OutputType = {
|
||||
matched: true,
|
||||
title: match.title,
|
||||
artist: match.artist,
|
||||
album: match.album,
|
||||
releaseDate: match.release_date,
|
||||
label: match.label,
|
||||
timecode: match.timecode,
|
||||
songLink: match.song_link,
|
||||
artworkUrl,
|
||||
spotifyUri: match.spotify?.uri,
|
||||
spotifyUrl: match.spotify?.external_urls?.spotify,
|
||||
trackNumber: match.spotify?.track_number,
|
||||
discNumber: match.spotify?.disc_number,
|
||||
isrc: match.spotify?.external_ids?.isrc,
|
||||
};
|
||||
|
||||
return new Response(superjson.stringify(result));
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Unable to identify audio.";
|
||||
return new Response(superjson.stringify({ error: message }), { status: 400 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user