mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Ability to remove a bonob registration from sonos (#16)
This commit is contained in:
@@ -12,7 +12,8 @@ import {
|
||||
PRESENTATION_MAP_ROUTE,
|
||||
SONOS_RECOMMENDED_IMAGE_SIZES,
|
||||
LOGIN_ROUTE,
|
||||
REGISTER_ROUTE,
|
||||
CREATE_REGISTRATION_ROUTE,
|
||||
REMOVE_REGISTRATION_ROUTE
|
||||
} from "./smapi";
|
||||
import { LinkCodes, InMemoryLinkCodes } from "./link_codes";
|
||||
import { MusicService, isSuccess } from "./music_service";
|
||||
@@ -95,7 +96,8 @@ function server(
|
||||
services,
|
||||
bonobService: service,
|
||||
registeredBonobService,
|
||||
registerRoute: bonobUrl.append({ pathname: REGISTER_ROUTE }).pathname(),
|
||||
createRegistrationRoute: bonobUrl.append({ pathname: CREATE_REGISTRATION_ROUTE }).pathname(),
|
||||
removeRegistrationRoute: bonobUrl.append({ pathname: REMOVE_REGISTRATION_ROUTE }).pathname(),
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -110,7 +112,7 @@ function server(
|
||||
});
|
||||
});
|
||||
|
||||
app.post(REGISTER_ROUTE, (_, res) => {
|
||||
app.post(CREATE_REGISTRATION_ROUTE, (_, res) => {
|
||||
sonos.register(service).then((success) => {
|
||||
if (success) {
|
||||
res.render("success", {
|
||||
@@ -124,6 +126,20 @@ function server(
|
||||
});
|
||||
});
|
||||
|
||||
app.post(REMOVE_REGISTRATION_ROUTE, (_, res) => {
|
||||
sonos.remove(service.sid).then((success) => {
|
||||
if (success) {
|
||||
res.render("success", {
|
||||
message: `Successfully removed registration`,
|
||||
});
|
||||
} else {
|
||||
res.status(500).render("failure", {
|
||||
message: `Failed to remove registration!`,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.get(LOGIN_ROUTE, (req, res) => {
|
||||
res.render("login", {
|
||||
bonobService: service,
|
||||
|
||||
@@ -23,7 +23,8 @@ import { Clock } from "./clock";
|
||||
import { URLBuilder } from "./url_builder";
|
||||
|
||||
export const LOGIN_ROUTE = "/login";
|
||||
export const REGISTER_ROUTE = "/register";
|
||||
export const CREATE_REGISTRATION_ROUTE = "/registration/add";
|
||||
export const REMOVE_REGISTRATION_ROUTE = "/registration/remove";
|
||||
export const SOAP_PATH = "/ws/sonos";
|
||||
export const STRINGS_ROUTE = "/sonos/strings.xml";
|
||||
export const PRESENTATION_MAP_ROUTE = "/sonos/presentationMap.xml";
|
||||
|
||||
91
src/sonos.ts
91
src/sonos.ts
@@ -61,14 +61,14 @@ export const bonobService = (
|
||||
): Service => ({
|
||||
name,
|
||||
sid,
|
||||
uri: bonobUrl.append({pathname: SOAP_PATH }).href(),
|
||||
secureUri: bonobUrl.append({pathname: SOAP_PATH }).href(),
|
||||
uri: bonobUrl.append({ pathname: SOAP_PATH }).href(),
|
||||
secureUri: bonobUrl.append({ pathname: SOAP_PATH }).href(),
|
||||
strings: {
|
||||
uri: bonobUrl.append({pathname: STRINGS_ROUTE }).href(),
|
||||
uri: bonobUrl.append({ pathname: STRINGS_ROUTE }).href(),
|
||||
version: PRESENTATION_AND_STRINGS_VERSION,
|
||||
},
|
||||
presentation: {
|
||||
uri: bonobUrl.append({pathname: PRESENTATION_MAP_ROUTE }).href(),
|
||||
uri: bonobUrl.append({ pathname: PRESENTATION_MAP_ROUTE }).href(),
|
||||
version: PRESENTATION_AND_STRINGS_VERSION,
|
||||
},
|
||||
pollInterval: 1200,
|
||||
@@ -78,12 +78,14 @@ export const bonobService = (
|
||||
export interface Sonos {
|
||||
devices: () => Promise<Device[]>;
|
||||
services: () => Promise<Service[]>;
|
||||
remove: (sid: number) => Promise<boolean>;
|
||||
register: (service: Service) => Promise<boolean>;
|
||||
}
|
||||
|
||||
export const SONOS_DISABLED: Sonos = {
|
||||
devices: () => Promise.resolve([]),
|
||||
services: () => Promise.resolve([]),
|
||||
remove: (_: number) => Promise.resolve(true),
|
||||
register: (_: Service) => Promise.resolve(true),
|
||||
};
|
||||
|
||||
@@ -111,6 +113,11 @@ export const asDevice = (sonosDevice: SonosDevice): Device => ({
|
||||
port: sonosDevice.Port,
|
||||
});
|
||||
|
||||
export const asRemoveCustomdForm = (csrfToken: string, sid: number) => ({
|
||||
csrfToken,
|
||||
sid: `${sid}`
|
||||
});
|
||||
|
||||
export const asCustomdForm = (csrfToken: string, service: Service) => ({
|
||||
csrfToken,
|
||||
sid: `${service.sid}`,
|
||||
@@ -158,6 +165,44 @@ export function autoDiscoverySonos(sonosSeedHost?: string): Sonos {
|
||||
});
|
||||
};
|
||||
|
||||
const post = async (action: string, customdForm: (csrfToken: string) => any) => {
|
||||
const anyDevice = await sonosDevices().then((devices) => head(devices));
|
||||
|
||||
if (!anyDevice) {
|
||||
logger.warn("Failed to find a device to register with...");
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`${action} using sonos device ${anyDevice.Name} @ ${anyDevice.Host}`
|
||||
);
|
||||
|
||||
const customd = `http://${anyDevice.Host}:${anyDevice.Port}/customsd`;
|
||||
|
||||
const csrfToken = await axios.get(customd).then((response) =>
|
||||
parse(response.data)
|
||||
.querySelectorAll("input")
|
||||
.find((it) => it.getAttribute("name") == "csrfToken")
|
||||
?.getAttribute("value")
|
||||
);
|
||||
|
||||
if (!csrfToken) {
|
||||
logger.warn(
|
||||
`Failed to find csrfToken at GET -> ${customd}, cannot ${action} service`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
const form = customdForm(csrfToken)
|
||||
logger.info(`${action} with sonos @ ${customd}`, { form });
|
||||
return axios
|
||||
.post(customd, new URLSearchParams(qs.stringify(form)), {
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
})
|
||||
.then((response) => response.status == 200);
|
||||
};
|
||||
|
||||
return {
|
||||
devices: async () => sonosDevices().then((it) => it.map(asDevice)),
|
||||
|
||||
@@ -170,43 +215,9 @@ export function autoDiscoverySonos(sonosSeedHost?: string): Sonos {
|
||||
)
|
||||
.then((it) => it.map(asService)),
|
||||
|
||||
register: async (service: Service) => {
|
||||
const anyDevice = await sonosDevices().then((devices) => head(devices));
|
||||
remove: async (sid: number) => post("remove", (csrfToken) => asRemoveCustomdForm(csrfToken, sid)),
|
||||
|
||||
if (!anyDevice) {
|
||||
logger.warn("Failed to find a device to register with...");
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`Registering ${service.name}(SID:${service.sid}) with sonos device ${anyDevice.Name} @ ${anyDevice.Host}`
|
||||
);
|
||||
|
||||
const customd = `http://${anyDevice.Host}:${anyDevice.Port}/customsd`;
|
||||
|
||||
const csrfToken = await axios.get(customd).then((response) =>
|
||||
parse(response.data)
|
||||
.querySelectorAll("input")
|
||||
.find((it) => it.getAttribute("name") == "csrfToken")
|
||||
?.getAttribute("value")
|
||||
);
|
||||
|
||||
if (!csrfToken) {
|
||||
logger.warn(
|
||||
`Failed to find csrfToken at GET -> ${customd}, cannot register service`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
const customdForm = asCustomdForm(csrfToken, service);
|
||||
logger.info(`Registering with sonos @ ${customd}`, { customdForm });
|
||||
return axios
|
||||
.post(customd, new URLSearchParams(qs.stringify(customdForm)), {
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
})
|
||||
.then((response) => response.status == 200);
|
||||
},
|
||||
register: async (service: Service) => post("register", (csrfToken) => asCustomdForm(csrfToken, service)),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user