mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
album art when playing track
This commit is contained in:
27
src/smapi.ts
27
src/smapi.ts
@@ -221,7 +221,7 @@ const album = (
|
|||||||
albumArtURI: `${webAddress}/album/${album.id}/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessToken}`,
|
albumArtURI: `${webAddress}/album/${album.id}/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessToken}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const track = (track: Track) => ({
|
export const track = (webAddress: string, accessToken: string, track: Track) => ({
|
||||||
itemType: "track",
|
itemType: "track",
|
||||||
id: `track:${track.id}`,
|
id: `track:${track.id}`,
|
||||||
mimeType: track.mimeType,
|
mimeType: track.mimeType,
|
||||||
@@ -232,7 +232,7 @@ const track = (track: Track) => ({
|
|||||||
albumId: track.album.id,
|
albumId: track.album.id,
|
||||||
albumArtist: track.artist.name,
|
albumArtist: track.artist.name,
|
||||||
albumArtistId: track.artist.id,
|
albumArtistId: track.artist.id,
|
||||||
// albumArtURI
|
albumArtURI: `${webAddress}/album/${track.album.id}/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessToken}`,
|
||||||
artist: track.artist.name,
|
artist: track.artist.name,
|
||||||
artistId: track.artist.id,
|
artistId: track.artist.id,
|
||||||
duration: track.duration,
|
duration: track.duration,
|
||||||
@@ -314,6 +314,7 @@ function bindSmapiSoapServiceToExpress(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
const authToken = headers.credentials.loginToken.token;
|
||||||
const login = await musicService
|
const login = await musicService
|
||||||
.login(headers.credentials.loginToken.token)
|
.login(headers.credentials.loginToken.token)
|
||||||
.catch((_) => {
|
.catch((_) => {
|
||||||
@@ -327,9 +328,12 @@ function bindSmapiSoapServiceToExpress(
|
|||||||
|
|
||||||
const typeId = id.split(":")[1];
|
const typeId = id.split(":")[1];
|
||||||
const musicLibrary = login as MusicLibrary;
|
const musicLibrary = login as MusicLibrary;
|
||||||
return musicLibrary
|
return musicLibrary.track(typeId!).then((it) => {
|
||||||
.track(typeId!)
|
const accessToken = accessTokens.mint(authToken);
|
||||||
.then((it) => ({ getMediaMetadataResult: track(it) }));
|
return {
|
||||||
|
getMediaMetadataResult: track(webAddress, accessToken, it),
|
||||||
|
};
|
||||||
|
});
|
||||||
},
|
},
|
||||||
getMetadata: async (
|
getMetadata: async (
|
||||||
{
|
{
|
||||||
@@ -430,13 +434,16 @@ function bindSmapiSoapServiceToExpress(
|
|||||||
return await musicLibrary
|
return await musicLibrary
|
||||||
.tracks(typeId!)
|
.tracks(typeId!)
|
||||||
.then(slice2(paging))
|
.then(slice2(paging))
|
||||||
.then(([page, total]) =>
|
.then(([page, total]) => {
|
||||||
getMetadataResult2({
|
const accessToken = accessTokens.mint(authToken);
|
||||||
mediaMetadata: page.map(track),
|
return getMetadataResult2({
|
||||||
|
mediaMetadata: page.map((it) =>
|
||||||
|
track(webAddress, accessToken, it)
|
||||||
|
),
|
||||||
index: paging._index,
|
index: paging._index,
|
||||||
total,
|
total,
|
||||||
})
|
});
|
||||||
);
|
});
|
||||||
default:
|
default:
|
||||||
throw `Unsupported id:${id}`;
|
throw `Unsupported id:${id}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { v4 as uuid } from "uuid";
|
|||||||
|
|
||||||
import { DOMParserImpl } from "xmldom-ts";
|
import { DOMParserImpl } from "xmldom-ts";
|
||||||
import * as xpath from "xpath-ts";
|
import * as xpath from "xpath-ts";
|
||||||
|
import { randomInt } from "crypto";
|
||||||
|
|
||||||
import { InMemoryLinkCodes, LinkCodes } from "../src/link_codes";
|
import { InMemoryLinkCodes, LinkCodes } from "../src/link_codes";
|
||||||
import makeServer, { BONOB_ACCESS_TOKEN_HEADER } from "../src/server";
|
import makeServer, { BONOB_ACCESS_TOKEN_HEADER } from "../src/server";
|
||||||
@@ -16,6 +17,7 @@ import {
|
|||||||
getMetadataResult2,
|
getMetadataResult2,
|
||||||
PRESENTATION_MAP_ROUTE,
|
PRESENTATION_MAP_ROUTE,
|
||||||
SONOS_RECOMMENDED_IMAGE_SIZES,
|
SONOS_RECOMMENDED_IMAGE_SIZES,
|
||||||
|
track,
|
||||||
} from "../src/smapi";
|
} from "../src/smapi";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -124,6 +126,43 @@ describe("getMetadataResult", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("track", () => {
|
||||||
|
it("should map into a sonos expected track", () => {
|
||||||
|
const webAddress = "http://localhost:4567";
|
||||||
|
const accessToken = uuid();
|
||||||
|
const someTrack = aTrack({
|
||||||
|
id: uuid(),
|
||||||
|
mimeType: "audio/something",
|
||||||
|
name: "great song",
|
||||||
|
duration: randomInt(1000),
|
||||||
|
number: randomInt(100),
|
||||||
|
album: anAlbum({ name: "great album", id: uuid(), genre: "some genre" }),
|
||||||
|
artist: anArtist({ name: "great artist", id: uuid() }),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(track(webAddress, accessToken, someTrack)).toEqual({
|
||||||
|
itemType: "track",
|
||||||
|
id: `track:${someTrack.id}`,
|
||||||
|
mimeType: someTrack.mimeType,
|
||||||
|
title: someTrack.name,
|
||||||
|
|
||||||
|
trackMetadata: {
|
||||||
|
album: someTrack.album.name,
|
||||||
|
albumId: someTrack.album.id,
|
||||||
|
albumArtist: someTrack.artist.name,
|
||||||
|
albumArtistId: someTrack.artist.id,
|
||||||
|
albumArtURI: `${webAddress}/album/${someTrack.album.id}/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessToken}`,
|
||||||
|
artist: someTrack.artist.name,
|
||||||
|
artistId: someTrack.artist.id,
|
||||||
|
duration: someTrack.duration,
|
||||||
|
genre: someTrack.album.genre,
|
||||||
|
// genreId
|
||||||
|
trackNumber: someTrack.number,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
class Base64AccessTokens implements AccessTokens {
|
class Base64AccessTokens implements AccessTokens {
|
||||||
mint(authToken: string) {
|
mint(authToken: string) {
|
||||||
return Buffer.from(authToken).toString("base64");
|
return Buffer.from(authToken).toString("base64");
|
||||||
@@ -611,31 +650,6 @@ describe("api", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// describe("asking for an album by id", () => {
|
|
||||||
// it("should return it", async () => {
|
|
||||||
// musicService.hasArtists(BLONDIE, BOB_MARLEY);
|
|
||||||
// const album = BOB_MARLEY.albums[0]!;
|
|
||||||
|
|
||||||
// const result = await ws.getMetadataAsync({
|
|
||||||
// id: `album:${album.id}`,
|
|
||||||
// index: 0,
|
|
||||||
// count: 100,
|
|
||||||
// });
|
|
||||||
// expect(result).toEqual(
|
|
||||||
// getMetadataResult({
|
|
||||||
// mediaCollection: [
|
|
||||||
// ...BLONDIE.albums,
|
|
||||||
// ...BOB_MARLEY.albums,
|
|
||||||
// ].map((it) =>
|
|
||||||
// ({ itemType: "album", id: `album:${it.id}`, title: it.name })
|
|
||||||
// ),
|
|
||||||
// index: 0,
|
|
||||||
// total: BLONDIE.albums.length + BOB_MARLEY.albums.length,
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
describe("asking for albums", () => {
|
describe("asking for albums", () => {
|
||||||
const artist1 = anArtist({
|
const artist1 = anArtist({
|
||||||
albums: [anAlbum(), anAlbum(), anAlbum()],
|
albums: [anAlbum(), anAlbum(), anAlbum()],
|
||||||
@@ -740,27 +754,14 @@ describe("api", () => {
|
|||||||
});
|
});
|
||||||
expect(result[0]).toEqual(
|
expect(result[0]).toEqual(
|
||||||
getMetadataResult2({
|
getMetadataResult2({
|
||||||
mediaMetadata: [track1, track2, track3, track4, track5].map(
|
mediaMetadata: [
|
||||||
(track) => ({
|
track1,
|
||||||
itemType: "track",
|
track2,
|
||||||
id: `track:${track.id}`,
|
track3,
|
||||||
mimeType: track.mimeType,
|
track4,
|
||||||
title: track.name,
|
track5,
|
||||||
|
].map((it) =>
|
||||||
trackMetadata: {
|
track(rootUrl, accessTokens.mint(token.authToken), it)
|
||||||
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,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
),
|
),
|
||||||
index: 0,
|
index: 0,
|
||||||
total: 5,
|
total: 5,
|
||||||
@@ -778,26 +779,7 @@ describe("api", () => {
|
|||||||
});
|
});
|
||||||
expect(result[0]).toEqual(
|
expect(result[0]).toEqual(
|
||||||
getMetadataResult2({
|
getMetadataResult2({
|
||||||
mediaMetadata: [track3, track4].map((track) => ({
|
mediaMetadata: [track3, track4].map(it => track(rootUrl, accessTokens.mint(token.authToken), it)),
|
||||||
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,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
index: 2,
|
index: 2,
|
||||||
total: 5,
|
total: 5,
|
||||||
})
|
})
|
||||||
@@ -980,7 +962,7 @@ describe("api", () => {
|
|||||||
const artist = anArtist({
|
const artist = anArtist({
|
||||||
albums: [album],
|
albums: [album],
|
||||||
});
|
});
|
||||||
const track = aTrack();
|
const someTrack = aTrack();
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
musicService.hasUser({ username, password });
|
musicService.hasUser({ username, password });
|
||||||
@@ -995,35 +977,16 @@ describe("api", () => {
|
|||||||
ws.addSoapHeader({ credentials: someCredentials(token.authToken) });
|
ws.addSoapHeader({ credentials: someCredentials(token.authToken) });
|
||||||
|
|
||||||
musicService.hasArtists(artist);
|
musicService.hasArtists(artist);
|
||||||
musicService.hasTracks(track);
|
musicService.hasTracks(someTrack);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("asking for media metadata for a tack", () => {
|
describe("asking for media metadata for a track", () => {
|
||||||
it("should return it with auth header", async () => {
|
it("should return it with auth header", async () => {
|
||||||
const root = await ws.getMediaMetadataAsync({
|
const root = await ws.getMediaMetadataAsync({
|
||||||
id: `track:${track.id}`,
|
id: `track:${someTrack.id}`,
|
||||||
});
|
});
|
||||||
expect(root[0]).toEqual({
|
expect(root[0]).toEqual({
|
||||||
getMediaMetadataResult: {
|
getMediaMetadataResult: track(rootUrl, accessTokens.mint(token.authToken), someTrack),
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user