GithubHelp home page GithubHelp logo

node-sonos-discovery's Introduction

Build Status

node-sonos-discovery

This is a simplification of the Sonos implementation of UPnP for the node.js stack. This library will allow you to interact with your sonos system with simple commands like play, pause, next etc, but is expected to be ran at all times because it keeps track of the players.

1.0.0 is totally rewritten to be promised based!

For example integrations, please see the following projects:

https://github.com/jishi/node-sonos-http-api

https://github.com/jishi/node-sonos-web-controller (old version)

Options

Contributions

If you are sending a pull request, please run:

npm test

Before submitting it, to validate syntax with jscs and run the few tests in there. Thank you!

node-sonos-discovery's People

Contributors

cederigo avatar coldfireice avatar garycaldwell avatar germanbluefox avatar hypermoose avatar jeffandersen avatar jishi avatar jonathankingston avatar jplourde5 avatar lockzi avatar mattwelch avatar neophob avatar noesberger avatar patrickdmiller avatar petele avatar rhew avatar sinnottj avatar steffest avatar wiegraff13 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-sonos-discovery's Issues

No devices found from Docker

When running sonos-web-controller from a Docker container it fails to find any devices. When I run it outside of a container it picks up all the Sonos devices just fine.

Here is the netstat output from within the container:

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:3500            0.0.0.0:*               LISTEN      123/node
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      123/node
udp        0      0 172.17.0.20:1901        0.0.0.0:*                           123/node

Note that 172.17.0.20 is the local non-public IP address of the container, and it just stays listening on 1901. Whereas my other Linux machine listens on 192.168.178.156:1901/udp for a little bit, finds all devices and moves on.

I've started my container with -p 8080:8080 -p 3500:3500 -p 1901:1901/udp to ensure that everything goes through. However it seems I'm still missing something. Any clues will be much appreciated.

GetFavorites does not return all favorites

I have a couple of Sonos Radio HD favorites but the GetFavorites method doesn't return them so I can't use them as presets in node-sonos-http-api. It calls a method browseAll("FV:2"). I looked at the Sonos S2 API and it says that FV:2 will return up to 70 favorites (I have less than that) but it seems it won't return these two. In the debugger I tried calling the same method with R:0/0 which is supposed to return radio stations. It doesn't return these either. Am I missing something, or is this just an omission in the Sonos Controller API? I don't see any way to get to them. This using an S2 system. I have 2 systems (households?) on the same account, but I don't think that's related. Running Ubuntu 22.04 LTS on intel hardware. The API runs in docker but that makes no difference because it does the same thing when I put in Visual Studio Code with npm start outside docker.

callback syntax inconsistent

The callback syntax is inconsistent across Sonos and Player. In Player, it appears to be callback(success, message), where success is a true/false boolean. While in Sonos it's callback(error, message), where error is either null or the actual error.

Most other libraries I've used follow the callback(error, message) style and would prefer that one.

Happy to submit a PR for this if you're willing.

Discovery Matching other devices

Hi,
I have 2 Linksys RE6500 Wifi repeaters with air play capability. Consistently Discovery tried to subscribe to them and then error out.

ex:
error: code=ECONNREFUSED, errno=ECONNREFUSED, syscall=connect, address=10.42.0.15, port=1400

I solved this by editing sonos.js to include:

var GATEWAY_UPNP_URN = '/InternetGatewayDevice.xml';

and

  if (response.indexOf(GATEWAY_UPNP_URN) !== -1) {
    // Ignore false positive from badly-behaved non-Sonos device.
    return;
  }

Hopefully that will help someone else.

Thank you for all the work you put into your projects!

Uncaught (in promise) TypeError: Cannot read property 'baseUrl' of undefined

I just switched networks and ran this line:

let discovery = new SonosDiscovery(sonosDiscoverySettings);

and getting the error:

Uncaught (in promise) TypeError: Cannot read property 'baseUrl' of undefined
    at NotificationListener.topologyChange (/Users/andy/dev-git/ElectroKC/node_modules/sonos-discovery/lib/SonosSystem.js:109)
    at NotificationListener.emit (events.js:182)
    at parseTopology.then (/Users/andy/dev-git/ElectroKC/node_modules/sonos-discovery/lib/NotificationListener.js:117)
    at process._tickCallback (internal/process/next_tick.js:68)

