spotify-uri
Version:
Parse the various Spotify URI formats into Objects and back
260 lines (247 loc) • 6.33 kB
JavaScript
// src/util.ts
function decode(str) {
return decodeURIComponent(str.replace(/\+/g, " "));
}
function encode(str) {
return encodeURIComponent(str).replace(/%20/g, "+").replace(/[!'()*]/g, escape);
}
// src/spotify-uri.ts
var SpotifyUri = class {
type;
id;
uri;
constructor(uri, id, type) {
this.uri = uri;
this.id = id;
this.type = type;
}
static is(v) {
return typeof v === "object" && typeof v.uri === "string";
}
toURI() {
return `spotify:${this.type}:${encode(this.id)}`;
}
toURL() {
return `/${this.type}/${encode(this.id)}`;
}
toEmbedURL() {
return `https://embed.spotify.com/?uri=${this.toURI()}`;
}
toOpenURL() {
return `https://open.spotify.com${this.toURL()}`;
}
toPlayURL() {
return `https://play.spotify.com${this.toURL()}`;
}
};
// src/local.ts
var Local = class extends SpotifyUri {
artist;
album;
track;
seconds;
constructor(uri, artist, album, track, seconds) {
super(uri, "", "local" /* Local */);
this.artist = artist;
this.album = album;
this.track = track;
this.seconds = seconds;
}
static is(v) {
return typeof v === "object" && v.type === "local";
}
toURI() {
return `spotify:${this.type}:${encode(this.artist)}:${encode(
this.album
)}:${encode(this.track)}:${this.seconds}`;
}
toURL() {
return `/${this.type}/${encode(this.artist)}/${encode(this.album)}/${encode(
this.track
)}/${this.seconds}`;
}
};
// src/search.ts
var Search = class extends SpotifyUri {
get query() {
return this.id;
}
static is(v) {
return typeof v === "object" && v.type === "search";
}
};
// src/playlist.ts
var Playlist = class extends SpotifyUri {
user;
constructor(uri, id, user) {
super(uri, id, "playlist" /* Playlist */);
if (typeof user === "string") {
this.user = user;
}
}
static is(v) {
return typeof v === "object" && v.type === "playlist";
}
toURI() {
if (this.user !== void 0) {
if (this.id === "starred") {
return `spotify:user:${encode(this.user)}:${encode(this.id)}`;
}
return `spotify:user:${encode(this.user)}:playlist:${encode(this.id)}`;
}
return `spotify:playlist:${encode(this.id)}`;
}
toURL() {
if (this.user !== void 0) {
if (this.id === "starred") {
return `/user/${encode(this.user)}/${encode(this.id)}`;
}
return `/user/${encode(this.user)}/playlist/${encode(this.id)}`;
}
return `/playlist/${encode(this.id)}`;
}
};
// src/artist.ts
var Artist = class extends SpotifyUri {
static is(v) {
return typeof v === "object" && v.type === "artist";
}
};
// src/album.ts
var Album = class extends SpotifyUri {
static is(v) {
return typeof v === "object" && v.type === "album";
}
};
// src/track.ts
var Track = class extends SpotifyUri {
static is(v) {
return typeof v === "object" && v.type === "track";
}
};
// src/episode.ts
var Episode = class extends SpotifyUri {
static is(v) {
return typeof v === "object" && v.type === "episode";
}
};
// src/show.ts
var Show = class extends SpotifyUri {
static is(v) {
return typeof v === "object" && v.type === "show";
}
};
// src/user.ts
var User = class extends SpotifyUri {
get user() {
return this.id;
}
static is(v) {
return typeof v === "object" && v.type === "user";
}
};
// src/parse.ts
function parse(input) {
const uri = SpotifyUri.is(input) ? input.uri : input;
const { protocol, hostname, pathname = "/", searchParams } = new URL(uri);
if (hostname === "embed.spotify.com") {
const parsedQs = Object.fromEntries(searchParams);
if (typeof parsedQs.uri !== "string") {
throw new Error(
"Parsed query string was not valid: " + searchParams.toString()
);
}
return parse(parsedQs.uri);
}
if (protocol === "spotify:") {
const parts2 = uri.split(":");
return parseParts(uri, parts2);
}
if (pathname === null) {
throw new TypeError("No pathname");
}
const parts = pathname.split("/");
return parseParts(uri, parts);
}
function parseParts(uri, parts) {
parts = parts.filter((p) => !p.startsWith("intl"));
let spotifyType = parts[1];
if (spotifyType === "embed" /* Embed */) {
parts = parts.slice(1);
spotifyType = parts[1];
}
const len = parts.length;
if (spotifyType === "search" /* Search */) {
return new Search(uri, decode(parts.slice(2).join(":")), spotifyType);
}
if (len >= 3 && spotifyType === "local" /* Local */) {
return new Local(
uri,
decode(parts[2]),
decode(parts[3]),
decode(parts[4]),
+parts[5]
);
}
if (len >= 4 || spotifyType === "playlist" /* Playlist */) {
if (len >= 5) {
return new Playlist(uri, decode(parts[4]), decode(parts[2]));
}
if (parts[3] === "starred") {
return new Playlist(uri, "starred", decode(parts[2]));
}
return new Playlist(uri, decode(parts[2]));
}
if (len === 3 && spotifyType === "user" /* User */) {
return new User(uri, decode(parts[2]), spotifyType);
}
if (spotifyType === "artist" /* Artist */) {
return new Artist(uri, parts[2], spotifyType);
}
if (spotifyType === "album" /* Album */) {
return new Album(uri, parts[2], spotifyType);
}
if (spotifyType === "track" /* Track */) {
return new Track(uri, parts[2], spotifyType);
}
if (spotifyType === "episode" /* Episode */) {
return new Episode(uri, parts[2], spotifyType);
}
if (spotifyType === "show" /* Show */) {
return new Show(uri, parts[2], spotifyType);
}
throw new TypeError(`Could not determine type for: ${uri}`);
}
// src/index.ts
function formatURI(input) {
const uri = typeof input === "string" ? parse(input) : input;
return uri.toURI();
}
function formatEmbedURL(input) {
const uri = typeof input === "string" ? parse(input) : input;
return uri.toEmbedURL();
}
function formatOpenURL(input) {
const uri = typeof input === "string" ? parse(input) : input;
return uri.toOpenURL();
}
function formatPlayURL(input) {
const uri = typeof input === "string" ? parse(input) : input;
return uri.toPlayURL();
}
export {
Album,
Artist,
Episode,
Local,
Playlist,
Search,
Show,
Track,
User,
formatEmbedURL,
formatOpenURL,
formatPlayURL,
formatURI,
parse
};