mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-22 01:43:29 +01:00
Ability to list tracks on an album
This commit is contained in:
@@ -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[]>;
|
||||
}
|
||||
|
||||
117
src/navidrome.ts
117
src/navidrome.ts
@@ -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);
|
||||
|
||||
41
src/smapi.ts
41
src/smapi.ts
@@ -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,
|
||||
})
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user