Ability to list tracks on an album

This commit is contained in:
simojenki
2021-03-08 11:26:24 +11:00
parent 07b00f00f2
commit 081819f12b
8 changed files with 361 additions and 76 deletions

View File

@@ -34,6 +34,12 @@ export type Images = {
large: string | undefined;
};
export const NO_IMAGES: Images = {
small: undefined,
medium: undefined,
large: undefined
}
export type Artist = ArtistSummary & {
albums: AlbumSummary[];
};
@@ -46,7 +52,6 @@ export type AlbumSummary = {
};
export type Album = AlbumSummary & {
tracks: Track[]
};
export type Track = {
@@ -54,6 +59,10 @@ export type Track = {
name: string;
mimeType: string;
duration: string;
number: string | undefined;
genre: string | undefined;
album: AlbumSummary;
artist: ArtistSummary
};
export type Paging = {
@@ -114,5 +123,6 @@ export interface MusicLibrary {
artist(id: string): Promise<Artist>;
albums(q: AlbumQuery): Promise<Result<AlbumSummary>>;
album(id: string): Promise<Album>;
tracks(albumId: string): Promise<Track[]>;
genres(): Promise<string[]>;
}

View File

@@ -16,6 +16,7 @@ import {
MusicLibrary,
Images,
AlbumSummary,
NO_IMAGES,
} from "./music_service";
import X2JS from "x2js";
@@ -58,7 +59,7 @@ export type artistSummary = {
_name: string;
_albumCount: string;
_artistImageUrl: string | undefined;
}
};
export type GetArtistsResponse = SubsonicResponse & {
artists: {
@@ -118,31 +119,33 @@ export type GetArtistResponse = SubsonicResponse & {
};
export type song = {
"_id": string,
"_parent": string,
"_title": string,
"_album": string,
"_artist": string,
"_coverArt": string,
"_created": "2004-11-08T23:36:11",
"_duration": string,
"_bitRate": "128",
"_suffix": "mp3",
"_contentType": string,
"_albumId": string,
"_artistId": string,
"_type": "music"
}
_id: string;
_parent: string;
_title: string;
_album: string;
_artist: string;
_track: string;
_genre: string;
_coverArt: string;
_created: "2004-11-08T23:36:11";
_duration: string;
_bitRate: "128";
_suffix: "mp3";
_contentType: string;
_albumId: string;
_artistId: string;
_type: "music";
};
export type GetAlbumResponse = {
album: {
_id: string,
_name: string,
_genre: string,
_year: string,
song: song[]
}
}
_id: string;
_name: string;
_genre: string;
_year: string;
song: song[];
};
};
export function isError(
subsonicResponse: SubsonicResponse
@@ -329,29 +332,57 @@ export class Navidrome implements MusicService {
total: Math.min(MAX_ALBUM_LIST, total),
}));
},
album: (id: string): Promise<Album> => navidrome
.get<GetAlbumResponse>(credentials, "/rest/getAlbum", { id })
.then(it => it.album)
.then(album => ({
id: album._id,
name: album._name,
year: album._year,
genre: album._genre,
tracks: album.song.map(track => ({
id: track._id,
name: track._title,
mimeType: track._contentType,
duration: track._duration,
}))
})),
album: (id: string): Promise<Album> =>
navidrome
.get<GetAlbumResponse>(credentials, "/rest/getAlbum", { id })
.then((it) => it.album)
.then((album) => ({
id: album._id,
name: album._name,
year: album._year,
genre: album._genre,
// tracks: album.song.map(track => ({
// id: track._id,
// name: track._title,
// mimeType: track._contentType,
// duration: track._duration,
// }))
})),
genres: () =>
navidrome
.get<GenGenresResponse>(credentials, "/rest/getGenres")
.then((it) => pipe(
it.genres.genre,
A.map(it => it.__text),
A.sort(ordString)
)),
.then((it) =>
pipe(
it.genres.genre,
A.map((it) => it.__text),
A.sort(ordString)
)
),
tracks: (albumId: string) =>
navidrome
.get<GetAlbumResponse>(credentials, "/rest/getAlbum", { id: albumId })
.then((it) => it.album)
.then((album) =>
album.song.map((song) => ({
id: song._id,
name: song._title,
mimeType: song._contentType,
duration: song._duration,
number: song._track,
genre: song._genre,
album: {
id: album._id,
name: album._name,
year: album._year,
genre: album._genre,
},
artist: {
id: song._artistId,
name: song._artist,
image: NO_IMAGES,
},
}))
),
};
return Promise.resolve(musicLibrary);

View File

@@ -11,6 +11,7 @@ import {
MusicLibrary,
MusicService,
slice2,
Track,
} from "./music_service";
export const LOGIN_ROUTE = "/login";
@@ -168,7 +169,7 @@ const genre = (genre: string) => ({
itemType: "container",
id: `genre:${genre}`,
title: genre,
})
});
const album = (album: AlbumSummary) => ({
itemType: "album",
@@ -182,6 +183,27 @@ const album = (album: AlbumSummary) => ({
// }
});
const track = (track: Track) => ({
itemType: "track",
id: `track:${track.id}`,
mimeType: track.mimeType,
title: track.name,
trackMetadata: {
album: track.album.name,
albumId: track.album.id,
albumArtist: track.artist.name,
albumArtistId: track.artist.id,
// albumArtURI
artist: track.artist.name,
artistId: track.artist.id,
duration: track.duration,
genre: track.album.genre,
// genreId
trackNumber: track.number,
},
});
type SoapyHeaders = {
credentials?: Credentials;
};
@@ -280,8 +302,8 @@ function bindSmapiSoapServiceToExpress(
index: paging._index,
total,
})
);
case "artist":
);
case "artist":
return await musicLibrary
.artist(typeId!)
.then((artist) => artist.albums)
@@ -289,7 +311,18 @@ function bindSmapiSoapServiceToExpress(
.then(([page, total]) =>
getMetadataResult({
mediaCollection: page.map(album),
index: 0,
index: paging._index,
total,
})
);
case "album":
return await musicLibrary
.tracks(typeId!)
.then(slice2(paging))
.then(([page, total]) =>
getMetadataResult({
mediaCollection: page.map(track),
index: paging._index,
total,
})
);