the error appears here (SonosSystem.js around line 109):

    // Update available services
    const anyPlayer = _this.getAnyPlayer();
    soap.invoke(`${anyPlayer.baseUrl}/MusicServices/Control`, soap.TYPE.ListAvailableServices)

I have a player here, but even if not - it should not throw, or?

Any idea or mechanism to recover from this situation?

Enqueueing a track from streaming service (eg Rdio or Soundcloud)

I've tried AddURIToQueue to enqueue url's that look like this:

uri: "x-sonos-http:_t%3a%3a1157781.mp3?sid=11&flags=32&sn=6",

The speaker returns a 500 error, and the Sonos Controller tells me, "Access Denied" (though the track information actually was added to the queue). I'm thinking this is a security issue from Sonos, but is there a way to solve it?

UnhandledPromiseRejectWarning

@jishi I found this unhandled exception today (I'm running on node 7.x)

(node:53725) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 7): Error: Got status 500 when invoking /MediaRenderer/AVTransport/Control
(node:53725) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

File: request.js
Line: 43

        res.on('end', () => {
          error.body = buffer.join('');
          reject(error);
        });

To repro use the node-sonos-http-api linein command on a player with no linein configured.

The exception is on line 43 when the reject is called. I would expect the exception to be caught, but it must be getting swallowed by another Promise somewhere.

setting incorrect volume

In node-sonos-discovery/lib/models/Player.js (line 509), I propose changing

if (/^[+-]/.test(level)) { level = this.state.volume + parseInt(level); }

to

if (/^[+-]/.test(level)) { level = parseInt(this.state.volume) + parseInt(level); }

In my experience, state.volume gets handled as a string. So volume 9 +1 becomes 91, giving me a heart attack.

