Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions examples/nowplayingwebsite.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
var http = require('http')
var Sonos = require('../').Sonos
const http = require('http')
const Sonos = require('../').Sonos

var sonos = new Sonos(process.env.SONOS_HOST || '192.168.2.11')
const sonos = new Sonos(process.env.SONOS_HOST || '192.168.2.11')

var server = http.createServer(async function (req, res) {
var track = await sonos.currentTrack()
const server = http.createServer(async function (req, res) {
const track = await sonos.currentTrack()
res.writeHead(200, {
'Content-Type': 'text/html'
})

var rows = []
const rows = []

for (var key in track) {
for (const key in track) {
if (key === 'albumArtURL') {
rows.push('<tr><th>' + key + '</th><td><img src="' + track[key] + '"/></td></tr>')
} else {
Expand Down
2 changes: 1 addition & 1 deletion examples/playSpotifyMusic.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ sonos.setSpotifyRegion(Regions.EU)
// your Sonos system.

// var spotifyUri = 'spotify:artistTopTracks:72qVrKXRp9GeFQOesj0Pmv'
var spotifyUri = 'spotify:track:6sYJuVcEu4gFHmeTLdHzRz'
const spotifyUri = 'spotify:track:6sYJuVcEu4gFHmeTLdHzRz'

sonos.play(spotifyUri)
.then(success => {
Expand Down
4 changes: 2 additions & 2 deletions examples/searchinfo.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
var sonos = require('../index')
const sonos = require('../index')

console.log('\nSearching for Sonos devices on network...')

sonos.DeviceDiscovery(function (device, model) {
var devInfo = '\n'
let devInfo = '\n'
devInfo += 'Device \t' + JSON.stringify(device) + ' (' + model + ')\n'
device.getZoneAttrs(function (err, attrs) {
if (err) devInfo += '`- failed to retrieve zone attributes\n'
Expand Down
4 changes: 2 additions & 2 deletions examples/switchToLineIn.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ const sonos = new Sonos(process.env.SONOS_HOST || '192.168.96.223')
sonos.getZoneInfo().then(data => {
// console.log('Got zone info %j', data)
// The mac is needed for switch to a different channel
var macCleaned = data.MACAddress.replace(/:/g, '')
const macCleaned = data.MACAddress.replace(/:/g, '')
console.log('Cleaned mac %j', macCleaned)

// To switch on a playbar do the following
var uri = 'x-sonos-htastream:RINCON_' + macCleaned + '01400:spdif'
const uri = 'x-sonos-htastream:RINCON_' + macCleaned + '01400:spdif'

// To switch on a Play:5 and Connect do the following
// var uri = 'x-rincon-stream:RINCON_' + macCleaned + '01400'
Expand Down
22 changes: 11 additions & 11 deletions lib/deviceDiscovery.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ const Sonos = require('./sonos').Sonos
* @class DeviceDiscovery
* @emits 'DeviceAvailable' on a Sonos Component Discovery
*/
var DeviceDiscovery = function DeviceDiscovery (options) {
var self = this
const DeviceDiscovery = function DeviceDiscovery (options) {
const self = this
self.foundSonosDevices = {}
self.onTimeout = function () {
clearTimeout(self.pollTimer)
}
var PLAYER_SEARCH = Buffer.from(['M-SEARCH * HTTP/1.1',
const PLAYER_SEARCH = Buffer.from(['M-SEARCH * HTTP/1.1',
'HOST: 239.255.255.250:1900',
'MAN: ssdp:discover',
'MX: 1',
'ST: urn:schemas-upnp-org:device:ZonePlayer:1'].join('\r\n'))
var sendDiscover = function () {
['239.255.255.250', '255.255.255.255'].map(function (addr) {
const sendDiscover = function () {
['239.255.255.250', '255.255.255.255'].forEach(function (addr) {
self.socket.send(PLAYER_SEARCH, 0, PLAYER_SEARCH.length, 1900, addr)
})
// Periodically send discover packet to find newly added devices
Expand All @@ -40,11 +40,11 @@ var DeviceDiscovery = function DeviceDiscovery (options) {
this.socket = dgram.createSocket('udp4', function (buffer, rinfo) {
buffer = buffer.toString()
if (buffer.match(/.+Sonos.+/)) {
var modelCheck = buffer.match(/SERVER.*\((.*)\)/)
var model = (modelCheck.length > 1 ? modelCheck[1] : null)
var addr = rinfo.address
const modelCheck = buffer.match(/SERVER.*\((.*)\)/)
const model = (modelCheck.length > 1 ? modelCheck[1] : null)
const addr = rinfo.address
if (!(addr in self.foundSonosDevices)) {
var sonos = self.foundSonosDevices[addr] = new Sonos(addr)
const sonos = self.foundSonosDevices[addr] = new Sonos(addr)
self.emit('DeviceAvailable', sonos, model)
}
}
Expand Down Expand Up @@ -92,14 +92,14 @@ DeviceDiscovery.prototype.destroy = function (callback) {
* @param {Function} listener Optional 'DeviceAvailable' listener (sonos)
* @return {DeviceDiscovery}
*/
var deviceDiscovery = function (options, listener) {
const deviceDiscovery = function (options, listener) {
if (typeof options === 'function') {
listener = options
options = null
}
options = options || {}
listener = listener || null
var search = new DeviceDiscovery(options)
const search = new DeviceDiscovery(options)
if (listener !== null) {
search.on('DeviceAvailable', listener)
}
Expand Down
8 changes: 4 additions & 4 deletions lib/events/adv-listener.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class SonosListener extends EventEmitter {
const cancel = function (s) {
return s.cancelAllSubscriptions()
}
var cancelAll = this._deviceSubscriptions.map(cancel)
const cancelAll = this._deviceSubscriptions.map(cancel)
return Promise.all(cancelAll)
} else {
return new Promise((resolve, reject) => { reject(new Error('Not listening')) })
Expand Down Expand Up @@ -218,7 +218,7 @@ class DeviceSubscription {
const sid = resp.headers.sid
debug('Got %s for %s', sid, endpoint)
this._startTimer()
this.subscriptions[sid] = { endpoint: endpoint, renew_at: this.headerToDateTime(resp.headers.timeout) }
this.subscriptions[sid] = { endpoint, renew_at: this.headerToDateTime(resp.headers.timeout) }
return sid
})
}
Expand Down Expand Up @@ -329,7 +329,7 @@ class DeviceSubscription {
url: 'http://' + this.device.host + ':' + this.device.port + this.subscriptions[sid].endpoint,
method: 'UNSUBSCRIBE',
headers: {
sid: sid
sid
}
}).then(result => {
debug('Cancelled subscription %s for %s', sid, this.device.host)
Expand All @@ -342,7 +342,7 @@ class DeviceSubscription {
* @param {String} timeout TimeOut header
*/
headerToDateTime (timeout) {
var seconds
let seconds

if ((!!timeout) && (timeout.indexOf('Second-') === 0)) timeout = timeout.substr(7)
seconds = (((!!timeout) && (!isNaN(timeout))) ? parseInt(timeout, 10) : 3600) - 15
Expand Down
3 changes: 1 addition & 2 deletions lib/events/eventParser.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

const Helpers = require('../helpers')
const debug = require('debug')('sonos-listener')
const SonosGroup = require('../sonosGroup')
Expand Down Expand Up @@ -97,7 +96,7 @@ EventParser._parseRenderingControlEvent = async function (body, device) {
}

EventParser._genericEvent = function (endpoint, body, device) {
const event = { name: 'UnknownEvent', endpoint: endpoint, eventBody: body }
const event = { name: 'UnknownEvent', endpoint, eventBody: body }
if (device) {
device.emit(event.name, event)
}
Expand Down
38 changes: 19 additions & 19 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const parseString = require('xml2js').parseString
* Helper class
* @class Helpers
*/
var Helpers = {}
const Helpers = {}

/**
* Wrap in UPnP Envelope
Expand Down Expand Up @@ -87,15 +87,15 @@ Helpers.GenerateCustomMetadata = function (streamUrl, itemId, duration = '00:00:
* @return {Object} { uri: uri, metadata: metadata }
*/
Helpers.GenerateLocalMetadata = function (uri, artUri = '') {
var title = ''
var match = /.*\/(.*)$/g.exec(uri.replace(/\.[a-zA-Z0-9]{3}$/, ''))
let title = ''
const match = /.*\/(.*)$/g.exec(uri.replace(/\.[a-zA-Z0-9]{3}$/, ''))
if (match) {
title = match[1]
}
var meta = '<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="##ITEMID##" parentID="##PARENTID##" restricted="true"><dc:title>##RESOURCETITLE##</dc:title><upnp:class>##UPNPCLASS##</upnp:class><upnp:albumArtURI>##ARTURI##</upnp:albumArtURI><desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">##REGION##</desc></item></DIDL-Lite>'
const meta = '<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="##ITEMID##" parentID="##PARENTID##" restricted="true"><dc:title>##RESOURCETITLE##</dc:title><upnp:class>##UPNPCLASS##</upnp:class><upnp:albumArtURI>##ARTURI##</upnp:albumArtURI><desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">##REGION##</desc></item></DIDL-Lite>'
if (uri.startsWith('x-file-cifs')) {
return {
uri: uri,
uri,
metadata: meta.replace('##ITEMID##', uri.replace('x-file-cifs', 'S').replace(/\s/g, '%20'))
.replace('##RESOURCETITLE##', title.replace('%20', ' '))
.replace('##UPNPCLASS##', Helpers.GetUpnpClass('A:TRACKS'))
Expand All @@ -105,11 +105,11 @@ Helpers.GenerateLocalMetadata = function (uri, artUri = '') {
}
}
if (uri.startsWith('x-rincon-playlist')) {
var parentMatch = /.*#(.*)\/.*/g.exec(uri)
var parentID = parentMatch[1]
const parentMatch = /.*#(.*)\/.*/g.exec(uri)
const parentID = parentMatch[1]

return {
uri: uri,
uri,
metadata: meta.replace('##ITEMID##', `${parentID}/${title.replace(/\s/g, '%20')}`)
.replace('##RESOURCETITLE##', title.replace('%20', ' '))
.replace('##UPNPCLASS##', Helpers.GetUpnpClass(parentID))
Expand All @@ -118,7 +118,7 @@ Helpers.GenerateLocalMetadata = function (uri, artUri = '') {
.replace('##REGION##', 'RINCON_AssociatedZPUDN')
}
}
return { uri: uri, metadata: '' }
return { uri, metadata: '' }
}

/**
Expand All @@ -129,15 +129,15 @@ Helpers.GenerateLocalMetadata = function (uri, artUri = '') {
* @return {Object} options {uri: Spotify uri, metadata: metadata}
*/
Helpers.GenerateMetadata = function (uri, title = '', region = '3079') {
var parts = uri.split(':')
const parts = uri.split(':')
if (!((parts.length === 2 && (parts[0] === 'radio' || parts[0] === 'x-sonosapi-stream' || parts[0] === 'x-rincon-cpcontainer')) || (parts.length >= 3 && parts[0] === 'spotify'))) {
debug('Returning string because it isn\'t recognized')
return Helpers.GenerateLocalMetadata(uri)
}
var meta = '<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="##SPOTIFYURI##" ##PARENTID##restricted="true"><dc:title>##RESOURCETITLE##</dc:title><upnp:class>##SPOTIFYTYPE##</upnp:class><desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">##REGION##</desc></item></DIDL-Lite>'
let meta = '<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="##SPOTIFYURI##" ##PARENTID##restricted="true"><dc:title>##RESOURCETITLE##</dc:title><upnp:class>##SPOTIFYTYPE##</upnp:class><desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">##REGION##</desc></item></DIDL-Lite>'

if (parts[0] === 'radio' || parts[0] === 'x-sonosapi-stream') {
var radioTitle = title || 'TuneIn Radio'
const radioTitle = title || 'TuneIn Radio'
if (parts[0] === 'radio') {
return {
uri: 'x-sonosapi-stream:' + parts[1] + '?sid=254&flags=8224&sn=0',
Expand All @@ -150,7 +150,7 @@ Helpers.GenerateMetadata = function (uri, title = '', region = '3079') {
} else {
const itemId = parts[1].split('?')[0]
return {
uri: uri,
uri,
metadata: meta.replace('##SPOTIFYURI##', 'F00092020' + itemId)
.replace('##RESOURCETITLE##', radioTitle)
.replace('##SPOTIFYTYPE##', 'object.item.audioItem.audioBroadcast')
Expand All @@ -161,7 +161,7 @@ Helpers.GenerateMetadata = function (uri, title = '', region = '3079') {
} else {
meta = meta.replace('##REGION##', 'SA_RINCON' + region + '_X_#Svc' + region + '-0-Token')
}
var spotifyUri = uri.replace(/:/g, '%3a')
const spotifyUri = uri.replace(/:/g, '%3a')

if (uri.startsWith('spotify:track:')) { // Just one track
return {
Expand Down Expand Up @@ -204,8 +204,8 @@ Helpers.GenerateMetadata = function (uri, title = '', region = '3079') {
.replace('##PARENTID##', 'parentID="10082664playlists" ')
}
} else if (uri.startsWith('spotify:artistRadio:')) { // Artist radio
var spotifyTitle = title || 'Artist Radio'
var parentId = spotifyUri.replace('artistRadio', 'artist')
const spotifyTitle = title || 'Artist Radio'
const parentId = spotifyUri.replace('artistRadio', 'artist')
return {
uri: 'x-sonosapi-radio:' + spotifyUri + '?sid=12&flags=8300&sn=5',
metadata: meta.replace('##SPOTIFYURI##', '100c206c' + spotifyUri)
Expand All @@ -226,7 +226,7 @@ Helpers.GenerateMetadata = function (uri, title = '', region = '3079') {
} else if (uri.startsWith('x-rincon-cpcontainer:100d206cuser-fav')) { // Sound Cloud likes
const id = uri.replace('x-rincon-cpcontainer:', '')
return {
uri: uri,
uri,
metadata: meta.replace('##SPOTIFYURI##', id)
.replace('##RESOURCETITLE##', title || 'Sound Cloud Likes')
.replace('##SPOTIFYTYPE##', 'object.container.albumList')
Expand All @@ -236,15 +236,15 @@ Helpers.GenerateMetadata = function (uri, title = '', region = '3079') {
} else if (uri.startsWith('x-rincon-cpcontainer:1006206cplaylist')) { // Sound Cloud playlists
const [id] = uri.replace('x-rincon-cpcontainer:', '').split('?')
return {
uri: uri,
uri,
metadata: meta.replace('##SPOTIFYURI##', id)
.replace('##RESOURCETITLE##', title || 'Sound Cloud Playlist')
.replace('##SPOTIFYTYPE##', 'object.container.playlistContainer')
.replace('##PARENTID##', '')
.replace(`SA_RINCON${region}_X_#Svc${region}-0-Token`, 'SA_RINCON40967_X_#Svc40967-0-Token')
}
} else {
return { uri: uri, metadata: '' }
return { uri, metadata: '' }
}
}

Expand Down
10 changes: 6 additions & 4 deletions lib/services/AVTransport.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,18 +192,20 @@ class AVTransport extends Service {
const trackUri = result.TrackURI || null
const queuePosition = parseInt(result.Track)
if (result.TrackMetaData && result.TrackMetaData !== 'NOT_IMPLEMENTED') { // There is some metadata, lets parse it.
var metadata = await Helpers.ParseXml(result.TrackMetaData)
const metadata = await Helpers.ParseXml(result.TrackMetaData)
const track = Helpers.ParseDIDL(metadata)
track.position = position
track.duration = duration
track.albumArtURL = !track.albumArtURI ? null
: track.albumArtURI.startsWith('http') ? track.albumArtURI
track.albumArtURL = !track.albumArtURI
? null
: track.albumArtURI.startsWith('http')
? track.albumArtURI
: 'http://' + this.host + ':' + this.port + track.albumArtURI
if (trackUri) track.uri = trackUri
track.queuePosition = queuePosition
return track
} else { // No metadata.
return { position: position, duration: duration, queuePosition: queuePosition, uri: trackUri }
return { position, duration, queuePosition, uri: trackUri }
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion lib/services/ContentDirectory.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class ContentDirectory extends Service {
returned: data.NumberReturned,
total: data.TotalMatches,
updateID: data.UpdateID,
items: items
items
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion lib/services/Service.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class Service {
})
}
messageBody += `</u:${action}>`
var responseTag = `u:${action}Response`
const responseTag = `u:${action}Response`
request({
url: 'http://' + this.host + ':' + this.port + this.controlURL,
method: 'POST',
Expand Down
Loading