Skip to content

Commit d5c9faa

Browse files
committed
Add tracks to musicbrainz API
1 parent 1cd1b63 commit d5c9faa

File tree

3 files changed

+62
-7
lines changed

3 files changed

+62
-7
lines changed

src/api/apis/MusicBrainzAPI.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type MediaDbPlugin from '../../main';
33
import type { MediaTypeModel } from '../../models/MediaTypeModel';
44
import { MusicReleaseModel } from '../../models/MusicReleaseModel';
55
import { MediaType } from '../../utils/MediaType';
6-
import { contactEmail, mediaDbVersion, pluginName } from '../../utils/Utils';
6+
import { contactEmail, extractTracksFromMedia, mediaDbVersion, pluginName } from '../../utils/Utils';
77
import { APIModel } from '../APIModel';
88

99
// sadly no open api schema available
@@ -136,19 +136,44 @@ export class MusicBrainzAPI extends APIModel {
136136
async getById(id: string): Promise<MediaTypeModel> {
137137
console.log(`MDB | api "${this.apiName}" queried by ID`);
138138

139-
const searchUrl = `https://musicbrainz.org/ws/2/release-group/${encodeURIComponent(id)}?inc=releases+artists+tags+ratings+genres&fmt=json`;
140-
const fetchData = await requestUrl({
141-
url: searchUrl,
139+
// Fetch release group
140+
const groupUrl = `https://musicbrainz.org/ws/2/release-group/${encodeURIComponent(id)}?inc=releases+artists+tags+ratings+genres&fmt=json`;
141+
const groupResponse = await requestUrl({
142+
url: groupUrl,
142143
headers: {
143144
'User-Agent': `${pluginName}/${mediaDbVersion} (${contactEmail})`,
144145
},
145146
});
146147

147-
if (fetchData.status !== 200) {
148-
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
148+
if (groupResponse.status !== 200) {
149+
throw Error(`MDB | Received status code ${groupResponse.status} from ${this.apiName}.`);
150+
}
151+
152+
const result = (await groupResponse.json) as IdResponse;
153+
154+
// Get ID of the first release
155+
const firstRelease = result.releases?.[0];
156+
if (!firstRelease) {
157+
throw Error('MDB | No releases found in release group.');
158+
}
159+
160+
// Fetch recordings for the first release
161+
const releaseUrl = `https://musicbrainz.org/ws/2/release/${firstRelease.id}?inc=recordings+artists&fmt=json`;
162+
console.log(`MDB | Fetching release recordings from: ${releaseUrl}`);
163+
164+
const releaseResponse = await requestUrl({
165+
url: releaseUrl,
166+
headers: {
167+
'User-Agent': `${pluginName}/${mediaDbVersion} (${contactEmail})`,
168+
},
169+
});
170+
171+
if (releaseResponse.status !== 200) {
172+
throw Error(`MDB | Received status code ${releaseResponse.status} from ${this.apiName}.`);
149173
}
150174

151-
const result = (await fetchData.json) as IdResponse;
175+
const releaseData = await releaseResponse.json;
176+
const tracks = extractTracksFromMedia(releaseData.media);
152177

153178
return new MusicReleaseModel({
154179
type: 'musicRelease',
@@ -164,6 +189,7 @@ export class MusicBrainzAPI extends APIModel {
164189
artists: result['artist-credit'].map(a => a.name),
165190
genres: result.genres.map(g => g.name),
166191
subType: result['primary-type'],
192+
tracks: tracks,
167193
rating: result.rating.value * 2,
168194

169195
userData: {

src/models/MusicReleaseModel.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ export class MusicReleaseModel extends MediaTypeModel {
1111
image: string;
1212
rating: number;
1313
releaseDate: string;
14+
tracks: {
15+
number: number;
16+
title: string;
17+
duration: string;
18+
featuredArtists: string[];
19+
}[];
1420

1521
userData: {
1622
personalRating: number;
@@ -36,6 +42,7 @@ export class MusicReleaseModel extends MediaTypeModel {
3642
}
3743

3844
this.type = this.getMediaType();
45+
this.tracks = obj.tracks ?? [];
3946
}
4047

4148
getTags(): string[] {

src/utils/Utils.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,3 +296,25 @@ export async function obsidianFetch(input: Request): Promise<Response> {
296296
text: async () => res.text,
297297
} as Response;
298298
}
299+
export function extractTracksFromMedia(media: any[]): {
300+
number: number;
301+
title: string;
302+
duration: string;
303+
featuredArtists: string[];
304+
}[] {
305+
if (!media || media.length === 0 || !media[0].tracks) return [];
306+
307+
return media[0].tracks.map((track: any, index: number) => {
308+
const title = track.title || track.recording?.title || 'Unknown Title';
309+
const rawLength = track.length || track.recording?.length;
310+
const duration = rawLength ? new Date(rawLength).toISOString().substr(14, 5) : 'unknown';
311+
const featuredArtists = track['artist-credit']?.map((ac: { name: string }) => ac.name) ?? [];
312+
313+
return {
314+
number: index + 1,
315+
title,
316+
duration,
317+
featuredArtists,
318+
};
319+
});
320+
}

0 commit comments

Comments
 (0)