(Note : depending on how state.volume was set, it's either a string or an int. So this bug occurs only in certain circumstances. Also only when increasing volume (+), because node handles subtraction (-) using int type.)

npm publish

Hi,

Why are you not publishing on npm?

Greetings

Trouble with setAVTransportURI and TTS APIs

I'm having troubles to play MP3 URLs from TTS APIs like the Google Translate API (blocks requests with wrong useragent) or from http://www.voicerss.org/api/ (needs free registration for API key).

I use it like that:

player.setAVTransportURI(textURL, '', function(success) {
                    player.play(function() {
                        queueSave[player.uuid] = {
                            favTrack: favTrack,
                            favURI: favURI,
                            started: false
                        };
                    });
                });

It just doesn't play. Any ideas for further debugging?
See also https://github.com/mattwelch/sonosifttt/blob/master/sonosifttt.js (I'm building based on this code)

npm test fails on spotify

Hi

Not sure what has changed, since a few days, npm test fails with

  1. spotify should load highres art:
    Got status 401 when invoking /v1/tracks/3WKg25vrbjJlkhsgl2W4p3
    Error
    at Object.tryGetHighResArt (lib/services/spotify.js:29:10)
    at Context.it (test/unit/services/spotify.js:19:20)

Perhaps a change on spotify side ?

Audio Delay

Hi,

Posting this here as this is the framework that does the heavy lifting, but this is something I would like to be able to do in the node proxy via node-red.

I'd like to be able to set the audio delay, I sniffed the notification from changing it and I see:

<e:propertyset
	xmlns:e="urn:schemas-upnp-org:event-1-0">
	<e:property>
		<LastChange>&lt;Event
			xmlns=&quot;urn:schemas-upnp-org:metadata-1-0/RCS/&quot;&gt;&lt;InstanceID val=&quot;0&quot;&gt;&lt;DialogLevel val=&quot;1&quot;/&gt;&lt;SurroundLevel val=&quot;0&quot;/&gt;&lt;MusicSurroundLevel val=&quot;0&quot;/&gt;&lt;AudioDelay val=&quot;1&quot;/&gt;&lt;AudioDelayLeftRear val=&quot;1&quot;/&gt;&lt;AudioDelayRightRear val=&quot;1&quot;/&gt;&lt;NightMode val=&quot;1&quot;/&gt;&lt;SurroundEnabled val=&quot;1&quot;/&gt;&lt;SurroundMode val=&quot;0&quot;/&gt;&lt;/InstanceID&gt;&lt;/Event&gt;
		</LastChange>
	</e:property>
</e:propertyset>

So AutioDelay, AudioDelayLeftRear and AudioDelayRightRear seem to be what needs to be changed, I need to set up a capture on my network to see the request that does it, but seeing the notification gives me hope that this shouldn't be too hard.

The reason behind this is that I have just installed a projector, but it shares a source with a TV, I have modified a HDMI switch so that it is now WiFi controlloable so I can switch the source to the TV or projector at the touch of a button, the idea being that it will also power on the projector and lower the projector screen automatically (as well as switching the source to the projector).

The TV and projector are connected via an optical cable, but the difference in processing time of the video on the TV and projector means I need to be able to change the delay depending on whether the TV or Projector is the sink of the signal.

Thanks.

Player#browse startIndex, 0 based?

I have a question regarding this method: here

Player.prototype.browse = function (objectID, startIndex, requestedCount, callback) {

When browsing media and I pass the following arguments:

browse('A:TRACKS', null, 10, myCallback);

I receive a list of tracks, and I presumed that I would be able to then do:

browse('A:TRACKS', 10, 10, myCallback)

to receive the next ten tracks. That doesn't seem to be the case. I end up getting way different results when simply incrementing the startIndex value (even by one).

Can you shed some light on the operation of this method?

exception in recalculateGroupVolume

In a program that makes use of this node module, we're seeing the following exception:

TypeError: Cannot read properties of undefined (reading 'members') at Player.recalculateGroupVolume (/var/polyglot/pg3/ns/000db9532fec_7/node_modules/sonos-discovery/lib/prototypes/Player/recalculateGroupVolume.js:4:32) at NotificationListener.notificationHandler (/var/polyglot/pg3/ns/000db9532fec_7/node_modules/sonos-discovery/lib/models/Player.js:370:25) at NotificationListener.emit (node:events:525:35) at /var/polyglot/pg3/ns/000db9532fec_7/node_modules/sonos-discovery/lib/NotificationListener.js:125:17 at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

This is happening every few days so repeatable, but not reproducible on demand.

HTTPS Support in lib/helpers/request.js

Kudos everyone for the great work here and the consuming project node-sonos-http-api.

I'm writing this issue in the node-sonos-discovery as I believe this is the source of the error although I'm using this library from an instance of node-sonos-http-api.

I've been having issues with the webhook out of the box when I point to a HTTPS endpoint. Specifically, I'm receiving a HTTP Status Code of 400 and looking at the URL parsed values, path, method, and host look good. I did specify the port 443 in the settings.webhook (node-sonos-http-api) to help it along but no luck. (Details below)

Given, the webhook URI as: https://api.YOURDOMAIN.com:443/api/webhook, the errors below are generated:

Error stack from node-sonos-http-api (sonos-http.api.js > invokewebhook()) but originating in sonos-discovery

{ Error
at invokeWebhook (/usr/src/app/lib/sonos-http-api.js:125:5)
at SonosSystem. (/usr/src/app/lib/sonos-http-api.js:36:5)
at emitOne (events.js:96:13)
at SonosSystem.emit (events.js:188:7)
at NotificationListener.notificationHandler (/usr/src/app/node_modules/sonos-discovery/lib/models/Player.js:323:20)
at emitTwo (events.js:111:20)
at NotificationListener.emit (events.js:191:7)
at parseLastChange.then (/usr/src/app/node_modules/sonos-discovery/lib/NotificationListener.js:125:17)
at process._tickCallback (internal/process/next_tick.js:103:7)
method: 'POST',
path: '/api/webhook',
host: 'api.YOURDOMAIN.com',
port: 443,
headers: { 'Content-Type': 'application/json', 'Content-Length': 127 },
statusCode: 400 }
2016-11-18T21:04:44.139Z ERROR Could not reach webhook endpoint https://api.YOURDOMAIN.com:443/api/webhook for some reason. Verify that the receiving end is up and running.

Checking the node-sonos-discovery/lib/helpers/request.js, I see the HTTP library is used and I'm wondering if the HTTPS library can be used for secure connections. I'm pretty new to NodeJS and the existing libraries so pardon my ignorance if I'm over simplifying. If this is an isolated need, no problem, I can fork the project for my own needs, just let me know.

Current version (not the latest, but no significant changes that I can see):
sonos-discovery (v1.1.4)
sonos-http-api (v1.1.5)

Thanks!
~Basil

What are all the possible state changes?

Thanks for this project, I'm having a lot of fun with it and it's super useful!
However I was wondering if there were any other state changes than 'volume-change', 'topology-change', 'transport-state' and 'mute-change'? For example a change on skipping a song or playing a new song. Thanks

Documentation

IS there any other documentation available other than the two sample projects?

Cheers

Switch dependencies from git to tarball

@GermanBluefox I created a new issue for this so we don't spam the others with irrelevant emails.

I have considered this for a long time but haven't gotten around to it, mainly because it requires more juggling with versions and tagging. But it is better to not depend on git, I agree.

Request: Soundbar Input Information

Hi,

would it be possible to add the information about the format of the input from a soundbar? For example:

  • Stereo
  • Dolby digital 2.0 / 2.1 / 5.1

Missing infos?

Hi,

while working with the code i notices, that some features seem to be missing.

  • currentTrack.type like radio/input/track
  • radio infos like: streamcontent and radioshowmd
  • using EnqueuedTransportURIMetaData to replace the title while radio is on
  • repeat has 2 states repeatAll and repeatOne, but is only represented as bool

Who should these features be handled? This time I'm asking before creating pull request ;)

Greetings

Implement same features in Java/Android app

Hello Jishi,
Thanks for such a nice and perfectly working api in node js for SONOS devices.
I want to achieve same kind of functionality in android application.My query is,
1)How can i acheive this in Android app.
2) Is it possible to implement same functionality in android?
3) Have you implemented for android?
4) If I have to start then from where I can start it?

