102 lines
2.4 KiB
TypeScript
102 lines
2.4 KiB
TypeScript
import {debug} from './debug.js';
|
|
import RelationLink from './relation-link.js';
|
|
|
|
type ApiReleaseData = {
|
|
'artist-credit': Array<{
|
|
name: string;
|
|
joinphrase: string;
|
|
}>;
|
|
'cover-art-archive': {
|
|
front: boolean;
|
|
};
|
|
date: string | undefined;
|
|
id: string;
|
|
relations: Array<{
|
|
ended: boolean;
|
|
type: string;
|
|
url: {
|
|
resource: string;
|
|
};
|
|
}>;
|
|
title: string;
|
|
};
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
interface IRelease {
|
|
artist: string;
|
|
date: string | undefined;
|
|
image: string | undefined;
|
|
links: RelationLink[];
|
|
title: string;
|
|
}
|
|
|
|
export default interface Release extends IRelease {}
|
|
|
|
export default class Release {
|
|
public static async fromMbid(mbid: string): Promise<Release> {
|
|
const apiResponse = await window.fetch(this.apiUrl(mbid), {
|
|
headers: {
|
|
accept: 'application/json',
|
|
'user-agent': hrefPlusUserAgent,
|
|
},
|
|
});
|
|
|
|
if (!apiResponse.ok) {
|
|
throw new Error(`No release found with MBID ${mbid}`);
|
|
}
|
|
|
|
const data = (await apiResponse.json()) as ApiReleaseData;
|
|
debug(data);
|
|
|
|
const artist = data['artist-credit']
|
|
.map(({name, joinphrase}) => `${name}${joinphrase}`)
|
|
.join('');
|
|
|
|
const image = data['cover-art-archive'].front
|
|
? `https://coverartarchive.org/release/${mbid}/front-500`
|
|
: undefined;
|
|
|
|
const relations = new Set(
|
|
data.relations
|
|
// Remove discography entries and links that have been marked as no
|
|
// longer working.
|
|
.filter(
|
|
(relation) =>
|
|
relation.type !== 'discography entry' && !relation.ended,
|
|
)
|
|
.map((relation) => relation.url.resource),
|
|
);
|
|
const links = Array.from(relations)
|
|
.map((url) => new RelationLink(url))
|
|
.sort((a, b) =>
|
|
// Sort links that aren't known to us at the bottom.
|
|
a.isKnown === b.isKnown
|
|
? a.text.localeCompare(b.text)
|
|
: b.isKnown
|
|
? 1 // This return 1 or -1 is because .sort() expects a number.
|
|
: -1,
|
|
);
|
|
|
|
return new Release({
|
|
artist,
|
|
date: data.date,
|
|
image,
|
|
links,
|
|
title: data.title,
|
|
});
|
|
}
|
|
|
|
private static apiUrl(mbid: string): string {
|
|
const root = 'https://musicbrainz.org/ws/2';
|
|
return `${root}/release/${mbid}?inc=artists+url-rels`;
|
|
}
|
|
|
|
constructor(release: IRelease) {
|
|
Object.assign(this, release, {});
|
|
}
|
|
|
|
public display(): string {
|
|
return `${this.artist} - ${this.title}`;
|
|
}
|
|
}
|