- 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
34 lines
1.1 KiB
TypeScript
34 lines
1.1 KiB
TypeScript
import { z } from "zod";
|
|
import superjson from "superjson";
|
|
|
|
const spotifyLink = z
|
|
.string()
|
|
.trim()
|
|
.regex(
|
|
/^(https:\/\/open\.spotify\.com\/(intl-[a-z-]+\/)?(track|playlist|album)\/[A-Za-z0-9]+(\?\S*)?|spotify:(track|playlist|album):[A-Za-z0-9]+)$/,
|
|
"Enter a Spotify track, album or playlist link.",
|
|
);
|
|
|
|
export const schema = z.object({
|
|
urls: z.array(spotifyLink).min(1).max(1000),
|
|
kind: z.enum(["track", "playlist"]),
|
|
name: z.string().max(200).optional(),
|
|
});
|
|
|
|
export type InputType = z.infer<typeof schema>;
|
|
export type OutputType = { jobId: string };
|
|
|
|
export async function postSpotifyDownload(body: InputType): Promise<OutputType> {
|
|
const validated = schema.parse(body);
|
|
const response = await fetch("/_api/spotify-download", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: superjson.stringify(validated),
|
|
});
|
|
if (!response.ok) {
|
|
const parsed = (await response.json().catch(() => ({}))) as { error?: string };
|
|
throw new Error(parsed.error || "Unable to start the download.");
|
|
}
|
|
return superjson.parse<OutputType>(await response.text());
|
|
}
|