Please help me out over above queries.
Thanks,
Chetan

How to find albumart from metadata

@ErwinvanderZwart I created a separate issue for this discussion, so we don't notify the other users in the other thread.

Getting album art for streaming services is actually the same principle as for local media, you would receive a relative URL with the metadata that you can invoke against any of your players. See the CurrentMetaData DIDL:

<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">
    <item id="-1" parentID="-1" restricted="true">
        <res protocolInfo="sonos.com-spotify:*:audio/x-spotify:*" duration="0:05:18">x-sonos-spotify:spotify%3atrack%3a5qAFqkXoQd2RfjZ2j1ay0w?sid=9&amp;flags=8224&amp;sn=9</res>
        <r:streamContent></r:streamContent>
        <r:radioShowMd></r:radioShowMd>
        <upnp:albumArtURI>/getaa?s=1&amp;u=x-sonos-spotify%3aspotify%253atrack%253a5qAFqkXoQd2RfjZ2j1ay0w%3fsid%3d9%26flags%3d8224%26sn%3d9</upnp:albumArtURI>
        <dc:title>Intermezzo No. 3 in C-sharp minor, Op. 117 - Andante con moto</dc:title>
        <upnp:class>object.item.audioItem.musicTrack</upnp:class>
        <dc:creator>Johannes Brahms</dc:creator>
        <upnp:album>Glenn Gould plays Brahms: 4 Ballades op. 10; 2 Rhapsodies op. 79; 10 Intermezzi</upnp:album>
    </item>
</DIDL-Lite>

As you can see, the upnp:albumArtURI tag contains a relative url that you can append to the player base url, which would be http://player_ip:1400/

This is the data that is evented, you are talking about TrackMetaData, are you polling that data? It might differ slightly.

No Metadata when browsing SQ:4

Hi

browsing SQ:4 does not return any metadata, for example:

