mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
sonos presentation xml image map for image resizing
This commit is contained in:
@@ -39,7 +39,9 @@
|
|||||||
"supertest": "^6.1.3",
|
"supertest": "^6.1.3",
|
||||||
"ts-jest": "^26.4.4",
|
"ts-jest": "^26.4.4",
|
||||||
"ts-mockito": "^2.6.1",
|
"ts-mockito": "^2.6.1",
|
||||||
"ts-node": "^9.1.1"
|
"ts-node": "^9.1.1",
|
||||||
|
"xmldom-ts": "^0.3.1",
|
||||||
|
"xpath-ts": "^1.3.13"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
SOAP_PATH,
|
SOAP_PATH,
|
||||||
STRINGS_ROUTE,
|
STRINGS_ROUTE,
|
||||||
PRESENTATION_MAP_ROUTE,
|
PRESENTATION_MAP_ROUTE,
|
||||||
|
SONOS_RECOMMENDED_IMAGE_SIZES,
|
||||||
LOGIN_ROUTE,
|
LOGIN_ROUTE,
|
||||||
} from "./smapi";
|
} from "./smapi";
|
||||||
import { LinkCodes, InMemoryLinkCodes } from "./link_codes";
|
import { LinkCodes, InMemoryLinkCodes } from "./link_codes";
|
||||||
@@ -101,19 +102,29 @@ function server(
|
|||||||
res.type("application/xml").send(`<?xml version="1.0" encoding="utf-8" ?>
|
res.type("application/xml").send(`<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<stringtables xmlns="http://sonos.com/sonosapi">
|
<stringtables xmlns="http://sonos.com/sonosapi">
|
||||||
<stringtable rev="1" xml:lang="en-US">
|
<stringtable rev="1" xml:lang="en-US">
|
||||||
<string stringId="AppLinkMessage">Linking sonos with bonob</string>
|
<string stringId="AppLinkMessage">Linking sonos with ${bonobService.name}</string>
|
||||||
<string stringId="string2">string2</string>
|
|
||||||
</stringtable>
|
</stringtable>
|
||||||
<stringtable rev="1" xml:lang="fr-FR">
|
<stringtable rev="1" xml:lang="fr-FR">
|
||||||
<string stringId="AppLinkMessage">Linking sonos with bonob fr</string>
|
<string stringId="AppLinkMessage">Lier les sonos à la ${bonobService.name}</string>
|
||||||
<string stringId="string2">string2 fr</string>
|
|
||||||
</stringtable>
|
</stringtable>
|
||||||
</stringtables>
|
</stringtables>
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get(PRESENTATION_MAP_ROUTE, (_, res) => {
|
app.get(PRESENTATION_MAP_ROUTE, (_, res) => {
|
||||||
res.send("");
|
res.type("application/xml").send(`<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Presentation>
|
||||||
|
<PresentationMap type="ArtWorkSizeMap">
|
||||||
|
<Match>
|
||||||
|
<imageSizeMap>
|
||||||
|
${SONOS_RECOMMENDED_IMAGE_SIZES.map(
|
||||||
|
(size) =>
|
||||||
|
`<sizeEntry size="${size}" substitution="/art/size/${size}"/>`
|
||||||
|
)}
|
||||||
|
</imageSizeMap>
|
||||||
|
</Match>
|
||||||
|
</PresentationMap>
|
||||||
|
</Presentation>`);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/stream/track/:id", async (req, res) => {
|
app.get("/stream/track/:id", async (req, res) => {
|
||||||
@@ -138,7 +149,7 @@ function server(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/album/:albumId/art", (req, res) => {
|
app.get("/album/:albumId/art/size/:size", (req, res) => {
|
||||||
const authToken = accessTokens.authTokenFor(
|
const authToken = accessTokens.authTokenFor(
|
||||||
req.query[BONOB_ACCESS_TOKEN_HEADER] as string
|
req.query[BONOB_ACCESS_TOKEN_HEADER] as string
|
||||||
);
|
);
|
||||||
@@ -147,7 +158,12 @@ function server(
|
|||||||
} else {
|
} else {
|
||||||
return musicService
|
return musicService
|
||||||
.login(authToken)
|
.login(authToken)
|
||||||
.then((it) => it.coverArt(req.params["albumId"]!, 200))
|
.then((it) =>
|
||||||
|
it.coverArt(
|
||||||
|
req.params["albumId"]!,
|
||||||
|
Number.parseInt(req.params["size"]!)
|
||||||
|
)
|
||||||
|
)
|
||||||
.then((coverArt) => {
|
.then((coverArt) => {
|
||||||
res.status(200);
|
res.status(200);
|
||||||
res.setHeader("content-type", coverArt.contentType);
|
res.setHeader("content-type", coverArt.contentType);
|
||||||
|
|||||||
17
src/smapi.ts
17
src/smapi.ts
@@ -20,6 +20,21 @@ export const LOGIN_ROUTE = "/login";
|
|||||||
export const SOAP_PATH = "/ws/sonos";
|
export const SOAP_PATH = "/ws/sonos";
|
||||||
export const STRINGS_ROUTE = "/sonos/strings.xml";
|
export const STRINGS_ROUTE = "/sonos/strings.xml";
|
||||||
export const PRESENTATION_MAP_ROUTE = "/sonos/presentationMap.xml";
|
export const PRESENTATION_MAP_ROUTE = "/sonos/presentationMap.xml";
|
||||||
|
export const SONOS_RECOMMENDED_IMAGE_SIZES = [
|
||||||
|
"60",
|
||||||
|
"80",
|
||||||
|
"120",
|
||||||
|
"180",
|
||||||
|
"192",
|
||||||
|
"200",
|
||||||
|
"230",
|
||||||
|
"300",
|
||||||
|
"600",
|
||||||
|
"640",
|
||||||
|
"750",
|
||||||
|
"1242",
|
||||||
|
"1500",
|
||||||
|
];
|
||||||
|
|
||||||
const WSDL_FILE = path.resolve(
|
const WSDL_FILE = path.resolve(
|
||||||
__dirname,
|
__dirname,
|
||||||
@@ -203,7 +218,7 @@ const album = (
|
|||||||
itemType: "album",
|
itemType: "album",
|
||||||
id: `album:${album.id}`,
|
id: `album:${album.id}`,
|
||||||
title: album.name,
|
title: album.name,
|
||||||
albumArtURI: `${webAddress}/album/${album.id}/art?${BONOB_ACCESS_TOKEN_HEADER}=${accessToken}`,
|
albumArtURI: `${webAddress}/album/${album.id}/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessToken}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const track = (track: Track) => ({
|
const track = (track: Track) => ({
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import { parse } from "node-html-parser";
|
|||||||
import { MusicService } from "@svrooij/sonos/lib/services";
|
import { MusicService } from "@svrooij/sonos/lib/services";
|
||||||
import { head } from "underscore";
|
import { head } from "underscore";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
import STRINGS from "./strings";
|
|
||||||
import { SOAP_PATH, STRINGS_ROUTE, PRESENTATION_MAP_ROUTE } from "./smapi";
|
import { SOAP_PATH, STRINGS_ROUTE, PRESENTATION_MAP_ROUTE } from "./smapi";
|
||||||
|
|
||||||
|
export const STRINGS_VERSION = "2";
|
||||||
|
export const PRESENTATION_MAP_VERSION = "7";
|
||||||
|
|
||||||
export type Device = {
|
export type Device = {
|
||||||
name: string;
|
name: string;
|
||||||
group: string;
|
group: string;
|
||||||
@@ -40,11 +42,11 @@ export const bonobService = (
|
|||||||
secureUri: `${stripTailingSlash(bonobRoot)}${SOAP_PATH}`,
|
secureUri: `${stripTailingSlash(bonobRoot)}${SOAP_PATH}`,
|
||||||
strings: {
|
strings: {
|
||||||
uri: `${stripTailingSlash(bonobRoot)}${STRINGS_ROUTE}`,
|
uri: `${stripTailingSlash(bonobRoot)}${STRINGS_ROUTE}`,
|
||||||
version: STRINGS.version,
|
version: STRINGS_VERSION,
|
||||||
},
|
},
|
||||||
presentation: {
|
presentation: {
|
||||||
uri: `${stripTailingSlash(bonobRoot)}${PRESENTATION_MAP_ROUTE}`,
|
uri: `${stripTailingSlash(bonobRoot)}${PRESENTATION_MAP_ROUTE}`,
|
||||||
version: "1",
|
version: PRESENTATION_MAP_VERSION,
|
||||||
},
|
},
|
||||||
pollInterval: 1200,
|
pollInterval: 1200,
|
||||||
authType,
|
authType,
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
const STRINGS = {
|
|
||||||
version: "1",
|
|
||||||
values: {
|
|
||||||
"foo": "bar"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default STRINGS;
|
|
||||||
@@ -299,7 +299,6 @@ describe("server", () => {
|
|||||||
expect(res.header["content-type"]).toEqual(
|
expect(res.header["content-type"]).toEqual(
|
||||||
stream.headers["content-type"]
|
stream.headers["content-type"]
|
||||||
);
|
);
|
||||||
// expect(res.header["content-length"]).toEqual(stream.headers["content-length"]);
|
|
||||||
expect(res.header["accept-ranges"]).toEqual(
|
expect(res.header["accept-ranges"]).toEqual(
|
||||||
stream.headers["accept-ranges"]
|
stream.headers["accept-ranges"]
|
||||||
);
|
);
|
||||||
@@ -396,7 +395,7 @@ describe("server", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("/album/:albumId/art", () => {
|
describe("/album/:albumId/art/size", () => {
|
||||||
const musicService = {
|
const musicService = {
|
||||||
login: jest.fn(),
|
login: jest.fn(),
|
||||||
};
|
};
|
||||||
@@ -425,7 +424,7 @@ describe("server", () => {
|
|||||||
|
|
||||||
describe("when there is no access-token", () => {
|
describe("when there is no access-token", () => {
|
||||||
it("should return a 401", async () => {
|
it("should return a 401", async () => {
|
||||||
const res = await request(server).get(`/album/123/art`);
|
const res = await request(server).get(`/album/123/art/size/180`);
|
||||||
|
|
||||||
expect(res.status).toEqual(401);
|
expect(res.status).toEqual(401);
|
||||||
});
|
});
|
||||||
@@ -436,7 +435,7 @@ describe("server", () => {
|
|||||||
now = now.add(1, "day");
|
now = now.add(1, "day");
|
||||||
|
|
||||||
const res = await request(server).get(
|
const res = await request(server).get(
|
||||||
`/album/123/art?${BONOB_ACCESS_TOKEN_HEADER}=${accessToken}`
|
`/album/123/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessToken}`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(res.status).toEqual(401);
|
expect(res.status).toEqual(401);
|
||||||
@@ -457,7 +456,7 @@ describe("server", () => {
|
|||||||
|
|
||||||
const res = await request(server)
|
const res = await request(server)
|
||||||
.get(
|
.get(
|
||||||
`/album/${albumId}/art?${BONOB_ACCESS_TOKEN_HEADER}=${accessToken}`
|
`/album/${albumId}/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessToken}`
|
||||||
)
|
)
|
||||||
.set(BONOB_ACCESS_TOKEN_HEADER, accessToken);
|
.set(BONOB_ACCESS_TOKEN_HEADER, accessToken);
|
||||||
|
|
||||||
@@ -465,7 +464,7 @@ describe("server", () => {
|
|||||||
expect(res.header["content-type"]).toEqual(coverArt.contentType);
|
expect(res.header["content-type"]).toEqual(coverArt.contentType);
|
||||||
|
|
||||||
expect(musicService.login).toHaveBeenCalledWith(authToken);
|
expect(musicService.login).toHaveBeenCalledWith(authToken);
|
||||||
expect(musicLibrary.coverArt).toHaveBeenCalledWith(albumId, 200);
|
expect(musicLibrary.coverArt).toHaveBeenCalledWith(albumId, 180);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import request from "supertest";
|
import request from "supertest";
|
||||||
import { Client, createClientAsync } from "soap";
|
import { Client, createClientAsync } from "soap";
|
||||||
import X2JS from "x2js";
|
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
|
|
||||||
|
import { DOMParserImpl } from "xmldom-ts";
|
||||||
|
import * as xpath from "xpath-ts";
|
||||||
|
|
||||||
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";
|
||||||
import { bonobService, SONOS_DISABLED } from "../src/sonos";
|
import { bonobService, SONOS_DISABLED } from "../src/sonos";
|
||||||
@@ -12,6 +14,8 @@ import {
|
|||||||
LOGIN_ROUTE,
|
LOGIN_ROUTE,
|
||||||
getMetadataResult,
|
getMetadataResult,
|
||||||
getMetadataResult2,
|
getMetadataResult2,
|
||||||
|
PRESENTATION_MAP_ROUTE,
|
||||||
|
SONOS_RECOMMENDED_IMAGE_SIZES,
|
||||||
} from "../src/smapi";
|
} from "../src/smapi";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -27,27 +31,62 @@ import supersoap from "./supersoap";
|
|||||||
import { AuthSuccess } from "../src/music_service";
|
import { AuthSuccess } from "../src/music_service";
|
||||||
import { AccessTokens } from "../src/access_tokens";
|
import { AccessTokens } from "../src/access_tokens";
|
||||||
|
|
||||||
describe("service config", () => {
|
const parseXML = (value: string) => new DOMParserImpl().parseFromString(value);
|
||||||
describe("strings.xml", () => {
|
|
||||||
const server = makeServer(
|
|
||||||
SONOS_DISABLED,
|
|
||||||
aService(),
|
|
||||||
"http://localhost:1234",
|
|
||||||
new InMemoryMusicService()
|
|
||||||
);
|
|
||||||
|
|
||||||
|
describe("service config", () => {
|
||||||
|
const server = makeServer(
|
||||||
|
SONOS_DISABLED,
|
||||||
|
aService({ name: "music land" }),
|
||||||
|
"http://localhost:1234",
|
||||||
|
new InMemoryMusicService()
|
||||||
|
);
|
||||||
|
|
||||||
|
describe(STRINGS_ROUTE, () => {
|
||||||
it("should return xml for the strings", async () => {
|
it("should return xml for the strings", async () => {
|
||||||
const res = await request(server).get(STRINGS_ROUTE).send();
|
const res = await request(server).get(STRINGS_ROUTE).send();
|
||||||
|
|
||||||
expect(res.status).toEqual(200);
|
expect(res.status).toEqual(200);
|
||||||
|
|
||||||
const strings: any = new X2JS({
|
// removing the sonos xml ns as makes xpath queries with xpath-ts painful
|
||||||
arrayAccessFormPaths: ["stringtables", "stringtables.stringtable"],
|
const xml = parseXML(
|
||||||
}).xml2js(res.text);
|
res.text.replace('xmlns="http://sonos.com/sonosapi"', "")
|
||||||
|
|
||||||
expect(strings.stringtables.stringtable[0].string[0]._stringId).toEqual(
|
|
||||||
"AppLinkMessage"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const sonosString = (id: string, lang: string) =>
|
||||||
|
xpath.select(
|
||||||
|
`string(/stringtables/stringtable[@xml:lang="${lang}"]/string[@stringId="${id}"])`,
|
||||||
|
xml
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(sonosString("AppLinkMessage", "en-US")).toEqual(
|
||||||
|
"Linking sonos with music land"
|
||||||
|
);
|
||||||
|
expect(sonosString("AppLinkMessage", "fr-FR")).toEqual(
|
||||||
|
"Lier les sonos à la music land"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(PRESENTATION_MAP_ROUTE, () => {
|
||||||
|
it("should have an ArtWorkSizeMap for all sizes recommended by sonos", async () => {
|
||||||
|
const res = await request(server).get(PRESENTATION_MAP_ROUTE).send();
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
|
||||||
|
// removing the sonos xml ns as makes xpath queries with xpath-ts painful
|
||||||
|
const xml = parseXML(
|
||||||
|
res.text.replace('xmlns="http://sonos.com/sonosapi"', "")
|
||||||
|
);
|
||||||
|
|
||||||
|
const imageSizeMap = (size: string) =>
|
||||||
|
xpath.select(
|
||||||
|
`string(/Presentation/PresentationMap[@type="ArtWorkSizeMap"]/Match/imageSizeMap/sizeEntry[@size="${size}"]/@substitution)`,
|
||||||
|
xml
|
||||||
|
);
|
||||||
|
|
||||||
|
SONOS_RECOMMENDED_IMAGE_SIZES.forEach((size) => {
|
||||||
|
expect(imageSizeMap(size)).toEqual(`/art/size/${size}`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -467,7 +506,11 @@ describe("api", () => {
|
|||||||
itemType: "album",
|
itemType: "album",
|
||||||
id: `album:${it.id}`,
|
id: `album:${it.id}`,
|
||||||
title: it.name,
|
title: it.name,
|
||||||
albumArtURI: `${rootUrl}/album/${it.id}/art?${BONOB_ACCESS_TOKEN_HEADER}=${accessTokens.mint(token.authToken)}`,
|
albumArtURI: `${rootUrl}/album/${
|
||||||
|
it.id
|
||||||
|
}/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessTokens.mint(
|
||||||
|
token.authToken
|
||||||
|
)}`,
|
||||||
})),
|
})),
|
||||||
index: 0,
|
index: 0,
|
||||||
total: artistWithManyAlbums.albums.length,
|
total: artistWithManyAlbums.albums.length,
|
||||||
@@ -492,7 +535,11 @@ describe("api", () => {
|
|||||||
itemType: "album",
|
itemType: "album",
|
||||||
id: `album:${it.id}`,
|
id: `album:${it.id}`,
|
||||||
title: it.name,
|
title: it.name,
|
||||||
albumArtURI: `${rootUrl}/album/${it.id}/art?${BONOB_ACCESS_TOKEN_HEADER}=${accessTokens.mint(token.authToken)}`,
|
albumArtURI: `${rootUrl}/album/${
|
||||||
|
it.id
|
||||||
|
}/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessTokens.mint(
|
||||||
|
token.authToken
|
||||||
|
)}`,
|
||||||
})),
|
})),
|
||||||
index: 2,
|
index: 2,
|
||||||
total: artistWithManyAlbums.albums.length,
|
total: artistWithManyAlbums.albums.length,
|
||||||
@@ -622,7 +669,11 @@ describe("api", () => {
|
|||||||
itemType: "album",
|
itemType: "album",
|
||||||
id: `album:${it.id}`,
|
id: `album:${it.id}`,
|
||||||
title: it.name,
|
title: it.name,
|
||||||
albumArtURI: `${rootUrl}/album/${it.id}/art?${BONOB_ACCESS_TOKEN_HEADER}=${accessTokens.mint(token.authToken)}`,
|
albumArtURI: `${rootUrl}/album/${
|
||||||
|
it.id
|
||||||
|
}/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessTokens.mint(
|
||||||
|
token.authToken
|
||||||
|
)}`,
|
||||||
})),
|
})),
|
||||||
index: 0,
|
index: 0,
|
||||||
total: 6,
|
total: 6,
|
||||||
@@ -648,7 +699,11 @@ describe("api", () => {
|
|||||||
itemType: "album",
|
itemType: "album",
|
||||||
id: `album:${it.id}`,
|
id: `album:${it.id}`,
|
||||||
title: it.name,
|
title: it.name,
|
||||||
albumArtURI: `${rootUrl}/album/${it.id}/art?${BONOB_ACCESS_TOKEN_HEADER}=${accessTokens.mint(token.authToken)}`,
|
albumArtURI: `${rootUrl}/album/${
|
||||||
|
it.id
|
||||||
|
}/art/size/180?${BONOB_ACCESS_TOKEN_HEADER}=${accessTokens.mint(
|
||||||
|
token.authToken
|
||||||
|
)}`,
|
||||||
})),
|
})),
|
||||||
index: 2,
|
index: 2,
|
||||||
total: 6,
|
total: 6,
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import sonos, {
|
|||||||
asCustomdForm,
|
asCustomdForm,
|
||||||
bonobService,
|
bonobService,
|
||||||
Service,
|
Service,
|
||||||
|
STRINGS_VERSION,
|
||||||
|
PRESENTATION_MAP_VERSION,
|
||||||
} from "../src/sonos";
|
} from "../src/sonos";
|
||||||
|
|
||||||
import { aSonosDevice, aService } from "./builders";
|
import { aSonosDevice, aService } from "./builders";
|
||||||
@@ -115,11 +117,11 @@ describe("sonos", () => {
|
|||||||
secureUri: `http://bonob.example.com/ws/sonos`,
|
secureUri: `http://bonob.example.com/ws/sonos`,
|
||||||
strings: {
|
strings: {
|
||||||
uri: `http://bonob.example.com/sonos/strings.xml`,
|
uri: `http://bonob.example.com/sonos/strings.xml`,
|
||||||
version: "1",
|
version: STRINGS_VERSION,
|
||||||
},
|
},
|
||||||
presentation: {
|
presentation: {
|
||||||
uri: `http://bonob.example.com/sonos/presentationMap.xml`,
|
uri: `http://bonob.example.com/sonos/presentationMap.xml`,
|
||||||
version: "1",
|
version: PRESENTATION_MAP_VERSION,
|
||||||
},
|
},
|
||||||
pollInterval: 1200,
|
pollInterval: 1200,
|
||||||
authType: "AppLink",
|
authType: "AppLink",
|
||||||
@@ -138,11 +140,11 @@ describe("sonos", () => {
|
|||||||
secureUri: `http://bonob.example.com/ws/sonos`,
|
secureUri: `http://bonob.example.com/ws/sonos`,
|
||||||
strings: {
|
strings: {
|
||||||
uri: `http://bonob.example.com/sonos/strings.xml`,
|
uri: `http://bonob.example.com/sonos/strings.xml`,
|
||||||
version: "1",
|
version: STRINGS_VERSION,
|
||||||
},
|
},
|
||||||
presentation: {
|
presentation: {
|
||||||
uri: `http://bonob.example.com/sonos/presentationMap.xml`,
|
uri: `http://bonob.example.com/sonos/presentationMap.xml`,
|
||||||
version: "1",
|
version: PRESENTATION_MAP_VERSION,
|
||||||
},
|
},
|
||||||
pollInterval: 1200,
|
pollInterval: 1200,
|
||||||
authType: "AppLink",
|
authType: "AppLink",
|
||||||
@@ -161,11 +163,11 @@ describe("sonos", () => {
|
|||||||
secureUri: `http://bonob.example.com/ws/sonos`,
|
secureUri: `http://bonob.example.com/ws/sonos`,
|
||||||
strings: {
|
strings: {
|
||||||
uri: `http://bonob.example.com/sonos/strings.xml`,
|
uri: `http://bonob.example.com/sonos/strings.xml`,
|
||||||
version: "1",
|
version: STRINGS_VERSION,
|
||||||
},
|
},
|
||||||
presentation: {
|
presentation: {
|
||||||
uri: `http://bonob.example.com/sonos/presentationMap.xml`,
|
uri: `http://bonob.example.com/sonos/presentationMap.xml`,
|
||||||
version: "1",
|
version: PRESENTATION_MAP_VERSION,
|
||||||
},
|
},
|
||||||
pollInterval: 1200,
|
pollInterval: 1200,
|
||||||
authType: "DeviceLink",
|
authType: "DeviceLink",
|
||||||
|
|||||||
10
yarn.lock
10
yarn.lock
@@ -5023,6 +5023,11 @@ xmlchars@^2.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
|
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
|
||||||
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
|
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
|
||||||
|
|
||||||
|
xmldom-ts@^0.3.1:
|
||||||
|
version "0.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/xmldom-ts/-/xmldom-ts-0.3.1.tgz#a70df029e44e9af3c03ba22d88f174a953830091"
|
||||||
|
integrity sha512-dmEBAK3Msm+BPVZOiwhXCyM0/q3BeiI4eoAPj2Us1nDhsPPhePtZ5RkgEdngNQQFp3j6QFKMLHlBIRUxdpomcQ==
|
||||||
|
|
||||||
xmldom@0.1.27:
|
xmldom@0.1.27:
|
||||||
version "0.1.27"
|
version "0.1.27"
|
||||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
|
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
|
||||||
@@ -5033,6 +5038,11 @@ xmldom@^0.1.19:
|
|||||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
|
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
|
||||||
integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
|
integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
|
||||||
|
|
||||||
|
xpath-ts@^1.3.13:
|
||||||
|
version "1.3.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/xpath-ts/-/xpath-ts-1.3.13.tgz#abca4f15dd7010161acf5b9cd01566f7b8d9541f"
|
||||||
|
integrity sha512-eNVXzDWbCV9KEB6fGNQ3qHFGC9PWBH7y2h13vZ+CMPNqOTZ+fgYTG4Sb0p5bVHiAwZrzgE6/tx987003P3dYpA==
|
||||||
|
|
||||||
xpath@0.0.27:
|
xpath@0.0.27:
|
||||||
version "0.0.27"
|
version "0.0.27"
|
||||||
resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.27.tgz#dd3421fbdcc5646ac32c48531b4d7e9d0c2cfa92"
|
resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.27.tgz#dd3421fbdcc5646ac32c48531b4d7e9d0c2cfa92"
|
||||||
|
|||||||
Reference in New Issue
Block a user