> p.browseAll('SQ:4').then((res)=>console.log(res));
Promise { <pending> }
> [ { uri: 'x-sonos-http:track%3a235766083.mp3?sid=160&flags=8224&sn=7',
    title: 'R84 PODCAST444: HERZ & KLΔNG',
    artist: 'ROOM84',
    album: undefined,
    albumTrackNumber: undefined,
    albumArtUri: '/getaa?s=1&u=x-sonos-http%3atrack%253a235766083.mp3%3fsid%3d160%26flags%3d8224%26sn%3d7',
    metadata: undefined },
...

compared to another directory:

p.browseAll('FV:2').then((res)=>console.log(res));
Promise { <pending> }
> [ { uri: 'x-sonos-spotify:spotify%3atrack%3a7r539iSTidDcjXjdmvXtFe?sid=9&flags=8224&sn=16',
    title: 'Palace',
    artist: undefined,
    album: undefined,
    albumTrackNumber: undefined,
    albumArtUri: 'https://i.scdn.co/image/3fbbec43f3d052ea25b2ca4c3dc7bda180d28eb2',
    metadata: '<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:.... <snip>

when you want to queue/play a track from SQ:4 no metadata is visible on Sonos but only garbage like x-sonos-spotify:spotify%3atrack%3a7r5.... I found out that SQ:4 does not include metadata in the answer (no r:resMD). However when we attach the original xml as metadata itself, the metadata are correctly visible on Sonos.

I did an ugly workaround for the legacy version here: neophob@46117dd

Change events for playlist changes

Hi,

I'm about to implement the playlist change emitter (queue-change, favorites-change and add playlists-change). I would report the uuid of the player when queue changes but, for favorites and playlists it concerns the whole system.
Is there anything against just passing this event through? Did you have other plans?

Switch preset with out changing volume.

I was looking at the applyPreset code to see if we could tweak it to use the current volume from each zone it's going to set if there is no volume set in the preset.

Right now it just dumps in 0 so if you don't set a volume you get nothing.

My thoughts were to have it check all the volumes right before the 'pauseall' (line 572) and keep a list of all the current player volumes. Then when you go to set volume, check to see if there was a volume in the preset. If so, use that, if not, use the current volume.

Thoughts?

Radio station support

Currently the web player shows the following info when playing a radio through tunein radio:

Track: x-sonosapi-stream:s...
Artist:
Album:
Next:

Realistically I would like this to say:

Station: AVTransportURIMetaData: dc:title
Show: CurrentTrackMetaData: r:radioShowMd.split(',')[0]

I think these should be new keys passed from the discovery, then a relevant task will be needed to clean up the interface.

Add more intelligence to SSDP scanning

Systems with multiple private interfaces and intermittent issues with Windows ARP cache and multicast, it should discover systems in the following order:

SSDP using 0.0.0.0
SSDP for each interface found on machine

And cycle through them every 5 seconds or so. That will get a snappy discovery on the majority of installations, and eventual discovery on all other systems.

If local endpoint changes, subscribe will keep failing to reconnect.

If the local end point changes, new ip is given by the router our such the subscribe call will throw a EADDRNOTAVAIL error. But since discovery.localEndpoint is only setup on init it will keep failing indefinitely or until restarted.

I fixed this on a legacy branch: pfiaux@67201dd

I handled the EADDRNOTAVAIL specifically can updated the localEndpoint in that case. I looked quickly, I could be wrong but it seems like 1.0.0 on master still only does it on init as well:
https://github.com/jishi/node-sonos-discovery/blob/master/lib/SonosSystem.js#L123

using bonding interface

Hi

I'm using the network bonding module, now sonos-discovery does not discover any sonos device anymore. and hints how to make this works?

error: sonos.0 TypeError: Cannot read property '$text' of undefined

2019-11-08 10:43:10.339 - error: sonos.0 TypeError: Cannot read property '$text' of undefined
at EventEmitter.sax.on (/opt/iobroker/node_modules/sonos-discovery/lib/models/Player.js:89:28)
at emitOne (events.js:116:13)
at EventEmitter.emit (events.js:211:7)
at SAXStream.onCloseTag (/opt/iobroker/node_modules/xml-flow/lib/xml-flow.js:131:15)
at emitOne (events.js:116:13)
at SAXStream.emit (events.js:211:7)
at SAXParser.me._parser.(anonymous function) [as onclosetag] (/opt/iobroker/node_modules/sax/lib/sax.js:258:17)
at emit (/opt/iobroker/node_modules/sax/lib/sax.js:624:35)
at emitNode (/opt/iobroker/node_modules/sax/lib/sax.js:629:5)
at closeTag (/opt/iobroker/node_modules/sax/lib/sax.js:889:7)
at SAXParser.write (/opt/iobroker/node_modules/sax/lib/sax.js:1436:13)
at SAXStream.write (/opt/iobroker/node_modules/sax/lib/sax.js:239:18)
at Readable.ondata (_stream_readable.js:639:20)
at emitOne (events.js:116:13)
at Readable.emit (events.js:211:7)
at addChunk (_stream_readable.js:263:12)
2019-11-08 10:43:10.340 - info: sonos.0 terminating

Media browsing

Preface

One of the things that mosts annoys me from Sonos is that it's search engine offers me inaccessible songs when people leaves my office. I think it's pretty straightforward to filter out music from inaccessible network libraries.

Issue

Implement media browsing in sonos-discovery.
It not just is really useful as-is, but also it enables us to implement some heartbeat ping system to add this capability, and provide a better Sonos experience from http-api or web-controller.

I've already started playing a bit with this, but I've no experience with UPnP at all.

This issue may be a bit of a self-reminder - but I'll be glad to know you're in, too :)

Hi

Hope it's okay that I post you those issues.
If you like I can also fork & send you a pull request.

Support switch to Line In and TV

I use a Playbar which is connected to my TV. After the configuration step, I can select "TV" in the Sonos app - which uses the optical input from the tv.

Looks like at the moment, sonos-discovery does not support switching to this input, which would be very handy.

do you have an idea how to implement that?

edit: looks like Soco implement this feature: https://github.com/SoCo/SoCo/blob/06a5e758f65dcb920f72b21353094b468173fa77/soco/core.py#L1077 and https://github.com/SoCo/SoCo/blob/06a5e758f65dcb920f72b21353094b468173fa77/soco/core.py#L1140

Support Google Play Music (I'm feeling Lucky mix)

When the Google Play Music "I'm feeling Lucky mix" is selected in Sonos, this (streaming) mode is not detected by Sonos discovery. This URI looks like:

"uri": "x-sonosprog-http:_dklxfo-EJNFGf4fhhl5zLwSxbZ-NIJgqG7UK83SzxsF8y9ZJwK58ehTTw3hKlMO.mp3?sid=151&flags=8192&sn=8",

I guess "x-sonosprog-http" needs to be added to the getUriType.js / isRadio check, right?

How to update libary

Hi,
i am not a Linux crack and don´t know how to update libary cause of problem with Iobroker Sonos Adapter. Only copy Files in this folder ?

/opt/iobroker/node_modules/sonos-discovery

And restart linux or iobroker ?

Regards
Dieter

Getting the current state of the system

So I have managed to get a simple example up and running using your api but I was wondering if I can grab a players state. Basically I want to cut out what is playing, play a specific playlist then stop it at some point in time and then resume what was playing on the device before I interrupted (could have been off or playing something else)

So far I have this basic module

var SonosDiscovery = require('sonos-discovery');

var discovery = new SonosDiscovery();

var sonos = {};

sonos.alert = function() {
  //Grab player(s) state to set back afterward
  var player = discovery.getPlayer('kitchen');
  player.play();
};

sonos.stop = function() {
  //get the saved state and set what was playing before or stop if nothing
  var player = discovery.getPlayer('kitchen');
  player.pause();
};

module.exports = sonos;

Do you have any examples where you are doing this in the other clients?

Cheers

Webhook: I'm not getting any transport-state events

I get events for topology-change as expected but have not seen any transport-state updates. What events on the system are supposed to fire that? I was hoping to get a notification each time the track changed on any player on the system.

not on npm?

Am I missing something or is this not published?

Unable to get state of player

Everything was working great up until yesterday. Now whenever I play a track through Spotify (Sonos App, AirPlay, Spotify Connect), I can't get the current state of the player (play/pause, current track, etc). Looking at the avTransportUriMetadata, for some reason, it keeps thinking I'm using line-in.

'<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"><item id="spotify" parentID="0" restricted="false"><dc:title>Spotify</dc:title>**<upnp:class>object.item.audioItem.linein</upnp:class>**<res protocolInfo="x-sonos-vli:*:audio:*">x-sonos-vli:RINCON_347E5C0EE19701400:2,spotify:5e9de992040a26982081102f3cf2b1b0</res><vli cookie="1" group=""></vli></item></DIDL-Lite>'
const SonosDiscovery = require('sonos-discovery');

const settings = {
  port: 1234,
  cacheDir: './cache',
};

const discovery = new SonosDiscovery(settings);

discovery.on('initialized', function(data) {
  console.log('EVENT: initialized');
});

discovery.on('topology-change', function(data) {
  console.log('EVENT: topology-change');
});

discovery.on('transport-state', function(data) {
  console.log('EVENT: transport-state');
  console.log(discovery.zones);
});

add promise support

It would be nice to have Promise support instead of callbacks, here is what I'm using to monkey-patch it in, would be a lot easier if it was supported natively :)

waitForPlayers should be rather named waitForDiscovery or something (or the getPlayer() / getPlayerByUUID() should be async, too)

Additionally I add a Player.getGroup() function that returns all players in that group.

// monkey patch: wait for discovery to complete
Sonos.prototype.waitForPlayers = async function() {
    var self = this;
    if (Object.keys(this.players).length == 0) {
        await new Promise((resolve, reject) => {
            self.on('topology-change', (rooms) => {
                resolve();
            });
        });
    }
};

// monkey patch: get Player prototype and promisify
(() => {
    var promisify = (proto, name) => {
        var old = proto[name];
        proto[name] = function(...args) {
            var self = this;
            return new Promise((resolve, reject) => {
                args.push((error, result) => {
                    if (error) {
                        reject(error);
                    } else {
                        resolve(result);
                    }
                });
                old.apply(self, args);
            });
        }
    };
    var patch = (Player) => {
        patch = undefined;
        Player.prototype.getGroup = function() {
            var r = [];
            for (var uuid in this.discovery.players) {
                var player = this.discovery.players[uuid];
                if (player.coordinator.uuid != this.uuid) continue;
                r.push(player);
            }
            return r;
        };
        // Player.prototype.inspect = function() {
        //     return 'sonos.Player<' + this.uuid + ',' + this.roomName + '>';
        // };
        var proto = Player.prototype;
        for (let k in proto) {
            if (typeof proto[k] !== 'function') continue;
            let argnames = proto[k].toString().split('{')[0].split('(')[1].split(')')[0].split(',').map(x => x.trim());
            let i = argnames.indexOf('callback');
            if (i < 0) continue;
            if (k == 'groupSetVolume') continue; // buggy upstream.
            let old = proto[k];
            proto[k] = function(...args) {
                let self = this;
                if (!args[i]) {
                    return new Promise((resolve, reject) => {
                        args[i] = (error, result) => {
                            if (error) {
                                reject(error);
                            } else {
                                resolve(result);
                            }
                        };
                        old.apply(self, args);
                    });
                }
                return old.apply(self, args);
            };
        }
    };
    var _getPlayer = Sonos.prototype.getPlayer;
    Sonos.prototype.getPlayer = function(...args) {
        var res = _getPlayer.apply(this, args);
        if (patch && res) patch(res.constructor);
        return res;
    };
    var _getPlayerByUUID = Sonos.prototype.getPlayerByUUID;
    Sonos.prototype.getPlayerByUUID = function(...args) {
        var res = _getPlayerByUUID.apply(this, args);
        if (patch && res) patch(res.constructor);
        return res;
    };
})();

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.