From 7fc74e8f46c341f2458626b3ab392ea671255db8 Mon Sep 17 00:00:00 2001 From: JayVee2 <35402108+JayVee2@users.noreply.github.com> Date: Wed, 27 Mar 2019 18:58:53 +0100 Subject: [PATCH 01/43] Force creation of MP3 instead of WAV file to play with Sonos https://github.com/jishi/node-sonos-http-api/issues/686 --- lib/tts-providers/voicerss.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/tts-providers/voicerss.js b/lib/tts-providers/voicerss.js index ea5aa24d..6b677dde 100644 --- a/lib/tts-providers/voicerss.js +++ b/lib/tts-providers/voicerss.js @@ -16,7 +16,8 @@ function voicerss(phrase, language) { language = 'en-gb'; } // Use voicerss tts translation service to create a mp3 file - const ttsRequestUrl = `http://api.voicerss.org/?key=${settings.voicerss}&f=22khz_16bit_mono&hl=${language}&src=${encodeURIComponent(phrase)}`; + // Option "c=MP3" added. Otherwise a WAV file is created that won't play on Sonos. + const ttsRequestUrl = `http://api.voicerss.org/?key=${settings.voicerss}&f=22khz_16bit_mono&hl=${language}&src=${encodeURIComponent(phrase)}&c=MP3`; // Construct a filesystem neutral filename const phraseHash = crypto.createHash('sha1').update(phrase).digest('hex'); From b7bc6b45039961ba3a563d5f2396272ad544fd78 Mon Sep 17 00:00:00 2001 From: Jimmy Shimizu Date: Thu, 28 Mar 2019 14:32:57 +0100 Subject: [PATCH 02/43] fix: Use strict --- lib/presets-loader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presets-loader.js b/lib/presets-loader.js index 986cea4a..ef8312d4 100644 --- a/lib/presets-loader.js +++ b/lib/presets-loader.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const fs = require('fs'); const util = require('util'); const path = require('path'); From 87fd1537ff4fc12b6b1e59795985e12efea25d6b Mon Sep 17 00:00:00 2001 From: Jimmy Shimizu Date: Thu, 28 Mar 2019 14:44:19 +0100 Subject: [PATCH 03/43] chore: Patch version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 55384cbc..6ff067d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sonos-http-api", - "version": "1.6.7", + "version": "1.6.8", "description": "A simple node app for controlling a Sonos system with basic HTTP requests", "scripts": { "start": "node server.js", From 921e49ba8b72b6b3b4ba29a79f14b6e999947563 Mon Sep 17 00:00:00 2001 From: Jimmy Shimizu Date: Thu, 28 Mar 2019 14:59:13 +0100 Subject: [PATCH 04/43] fix: Add JessaNeural #679 --- lib/tts-providers/microsoft.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/tts-providers/microsoft.js b/lib/tts-providers/microsoft.js index b0789d5c..e24803ee 100644 --- a/lib/tts-providers/microsoft.js +++ b/lib/tts-providers/microsoft.js @@ -274,6 +274,11 @@ const VOICE = { language: 'zh-TW', gender: 'Male', font: 'Microsoft Server Speech Text to Speech Voice (zh-TW, Zhiwei, Apollo)' + }, + JessaNeural: { + language: 'en-US', + gender: 'Female', + font: 'Microsoft Server Speech Text to Speech Voice (en-US, JessaNeural)' } }; From a1e93825ac40c157d6931e6fad9c78ef51f8b348 Mon Sep 17 00:00:00 2001 From: Stefan Kienzle Date: Mon, 17 Jun 2019 17:56:16 +0200 Subject: [PATCH 05/43] Add Napster/Aldi Life Music support (#699) * Add Napster/Aldi Life Music support * Bugfix Napster "now" while radio station is played * Final fixes for Napster and Aldi Life Music (powered by Napster) --- lib/actions/aldilifeMusic.js | 65 ++++++++++++++++++++++++++++++++++++ lib/actions/napster.js | 65 ++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 lib/actions/aldilifeMusic.js create mode 100644 lib/actions/napster.js diff --git a/lib/actions/aldilifeMusic.js b/lib/actions/aldilifeMusic.js new file mode 100644 index 00000000..570a7285 --- /dev/null +++ b/lib/actions/aldilifeMusic.js @@ -0,0 +1,65 @@ +'use strict'; +function getMetadata(id, parentUri, type, title) { + return ` + "${title}"${type} + SA_RINCON55303_X_#Svc55303-0-Token`; +} + +function getUri(id, type) { + var uri = { + song: `x-sonos-http:ondemand_track%3a%3atra.${id}%7cv1%7cALBUM%7calb.mp4?sid=216&flags=8224&sn=13`, + album: `x-rincon-cpcontainer:100420ecexplore%3aalbum%3a%3aAlb.${id}` + }; + + return uri[type]; +} + +const CLASSES = { + song: 'object.item.audioItem.musicTrack', + album: 'object.container.album.musicAlbum' +}; + +const METADATA_URI_STARTERS = { + song: '10032020ondemand_track%3a%3atra.', + album: '100420ec' +}; + +const PARENTS = { + song: '100420ecexplore%3a', + album: '100420ecexplore%3aalbum%3a' +}; + +function aldilifeMusic(player, values) { + const action = values[0]; + const trackID = values[1].split(':')[1]; + const type = values[1].split(':')[0]; + var nextTrackNo = 0; + + const metadataID = METADATA_URI_STARTERS[type] + encodeURIComponent(trackID); + const metadata = getMetadata(metadataID, PARENTS[type], CLASSES[type], ''); + const uri = getUri(encodeURIComponent(trackID), type); + + if (action == 'queue') { + return player.coordinator.addURIToQueue(uri, metadata); + } else if (action == 'now') { + nextTrackNo = player.coordinator.state.trackNo + 1; + let promise = Promise.resolve(); + if (player.coordinator.avTransportUri.startsWith('x-rincon-queue') === false) { + promise = promise.then(() => player.coordinator.setAVTransport(`x-rincon-queue:${player.coordinator.uuid}#0`)); + } + + return promise.then(() => { + return player.coordinator.addURIToQueue(uri, metadata, true, nextTrackNo) + .then((addToQueueStatus) => player.coordinator.trackSeek(addToQueueStatus.firsttracknumberenqueued)) + .then(() => player.coordinator.play()); + }); + } else if (action == 'next') { + nextTrackNo = player.coordinator.state.trackNo + 1; + return player.coordinator.addURIToQueue(uri, metadata, true, nextTrackNo); + } +} + +module.exports = function (api) { + api.registerAction('aldilifemusic', aldilifeMusic); +}; diff --git a/lib/actions/napster.js b/lib/actions/napster.js new file mode 100644 index 00000000..7540800b --- /dev/null +++ b/lib/actions/napster.js @@ -0,0 +1,65 @@ +'use strict'; +function getMetadata(id, parentUri, type, title) { + return ` + "${title}"${type} + SA_RINCON51975_X_#Svc51975-0-Token`; +} + +function getUri(id, type) { + var uri = { + song: `x-sonos-http:ondemand_track%3a%3atra.${id}%7cv1%7cALBUM%7calb.mp4?sid=203&flags=8224&sn=13`, + album: `x-rincon-cpcontainer:100420ecexplore%3aalbum%3a%3aAlb.${id}` + }; + + return uri[type]; +} + +const CLASSES = { + song: 'object.item.audioItem.musicTrack', + album: 'object.container.album.musicAlbum' +}; + +const METADATA_URI_STARTERS = { + song: '10032020ondemand_track%3a%3atra.', + album: '100420ec' +}; + +const PARENTS = { + song: '100420ecexplore%3a', + album: '100420ecexplore%3aalbum%3a' +}; + +function napster(player, values) { + const action = values[0]; + const trackID = values[1].split(':')[1]; + const type = values[1].split(':')[0]; + var nextTrackNo = 0; + + const metadataID = METADATA_URI_STARTERS[type] + encodeURIComponent(trackID); + const metadata = getMetadata(metadataID, PARENTS[type], CLASSES[type], ''); + const uri = getUri(encodeURIComponent(trackID), type); + + if (action == 'queue') { + return player.coordinator.addURIToQueue(uri, metadata); + } else if (action == 'now') { + nextTrackNo = player.coordinator.state.trackNo + 1; + let promise = Promise.resolve(); + if (player.coordinator.avTransportUri.startsWith('x-rincon-queue') === false) { + promise = promise.then(() => player.coordinator.setAVTransport(`x-rincon-queue:${player.coordinator.uuid}#0`)); + } + + return promise.then(() => { + return player.coordinator.addURIToQueue(uri, metadata, true, nextTrackNo) + .then((addToQueueStatus) => player.coordinator.trackSeek(addToQueueStatus.firsttracknumberenqueued)) + .then(() => player.coordinator.play()); + }); + } else if (action == 'next') { + nextTrackNo = player.coordinator.state.trackNo + 1; + return player.coordinator.addURIToQueue(uri, metadata, true, nextTrackNo); + } +} + +module.exports = function (api) { + api.registerAction('napster', napster); +}; From 49c48a2eb2b69affaad8c3fe09a552715a13a74c Mon Sep 17 00:00:00 2001 From: Jimmy Shimizu Date: Fri, 5 Jul 2019 16:40:07 +0200 Subject: [PATCH 06/43] fix: Upgrade sonos-discovery dep to mitigate `TypeError: Cannot read property 'length' of undefined` Fixes #706 --- package-lock.json | 698 +++++++++++++++++++++++----------------------- package.json | 4 +- 2 files changed, 351 insertions(+), 351 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4130cd4c..8873d5e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "sonos-http-api", - "version": "1.6.3", + "version": "1.6.9", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -16,7 +16,7 @@ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "acorn": "3.3.0" + "acorn": "^3.0.4" }, "dependencies": { "acorn": { @@ -32,10 +32,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "ajv-keywords": { @@ -49,8 +49,8 @@ "resolved": "https://registry.npmjs.org/anesidora/-/anesidora-1.2.1.tgz", "integrity": "sha1-/ZWdrLiPx6im5xE+OA8/rQmTipo=", "requires": { - "request": "2.87.0", - "underscore": "1.9.1" + "request": "^2.64.0", + "underscore": "^1.8.3" } }, "ansi-escapes": { @@ -77,7 +77,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "array-union": { @@ -86,7 +86,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -155,9 +155,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" }, "dependencies": { "chalk": { @@ -166,11 +166,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "strip-ansi": { @@ -179,7 +179,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } } } @@ -206,7 +206,7 @@ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "bluebird": { @@ -220,7 +220,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -229,9 +229,9 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "requires": { - "base64-js": "1.3.0", - "ieee754": "1.1.8", - "isarray": "1.0.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, "buffer-from": { @@ -252,7 +252,7 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "0.2.0" + "callsites": "^0.2.0" } }, "callsites": { @@ -272,9 +272,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "dependencies": { "ansi-styles": { @@ -283,7 +283,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.2" + "color-convert": "^1.9.0" } }, "supports-color": { @@ -292,7 +292,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -315,7 +315,7 @@ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "restore-cursor": "2.0.0" + "restore-cursor": "^2.0.0" } }, "cli-width": { @@ -329,8 +329,8 @@ "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-1.1.3.tgz", "integrity": "sha1-syY8EaCJsDlhhaG3q5BNkPAq1Cg=", "requires": { - "is-bluebird": "1.0.2", - "shimmer": "1.2.0" + "is-bluebird": "^1.0.1", + "shimmer": "^1.1.0" } }, "co": { @@ -363,7 +363,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "concat-map": { @@ -378,10 +378,10 @@ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { - "buffer-from": "1.1.1", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, "contains-path": { @@ -401,9 +401,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "dashdash": { @@ -411,14 +411,13 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -435,13 +434,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" } }, "delayed-stream": { @@ -455,7 +454,7 @@ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "2.0.2" + "esutils": "^2.0.2" } }, "ecc-jsbn": { @@ -464,8 +463,8 @@ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "optional": true, "requires": { - "jsbn": "0.1.1", - "safer-buffer": "2.1.2" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "error-ex": { @@ -474,9 +473,14 @@ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -489,44 +493,44 @@ "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", "dev": true, "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.3", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.7.0", - "ignore": "3.3.10", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.5.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", "table": "4.0.2", - "text-table": "0.2.0" + "text-table": "~0.2.0" } }, "eslint-config-airbnb-base": { @@ -535,7 +539,7 @@ "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", "dev": true, "requires": { - "eslint-restricted-globals": "0.1.1" + "eslint-restricted-globals": "^0.1.1" } }, "eslint-import-resolver-node": { @@ -544,8 +548,8 @@ "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", "dev": true, "requires": { - "debug": "2.6.9", - "resolve": "1.8.1" + "debug": "^2.6.9", + "resolve": "^1.5.0" }, "dependencies": { "debug": { @@ -565,8 +569,8 @@ "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", "dev": true, "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" + "debug": "^2.6.8", + "pkg-dir": "^1.0.0" }, "dependencies": { "debug": { @@ -586,16 +590,16 @@ "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==", "dev": true, "requires": { - "contains-path": "0.1.0", - "debug": "2.6.9", + "contains-path": "^0.1.0", + "debug": "^2.6.8", "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.2", - "eslint-module-utils": "2.2.0", - "has": "1.0.3", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0", - "resolve": "1.8.1" + "eslint-import-resolver-node": "^0.3.1", + "eslint-module-utils": "^2.2.0", + "has": "^1.0.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.3", + "read-pkg-up": "^2.0.0", + "resolve": "^1.6.0" }, "dependencies": { "debug": { @@ -613,8 +617,8 @@ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" + "esutils": "^2.0.2", + "isarray": "^1.0.0" } } } @@ -631,8 +635,8 @@ "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", "dev": true, "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "eslint-visitor-keys": { @@ -647,8 +651,8 @@ "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", "dev": true, "requires": { - "acorn": "5.7.1", - "acorn-jsx": "3.0.1" + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" } }, "esprima": { @@ -663,7 +667,7 @@ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.0.0" } }, "esrecurse": { @@ -672,7 +676,7 @@ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.1.0" } }, "estraverse": { @@ -703,9 +707,9 @@ "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.23", - "tmp": "0.0.33" + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" } }, "extsprintf": { @@ -735,7 +739,7 @@ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5" + "escape-string-regexp": "^1.0.5" } }, "file-entry-cache": { @@ -744,23 +748,18 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" } }, - "file-type": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-10.2.0.tgz", - "integrity": "sha512-eqX81S1PWdLDPW39yyB214TVVOsUQjSmPcyUjeVH6ksH+94Y2YA/ItiIwa53rJiSofJZLK6lGsuCE3rwt0vp4w==" - }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "flat-cache": { @@ -769,10 +768,10 @@ "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" + "circular-json": "^0.3.1", + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" } }, "forever-agent": { @@ -785,9 +784,19 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.19" + "mime-types": "^2.1.12" + } + }, + "fs-extra": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, "fs.realpath": { @@ -818,7 +827,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "glob": { @@ -827,12 +836,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "globals": { @@ -847,19 +856,18 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "har-schema": { "version": "2.0.0", @@ -871,8 +879,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.1.0", + "har-schema": "^2.0.0" } }, "has": { @@ -881,7 +889,7 @@ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.1.1" } }, "has-ansi": { @@ -890,7 +898,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -915,9 +923,9 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.14.2" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "iconv-lite": { @@ -926,7 +934,7 @@ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "ieee754": { @@ -952,8 +960,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -968,20 +976,20 @@ "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", "dev": true, "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.10", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" } }, "is-arrayish": { @@ -1001,7 +1009,7 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-fullwidth-code-point": { @@ -1022,7 +1030,7 @@ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { - "is-path-inside": "1.0.1" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -1031,7 +1039,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-promise": { @@ -1084,8 +1092,8 @@ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jsbn": { @@ -1120,6 +1128,14 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -1137,8 +1153,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "load-json-file": { @@ -1147,10 +1163,10 @@ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" } }, "locate-path": { @@ -1159,8 +1175,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" }, "dependencies": { "path-exists": { @@ -1183,15 +1199,10 @@ "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, - "media-typer": { - "version": "0.3.0", - "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -1207,7 +1218,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", "requires": { - "mime-db": "1.35.0" + "mime-db": "~1.35.0" } }, "mimic-fn": { @@ -1222,7 +1233,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1250,34 +1261,25 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "music-metadata": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-3.1.5.tgz", - "integrity": "sha512-ZR+sy0Bu6iojocbEQ6mH/UTfpD9OCkCNcbbewdycOX4oF8iNEwp0TXtASmAW9Y4xKIcsgWjI/e5yzWfpu+ue1Q==", - "requires": { - "debug": "4.1.0", - "file-type": "10.2.0", - "media-typer": "0.3.0", - "strtok3": "2.1.1", - "then-read-stream": "1.3.1", - "token-types": "1.0.1" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-1.1.0.tgz", + "integrity": "sha512-HTIWhewHyLwVQByhh45BGtmxrEDpq4RI4ZwUKYBwj7uPheE+MmudlnRc22emq99GRLGmb16/Q7RgM+3O0Wi2wg==", + "requires": { + "bluebird": "^3.5.1", + "debug": "^3.1.0", + "fs-extra": "^6.0.1", + "strtok3": "^1.4.2", + "then-read-stream": "^1.1.3", + "token-types": "^0.9.4" }, "dependencies": { - "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", - "requires": { - "ms": "2.1.1" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "bluebird": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" } } }, @@ -1298,9 +1300,9 @@ "resolved": "https://registry.npmjs.org/node-static/-/node-static-0.7.10.tgz", "integrity": "sha512-bd7zO5hvCWzdglgwz9t82T4mYTEUzEG5pXnSqEzitvmEacusbhl8/VwuCbMaYR9g2PNK5191yBtAEQLJEmQh1A==", "requires": { - "colors": "1.3.1", - "mime": "1.6.0", - "optimist": "0.6.1" + "colors": ">=0.6.0", + "mime": "^1.2.9", + "optimist": ">=0.3.4" } }, "normalize-package-data": { @@ -1309,10 +1311,10 @@ "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { - "hosted-git-info": "2.7.1", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "oauth-sign": { @@ -1332,7 +1334,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "onetime": { @@ -1341,7 +1343,7 @@ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "optimist": { @@ -1349,8 +1351,8 @@ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "requires": { - "minimist": "0.0.10", - "wordwrap": "0.0.3" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" } }, "optionator": { @@ -1359,12 +1361,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" }, "dependencies": { "wordwrap": { @@ -1387,7 +1389,7 @@ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { - "p-try": "1.0.0" + "p-try": "^1.0.0" } }, "p-locate": { @@ -1396,7 +1398,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "1.3.0" + "p-limit": "^1.1.0" } }, "p-try": { @@ -1411,7 +1413,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "1.3.2" + "error-ex": "^1.2.0" } }, "path-exists": { @@ -1420,7 +1422,7 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "path-is-absolute": { @@ -1447,7 +1449,7 @@ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { - "pify": "2.3.0" + "pify": "^2.0.0" } }, "performance-now": { @@ -1473,7 +1475,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pkg-dir": { @@ -1482,7 +1484,7 @@ "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", "dev": true, "requires": { - "find-up": "1.1.2" + "find-up": "^1.0.0" } }, "pluralize": { @@ -1536,9 +1538,9 @@ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" } }, "read-pkg-up": { @@ -1547,8 +1549,8 @@ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" }, "dependencies": { "find-up": { @@ -1557,7 +1559,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "2.0.0" + "locate-path": "^2.0.0" } } } @@ -1568,13 +1570,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "regexpp": { @@ -1588,26 +1590,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.2", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.0.3", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.19", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.2", - "safe-buffer": "5.1.2", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.3.2" + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" } }, "request-promise": { @@ -1615,10 +1617,10 @@ "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-1.0.2.tgz", "integrity": "sha1-FV9BBgjZJXwInB0LJvjY96iqhqE=", "requires": { - "bluebird": "2.11.0", - "cls-bluebird": "1.1.3", - "lodash": "3.10.1", - "request": "2.87.0" + "bluebird": "^2.3", + "cls-bluebird": "^1.0.1", + "lodash": "^3.10.0", + "request": "^2.34" }, "dependencies": { "lodash": { @@ -1634,8 +1636,8 @@ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" } }, "resolve": { @@ -1644,7 +1646,7 @@ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "dev": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "^1.0.5" } }, "resolve-from": { @@ -1659,8 +1661,8 @@ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } }, "rimraf": { @@ -1669,7 +1671,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "run-async": { @@ -1678,7 +1680,7 @@ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { - "is-promise": "2.1.0" + "is-promise": "^2.1.0" } }, "rx-lite": { @@ -1693,7 +1695,7 @@ "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", "dev": true, "requires": { - "rx-lite": "4.0.8" + "rx-lite": "*" } }, "safe-buffer": { @@ -1723,7 +1725,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -1749,14 +1751,14 @@ "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0" + "is-fullwidth-code-point": "^2.0.0" } }, "sonos-discovery": { - "version": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.1.tar.gz", - "integrity": "sha512-1i8FAbLBajwe0i9nWqVEjvguM8ltfz7Gnc6yaURyCyKYuodoH3KicrLD6xoyi4BYxGyrs7sgTiNDFO0b489erg==", + "version": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.3.tar.gz", + "integrity": "sha512-bHog/7+zjirplyZOjclSM9g6rZVZX0bDWX+PzkS6KN0I1/KK6SjotazhkI4nhcrx4NYWnxCQULIO9RvzlyG2uA==", "requires": { - "html-entities": "1.0.10", + "html-entities": "1.0.x", "xml-flow": "1.0.2" }, "dependencies": { @@ -1773,8 +1775,8 @@ "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { @@ -1789,8 +1791,8 @@ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { @@ -1810,15 +1812,15 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.2", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.2", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "safer-buffer": "2.1.2", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" } }, "string-width": { @@ -1827,8 +1829,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "string_decoder": { @@ -1837,7 +1839,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -1846,7 +1848,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" }, "dependencies": { "ansi-regex": { @@ -1870,27 +1872,20 @@ "dev": true }, "strtok3": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-2.1.1.tgz", - "integrity": "sha512-fASvEpC2aDaTS6TZHffbW4w8li471ws3qQc0ag1KdftigxvOxhjIF8NWiDLSiWQV8YQSKhZggq8YbGTzvicCHA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-1.6.0.tgz", + "integrity": "sha512-BDr7b5RJSfvX1wBjJDwpJOGZ0EhfhZaMCm+YaOVAcvFgo8/+nJq/Vurzh7JykAgiW+EOo5kkrfVffBFFp3u8TQ==", "requires": { - "debug": "4.1.0", - "then-read-stream": "1.3.1", - "token-types": "1.0.1" + "debug": "^3.1.0", + "es6-promise": "^4.2.4", + "then-read-stream": "^1.2.1", + "token-types": "^0.10.0" }, "dependencies": { - "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", - "requires": { - "ms": "2.1.1" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "token-types": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-0.10.0.tgz", + "integrity": "sha512-26A0816VoHW8h64OT47dcclsH5M9iwo9zi3KoCPz1NrKoI9T2dlVkisgzTaGK4dPjCbP3ugf7cYqhWOiAzVHgw==" } } }, @@ -1906,12 +1901,12 @@ "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", "dev": true, "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.10", + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", "slice-ansi": "1.0.0", - "string-width": "2.1.1" + "string-width": "^2.1.1" } }, "text-table": { @@ -1921,9 +1916,9 @@ "dev": true }, "then-read-stream": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/then-read-stream/-/then-read-stream-1.3.1.tgz", - "integrity": "sha512-RDxUU490df9+DlL0qd1Uc8EpKOwHQodjh5Gd2qZ249k4zYyv8FLgb3g9ygII1EItT35SDOK1LE3vX2zNZKCSXA==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/then-read-stream/-/then-read-stream-1.5.1.tgz", + "integrity": "sha512-I+iiemYWhp1ysJQEioqpEICgvHlqHS5WrQGZkboFLs7Jm350Kvq4cN3qRCzHpETUuq5+NsdrdWEg6M0NFxtwtQ==" }, "through": { "version": "2.3.8", @@ -1937,20 +1932,20 @@ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.2" } }, "token-types": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-1.0.1.tgz", - "integrity": "sha512-Q2yPT4GA4gmIAgUrL9O9LRzKFKJ8FA1P5eiOfC2eH+IZMSJVQBCML1SOooeRicIIvTr/UZuTAX5PqMzgBXJOvg==" + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-0.9.4.tgz", + "integrity": "sha512-KSl/Q1GJ4FoxbqKCLhTiIowVzom2cP0fgWGXKsJupbJQqfnCDmxkdMopIrt+y5Ak6YAGdy9TKpplWDioaBsbEw==" }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" } }, "tunnel-agent": { @@ -1958,7 +1953,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -1973,7 +1968,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "typedarray": { @@ -1987,6 +1982,11 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, "url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", @@ -2020,8 +2020,8 @@ "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", "dev": true, "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, "verror": { @@ -2029,9 +2029,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" } }, "wav-file-info": { @@ -2045,7 +2045,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "wordwrap": { @@ -2065,7 +2065,7 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "0.5.1" + "mkdirp": "^0.5.1" } }, "xml-flow": { @@ -2073,7 +2073,7 @@ "resolved": "https://registry.npmjs.org/xml-flow/-/xml-flow-1.0.2.tgz", "integrity": "sha512-TfV52Su2083n8w61l1hGI5K3ZAkn4hmaon3oJHc+TRQo0QkKLMPAPdMpGMJd+5Aik6ZUicPDjBINO8QxLkZGgg==", "requires": { - "sax": "1.2.4" + "sax": "^1.2.4" }, "dependencies": { "sax": { @@ -2088,8 +2088,8 @@ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", "requires": { - "sax": "1.2.1", - "xmlbuilder": "9.0.7" + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" } }, "xmlbuilder": { diff --git a/package.json b/package.json index 6ff067d8..af9afe88 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sonos-http-api", - "version": "1.6.8", + "version": "1.6.9", "description": "A simple node app for controlling a Sonos system with basic HTTP requests", "scripts": { "start": "node server.js", @@ -22,7 +22,7 @@ "music-metadata": "^1.1.0", "node-static": "^0.7.9", "request-promise": "~1.0.2", - "sonos-discovery": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.2.tar.gz", + "sonos-discovery": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.3.tar.gz", "wav-file-info": "0.0.8" }, "engines": { From dae63a35a3b744b2034a3de0d19a5d7ff01d90a8 Mon Sep 17 00:00:00 2001 From: David De Sloovere Date: Sun, 18 Aug 2019 12:32:10 +0200 Subject: [PATCH 07/43] Add Spotify link info Some more info regarding Spotify links/URIs --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index c885d5ee..5aea0e83 100644 --- a/README.md +++ b/README.md @@ -797,8 +797,23 @@ The following endpoints are available: /RoomName/amazonmusic/{now,next,queue}/album:{albumID} ``` +**Spotify** + +You can find the **Spotify** track and album IDs as the last part of the URL. + +How to find the URL? +- Web player: the address bar URL for albums and playlist; select _Copy Song Link_ from the dot menu. +- Desktop client: via _Share > Copy {Album,Playlist,Song} Link_ +- Mobile client: via _Share > Copy Link_ + +For Spotify playlists, you'll need this format: `spotify:user:spotify:playlist:{playlistid}`. Even if it's a public playlist, you always need to prefix with `spotify:user:`. An example of a great playlist: `/kitchen/spotify/now/spotify:user:spotify:playlist:32O0SSXDNWDrMievPkV0Im`. + +To get more technical, you actually use the Spotify URI (not URL) for the endpoint, like so: `{room}/spotify/{now,next,queue}/{spotifyuri}`. + It only handles a single **spotify** account currently. It will probably use the first account added on your system. +**Apple Music** + You can find **Apple Music** song and album IDs via the [iTunes Search API](https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/). @@ -814,6 +829,8 @@ The format is: https://itunes.apple.com/de/album/{songName}/{albumID}?i={songID} The format is: https://itunes.apple.com/de/album/{albumName}/{albumID} > eg: https://itunes.apple.com/de/album/f-g-restless/355363490 +**Amazon Music** + To find **Amazon Music** song and album IDs you can use the Amazon Music App, search for a song or an album and share a link. Look at the link you just shared. This works with Amazon Music Prime as well as with Amazon Music Prime which is included in your Amazon Prime membership. From 7808d1f400d81adc60e28fffc561a2d56ccec631 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 24 Jan 2020 12:01:23 +0100 Subject: [PATCH 08/43] Add household setting to readme I've been looking for this feature and had to find out about it through the issues, seemed a good one to have in the readme :) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5aea0e83..65feb6a6 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,7 @@ Available options are: * auth: require basic auth credentials which requires a username and password * announceVolume: the percentual volume use when invoking say/sayall without any volume parameter * presetDir: absolute path to look for presets (folder must exist!) +* household: when theres multiple sonos accounts on one network (example: Sonos_ab7d67898dcc5a6d, find it in [Your sonos IP]:1400/status/zp) Example: From 2ca0ee3e43e3d7b205c5b561459acd33f6e0ef63 Mon Sep 17 00:00:00 2001 From: rummens <31141785+rummens@users.noreply.github.com> Date: Thu, 23 Apr 2020 10:14:02 +0200 Subject: [PATCH 09/43] Enhanced documentation for presets Added trackNo and elapsedTime to preset documentation, as they are supported but not documented. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 65feb6a6..dff360d1 100644 --- a/README.md +++ b/README.md @@ -293,6 +293,8 @@ Example content: "volume": 15 } ], + "trackNo": 3, + "elapsedTime": 42, "playMode": { "shuffle": true, "repeat": "all", From 91284cbdeb8db0e26c3d3bff9060b59e4b406d6c Mon Sep 17 00:00:00 2001 From: Jimmy Shimizu Date: Tue, 5 May 2020 12:34:14 +0200 Subject: [PATCH 10/43] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index dff360d1..430274b9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ [![PayPal donate button](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.me/jishi "Donate once-off to this project using Paypal") [![Join the chat at gitter](https://img.shields.io/gitter/room/badges/shields.svg)](https://gitter.im/node-sonos-http-api/Lobby "Need assistance? Join the chat at Gitter.im") +⚠WARNING!⚠ + +The upcoming Sonos software update (dubbed S2) will most likely break this API. If you rely on it, and want to continue use it, I would hold of upgrading to S2 right now until we know more. + + Feel free to use it as you please. Consider donating if you want to support further development. Reach out on the gitter chat if you have issues getting it to run, instead of creating new issues, thank you! If you are also looking for cloud control (ifttt, public webhooks etc), see the [bronos-client](http://www.bronos.net) project! That pi image also contains an installation of this http-api. From 7b5d5e45863a4ea88a34aab3e554e282ab93b945 Mon Sep 17 00:00:00 2001 From: Jimmy Shimizu Date: Mon, 22 Jun 2020 10:40:18 +0200 Subject: [PATCH 11/43] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 430274b9..997f6a59 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ⚠WARNING!⚠ -The upcoming Sonos software update (dubbed S2) will most likely break this API. If you rely on it, and want to continue use it, I would hold of upgrading to S2 right now until we know more. +The upcoming Sonos software update (dubbed S2) seems to still work. However, it might break in the future if and when they decide to drop UPnP as control protocol. Feel free to use it as you please. Consider donating if you want to support further development. Reach out on the gitter chat if you have issues getting it to run, instead of creating new issues, thank you! From 8789ed81e53d2c018f8b28d48466c564d5146043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98ystein=20Blixhavn?= Date: Fri, 29 Jan 2021 15:35:56 +0100 Subject: [PATCH 12/43] Update spotify/now/album|playlist to always set AVtransport to queue --- lib/actions/spotify.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/actions/spotify.js b/lib/actions/spotify.js index dbbd8c5a..6b281489 100644 --- a/lib/actions/spotify.js +++ b/lib/actions/spotify.js @@ -29,15 +29,10 @@ function spotify(player, values) { } else if (action == 'now') { var nextTrackNo = player.coordinator.state.trackNo + 1; let promise = Promise.resolve(); - if (player.coordinator.avTransportUri.startsWith('x-rincon-queue') === false) { - promise = promise.then(() => player.coordinator.setAVTransport(`x-rincon-queue:${player.coordinator.uuid}#0`)); - } - - return promise.then(() => { - return player.coordinator.addURIToQueue(uri, metadata, true, nextTrackNo) - .then((addToQueueStatus) => player.coordinator.trackSeek(addToQueueStatus.firsttracknumberenqueued)) - .then(() => player.coordinator.play()); - }); + return promise.then(() => player.coordinator.setAVTransport(`x-rincon-queue:${player.coordinator.uuid}#0`)) + .then(() => player.coordinator.addURIToQueue(uri, metadata, true, nextTrackNo)) + .then((addToQueueStatus) => player.coordinator.trackSeek(addToQueueStatus.firsttracknumberenqueued)) + .then(() => player.coordinator.play()); } else if (action == 'next') { var nextTrackNo = player.coordinator.state.trackNo + 1; From 03160925a988d694a4fd9c906f0a83227bafad1d Mon Sep 17 00:00:00 2001 From: Thyraz Date: Thu, 3 Sep 2020 21:22:03 +0200 Subject: [PATCH 13/43] Updates fuse.js for more reliable search results --- lib/actions/pandora.js | 6 +++--- lib/actions/siriusXM.js | 4 ++-- lib/music_services/libraryDef.js | 18 +++++++++--------- package-lock.json | 6 +++--- package.json | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/actions/pandora.js b/lib/actions/pandora.js index 2f498ed3..faa1772e 100644 --- a/lib/actions/pandora.js +++ b/lib/actions/pandora.js @@ -89,11 +89,11 @@ function pandora(player, values) { if (results.length > 0) { const station = results[0]; if (station.type == undefined) { - uri = getPandoraUri(station.stationId, station.stationName, station.artUrl); - metadata = getPandoraMetadata(station.stationId, station.stationName, player.system.getServiceType('Pandora')); + uri = getPandoraUri(station.item.stationId, station.item.stationName, station.item.artUrl); + metadata = getPandoraMetadata(station.item.stationId, station.item.stationName, player.system.getServiceType('Pandora')); return Promise.resolve(); } else { - return pandoraAPI("station.createStation", {"musicToken":station.stationId, "musicType":station.type}) + return pandoraAPI("station.createStation", {"musicToken":station.item.stationId, "musicType":station.item.type}) .then((stationInfo) => { uri = getPandoraUri(stationInfo.stationId); metadata = getPandoraMetadata(stationInfo.stationId, stationInfo.stationName, player.system.getServiceType('Pandora')); diff --git a/lib/actions/siriusXM.js b/lib/actions/siriusXM.js index 0930ec67..9e3dc168 100644 --- a/lib/actions/siriusXM.js +++ b/lib/actions/siriusXM.js @@ -72,8 +72,8 @@ function siriusXM(player, values) { results = fuzzy.search(searchVal); if (results.length > 0) { const channel = results[0]; - const uri = getSiriusXmUri(channel.id); - const metadata = getSiriusXmMetadata(channel.id, channel.parentID, channel.fullTitle); + const uri = getSiriusXmUri(channel.item.id); + const metadata = getSiriusXmMetadata(channel.item.id, channel.item.parentID, channel.item.fullTitle); return player.coordinator.setAVTransport(uri, metadata) .then(() => player.coordinator.play()); diff --git a/lib/music_services/libraryDef.js b/lib/music_services/libraryDef.js index a12c0d2e..50ee2b84 100644 --- a/lib/music_services/libraryDef.js +++ b/lib/music_services/libraryDef.js @@ -99,7 +99,7 @@ function loadTracks(type, tracksJson) { }; if (tracksJson.length > 0) { - var albumName = tracksJson[0].albumName; + var albumName = tracksJson[0].item.albumName; // Filtered list of tracks to play tracks.queueTracks = tracksJson.reduce(function(tracksArray, track) { @@ -109,18 +109,18 @@ function loadTracks(type, tracksJson) { if (type == 'song') { for (var j = 0; (j < tracksArray.length) && !skip; j++) { // Skip duplicate songs - skip = (track.trackName == tracksArray[j].trackName); + skip = (track.item.trackName == tracksArray[j].trackName); } } else { - skip = (track.albumName != albumName); + skip = (track.item.albumName != albumName); } if (!skip) { tracksArray.push({ - trackName: track.trackName, - artistName: track.artistName, - albumTrackNumber:track.albumTrackNumber, - uri: track.uri, - metadata: track.metadata + trackName: track.item.trackName, + artistName: track.item.artistName, + albumTrackNumber:track.item.albumTrackNumber, + uri: track.item.uri, + metadata: track.item.metadata }); tracks.count++; } @@ -148,7 +148,7 @@ function libIsEmpty() { function loadFuse(items, fuzzyKeys) { return new Promise((resolve) => { - return resolve(new Fuse(items, { keys: fuzzyKeys, threshold: 0.2, distance: 5, maxPatternLength: 100 })); + return resolve(new Fuse(items, { keys: fuzzyKeys, threshold: 0.2, maxPatternLength: 100, ignoreLocation: true })); }); } diff --git a/package-lock.json b/package-lock.json index 8873d5e6..8ce6f9ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -818,9 +818,9 @@ "dev": true }, "fuse.js": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-2.7.4.tgz", - "integrity": "sha1-luQg/efvARrEnCWKYhMU/ldlNvk=" + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.4.1.tgz", + "integrity": "sha512-+hAS7KYgLXontDh/vqffs7wIBw0ceb9Sx8ywZQhOsiQGcSO5zInGhttWOUYQYlvV/yYMJOacQ129Xs3mP3+oZQ==" }, "getpass": { "version": "0.1.7", diff --git a/package.json b/package.json index af9afe88..c19a4db9 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "anesidora": "^1.2.0", "aws-sdk": "^2.12.0", "basic-auth": "~1.1.0", - "fuse.js": "^2.5.0", + "fuse.js": "^6.4.1", "html-entities": "^1.2.1", "json5": "^0.5.1", "mime": "^1.4.1", From 07b5e12143e7f6a06d7b524e5a6b37cff40e7af3 Mon Sep 17 00:00:00 2001 From: Jimmy Shimizu Date: Mon, 8 Feb 2021 16:33:17 +0100 Subject: [PATCH 14/43] Update index.html --- static/index.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/static/index.html b/static/index.html index fc16b3d4..7bfc06db 100644 --- a/static/index.html +++ b/static/index.html @@ -95,9 +95,11 @@

Queue

Room Grouping

    -
  • add/{other zone name}
  • -
  • remove/{other zone name}
  • +
  • add/{player name from existing zone, prefix with player you want to join}
  • +
  • join/{player player to join in, prefix with player from current zone} (this is just the inverse of add)
  • isolate
  • +
  • ungroup (alias of isolate)
  • +
  • leave (alias of isolate)

Other

From 545fd3d21fd11519cee1797727b5f2a0ca868e92 Mon Sep 17 00:00:00 2001 From: Michel Bardelmeijer Date: Mon, 18 Oct 2021 12:54:46 +0200 Subject: [PATCH 15/43] Add note about household value --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 997f6a59..9302c616 100644 --- a/README.md +++ b/README.md @@ -325,7 +325,7 @@ Available options are: * auth: require basic auth credentials which requires a username and password * announceVolume: the percentual volume use when invoking say/sayall without any volume parameter * presetDir: absolute path to look for presets (folder must exist!) -* household: when theres multiple sonos accounts on one network (example: Sonos_ab7d67898dcc5a6d, find it in [Your sonos IP]:1400/status/zp) +* household: when theres multiple sonos accounts on one network (example: Sonos_ab7d67898dcc5a6d, find it in [Your sonos IP]:1400/status/zp). Note that the value after the '.' should not be removed. See more info here: https://github.com/jishi/node-sonos-http-api/issues/783 Example: From 01f60ff08080158ed0ef4db55d2fc97306b30244 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Tue, 8 Mar 2022 16:11:39 +1300 Subject: [PATCH 16/43] Add toggles for on/off actions Closes: #813 Signed-off-by: Mike Beattie --- README.md | 10 +++++----- lib/actions/equalizer.js | 6 ++++-- lib/actions/playmode.js | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9302c616..6e2aaff7 100644 --- a/README.md +++ b/README.md @@ -89,9 +89,9 @@ The actions supported as of today: * favorites (with optional "detailed" parameter) * playlist * lockvolumes / unlockvolumes (experimental, will enforce the volume that was selected when locking!) -* repeat (on/off) -* shuffle (on/off) -* crossfade (on/off) +* repeat (on(=all)/one/off(=none)/toggle) +* shuffle (on/off/toggle) +* crossfade (on/off/toggle) * pauseall (with optional timeout in minutes) * resumeall (will resume the ones that was pause on the pauseall call. Useful for doorbell, phone calls, etc. Optional timeout) * say @@ -106,8 +106,8 @@ The actions supported as of today: * clippreset * join / leave (Grouping actions) * sub (on/off/gain/crossover/polarity) See SUB section for more info -* nightmode (on/off, PLAYBAR only) -* speechenhancement (on/off, PLAYBAR only) +* nightmode (on/off/toggle, PLAYBAR only) +* speechenhancement (on/off/toggle, PLAYBAR only) * bass/treble (use -10 thru 10 as value. 0 is neutral) diff --git a/lib/actions/equalizer.js b/lib/actions/equalizer.js index beba3655..d4ad5b8d 100644 --- a/lib/actions/equalizer.js +++ b/lib/actions/equalizer.js @@ -1,12 +1,14 @@ 'use strict'; function nightMode(player, values) { - const enable = values[0] === 'on'; + let enable = values[0] === 'on'; + if(values[0] == "toggle") enable = !player.coordinator.state.equalizer.nightMode; return player.nightMode(enable); } function speechEnhancement(player, values) { - const enable = values[0] === 'on'; + let enable = values[0] === 'on'; + if(values[0] == "toggle") enable = !player.coordinator.state.equalizer.speechEnhancement; return player.speechEnhancement(enable); } diff --git a/lib/actions/playmode.js b/lib/actions/playmode.js index ff13d88e..b8d21c9e 100644 --- a/lib/actions/playmode.js +++ b/lib/actions/playmode.js @@ -6,17 +6,27 @@ function repeat(player, values) { mode = "all"; } else if (mode === "off") { mode = "none"; + } else if (mode === "toggle") { + switch (player.coordinator.state.playMode.repeat) { + case 'all': mode = "one"; break; + case 'one': mode = "off"; break; + default: mode = "all"; + } } return player.coordinator.repeat(mode); } function shuffle(player, values) { - return player.coordinator.shuffle(values[0] == "on" ? true : false); + let enable = values[0] === "on"; + if(values[0] == "toggle") enable = !player.coordinator.state.playMode.shuffle; + return player.coordinator.shuffle(enable); } function crossfade(player, values) { - return player.coordinator.crossfade(values[0] == "on" ? true : false); + let enable = values[0] === "on"; + if(values[0] == "toggle") enable = !player.coordinator.state.playMode.crossfade; + return player.coordinator.crossfade(enable); } module.exports = function (api) { From 03533697324d10f721393954354550bd43dd842f Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Tue, 8 Mar 2022 16:15:36 +1300 Subject: [PATCH 17/43] Add state of toggled setting to action responses Signed-off-by: Mike Beattie --- lib/actions/equalizer.js | 14 ++++++++++---- lib/actions/mute.js | 11 +++++++++-- lib/actions/playmode.js | 20 +++++++++++++++----- lib/actions/playpause.js | 11 +++++++++-- 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/lib/actions/equalizer.js b/lib/actions/equalizer.js index d4ad5b8d..51c1c3da 100644 --- a/lib/actions/equalizer.js +++ b/lib/actions/equalizer.js @@ -2,14 +2,20 @@ function nightMode(player, values) { let enable = values[0] === 'on'; - if(values[0] == "toggle") enable = !player.coordinator.state.equalizer.nightMode; - return player.nightMode(enable); + let ret = { status: 'success' }; + if(values[0] == "toggle") enable = ret.nightmode = !player.coordinator.state.equalizer.nightMode; + return player.nightMode(enable).then((response) => { + return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + }); } function speechEnhancement(player, values) { let enable = values[0] === 'on'; - if(values[0] == "toggle") enable = !player.coordinator.state.equalizer.speechEnhancement; - return player.speechEnhancement(enable); + let ret = { status: 'success' }; + if(values[0] == "toggle") enable = ret.speechenhancement = !player.coordinator.state.equalizer.speechEnhancement; + return player.speechEnhancement(enable).then((response) => { + return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + }); } function bass(player, values) { diff --git a/lib/actions/mute.js b/lib/actions/mute.js index efa6c938..1e494df6 100644 --- a/lib/actions/mute.js +++ b/lib/actions/mute.js @@ -16,11 +16,18 @@ function groupUnmute(player) { } function toggleMute(player) { + let ret = { status: 'success', muted: true }; + if(player.state.mute) { - return player.unMute(); + ret.muted = false; + return player.unMute().then((response) => { + return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + }); }; - return player.mute(); + return player.mute().then((response) => { + return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + }); } module.exports = function (api) { diff --git a/lib/actions/playmode.js b/lib/actions/playmode.js index b8d21c9e..2714a900 100644 --- a/lib/actions/playmode.js +++ b/lib/actions/playmode.js @@ -1,6 +1,7 @@ 'use strict'; function repeat(player, values) { let mode = values[0]; + let ret = { status: 'success' }; if (mode === "on") { mode = "all"; @@ -12,21 +13,30 @@ function repeat(player, values) { case 'one': mode = "off"; break; default: mode = "all"; } + ret.repeat = mode; } - return player.coordinator.repeat(mode); + return player.coordinator.repeat(mode).then((response) => { + return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + }); } function shuffle(player, values) { let enable = values[0] === "on"; - if(values[0] == "toggle") enable = !player.coordinator.state.playMode.shuffle; - return player.coordinator.shuffle(enable); + let ret = { status: 'success' }; + if(values[0] == "toggle") enable = ret.shuffle = !player.coordinator.state.playMode.shuffle; + return player.coordinator.shuffle(enable).then((response) => { + return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + }); } function crossfade(player, values) { let enable = values[0] === "on"; - if(values[0] == "toggle") enable = !player.coordinator.state.playMode.crossfade; - return player.coordinator.crossfade(enable); + let ret = { status: 'success' }; + if(values[0] == "toggle") enable = ret.crossfade = !player.coordinator.state.playMode.crossfade; + return player.coordinator.crossfade(enable).then((response) => { + return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + }); } module.exports = function (api) { diff --git a/lib/actions/playpause.js b/lib/actions/playpause.js index 8732b97b..aac63c9e 100644 --- a/lib/actions/playpause.js +++ b/lib/actions/playpause.js @@ -1,10 +1,17 @@ 'use strict'; function playpause(player) { + let ret = { status: 'success', paused: false }; + if(player.coordinator.state.playbackState === 'PLAYING') { - return player.coordinator.pause(); + ret.paused = true; + return player.coordinator.pause().then((response) => { + return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + }); } - return player.coordinator.play(); + return player.coordinator.play().then((response) => { + return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + }); } function play(player) { From f1ac98c41853c3831a6489965d1cece024b6c103 Mon Sep 17 00:00:00 2001 From: Mike Beattie Date: Wed, 9 Mar 2022 11:02:17 +1300 Subject: [PATCH 18/43] Return state for on/off actions as well. Also remove check for IncomingMessage response Signed-off-by: Mike Beattie --- lib/actions/equalizer.js | 10 ++++------ lib/actions/mute.js | 8 ++------ lib/actions/playmode.js | 14 +++++--------- lib/actions/playpause.js | 8 ++------ 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/lib/actions/equalizer.js b/lib/actions/equalizer.js index 51c1c3da..66c50fd0 100644 --- a/lib/actions/equalizer.js +++ b/lib/actions/equalizer.js @@ -2,19 +2,17 @@ function nightMode(player, values) { let enable = values[0] === 'on'; - let ret = { status: 'success' }; - if(values[0] == "toggle") enable = ret.nightmode = !player.coordinator.state.equalizer.nightMode; + if(values[0] == "toggle") enable = !player.coordinator.state.equalizer.nightMode; return player.nightMode(enable).then((response) => { - return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + return { status: 'success', nightmode: enable }; }); } function speechEnhancement(player, values) { let enable = values[0] === 'on'; - let ret = { status: 'success' }; - if(values[0] == "toggle") enable = ret.speechenhancement = !player.coordinator.state.equalizer.speechEnhancement; + if(values[0] == "toggle") enable = !player.coordinator.state.equalizer.speechEnhancement; return player.speechEnhancement(enable).then((response) => { - return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + return { status: 'success', speechenhancement: enable }; }); } diff --git a/lib/actions/mute.js b/lib/actions/mute.js index 1e494df6..6ac2a76e 100644 --- a/lib/actions/mute.js +++ b/lib/actions/mute.js @@ -20,14 +20,10 @@ function toggleMute(player) { if(player.state.mute) { ret.muted = false; - return player.unMute().then((response) => { - return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; - }); + return player.unMute().then((response) => { return ret; }); }; - return player.mute().then((response) => { - return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; - }); + return player.mute().then((response) => { return ret; }); } module.exports = function (api) { diff --git a/lib/actions/playmode.js b/lib/actions/playmode.js index 2714a900..2746beee 100644 --- a/lib/actions/playmode.js +++ b/lib/actions/playmode.js @@ -1,7 +1,6 @@ 'use strict'; function repeat(player, values) { let mode = values[0]; - let ret = { status: 'success' }; if (mode === "on") { mode = "all"; @@ -13,29 +12,26 @@ function repeat(player, values) { case 'one': mode = "off"; break; default: mode = "all"; } - ret.repeat = mode; } return player.coordinator.repeat(mode).then((response) => { - return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + return { status: 'success', repeat: mode }; }); } function shuffle(player, values) { let enable = values[0] === "on"; - let ret = { status: 'success' }; - if(values[0] == "toggle") enable = ret.shuffle = !player.coordinator.state.playMode.shuffle; + if(values[0] == "toggle") enable = !player.coordinator.state.playMode.shuffle; return player.coordinator.shuffle(enable).then((response) => { - return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + return { status: 'success', shuffle: mode }; }); } function crossfade(player, values) { let enable = values[0] === "on"; - let ret = { status: 'success' }; - if(values[0] == "toggle") enable = ret.crossfade = !player.coordinator.state.playMode.crossfade; + if(values[0] == "toggle") enable = !player.coordinator.state.playMode.crossfade; return player.coordinator.crossfade(enable).then((response) => { - return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; + return { status: 'success', crossfade: enable }; }); } diff --git a/lib/actions/playpause.js b/lib/actions/playpause.js index aac63c9e..655c0544 100644 --- a/lib/actions/playpause.js +++ b/lib/actions/playpause.js @@ -4,14 +4,10 @@ function playpause(player) { if(player.coordinator.state.playbackState === 'PLAYING') { ret.paused = true; - return player.coordinator.pause().then((response) => { - return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; - }); + return player.coordinator.pause().then((response) => { return ret; }); } - return player.coordinator.play().then((response) => { - return (!response || response.constructor.name === 'IncomingMessage') ? ret : response; - }); + return player.coordinator.play().then((response) => { return ret; }); } function play(player) { From ce064fa7d93afa430166f11fa26c8ced7dcd9a83 Mon Sep 17 00:00:00 2001 From: Tom Slominski Date: Thu, 10 Mar 2022 19:06:20 +0000 Subject: [PATCH 19/43] Add action for the BBC Sounds service --- lib/actions/bbcSounds.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 lib/actions/bbcSounds.js diff --git a/lib/actions/bbcSounds.js b/lib/actions/bbcSounds.js new file mode 100644 index 00000000..cb4d63c9 --- /dev/null +++ b/lib/actions/bbcSounds.js @@ -0,0 +1,38 @@ +'use strict'; + +function getMetadata(station) { + return ` + BBC Soundsobject.item.audioItem.audioBroadcast + SA_RINCON83207_`; +} + +function getUri(station) { + return `x-sonosapi-hls:stations%7eplayable%7e%7e${station}%7e%7eurn%3abbc%3aradio%3anetwork%3a${station}?sid=325&flags=288&sn=10`; +} + +/** + * @link https://gist.github.com/bpsib/67089b959e4fa898af69fea59ad74bc3 Stream names can be found here + */ +function bbcSounds(player, values) { + const action = values[0]; + const station = encodeURIComponent(values[1]); + + if (!station) { + return Promise.reject('Expected BBC Sounds station name.'); + } + + const metadata = getMetadata(station); + const uri = getUri(station); + + if (action === 'play') { + return player.coordinator.setAVTransport(uri, metadata).then(() => player.coordinator.play()); + } else if (action === 'set') { + return player.coordinator.setAVTransport(uri, metadata); + } + + return Promise.reject('BBC Sounds only handles the {play} & {set} actions.'); +} + +module.exports = function (api) { + api.registerAction('bbcsounds', bbcSounds); +} From 025bbaba76d69e2cf9b6e1b233025efd36115400 Mon Sep 17 00:00:00 2001 From: jsiegenthaler <59387202+jsiegenthaler@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:47:45 +0100 Subject: [PATCH 20/43] Update README.md Updated Readme to make Sonos S2 update more time-relevant, as S2 was released in June 2020 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6e2aaff7..121479c8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ⚠WARNING!⚠ -The upcoming Sonos software update (dubbed S2) seems to still work. However, it might break in the future if and when they decide to drop UPnP as control protocol. +The Sonos S2 update, released June 2020, still works with this API. However, it might break in the future if and when Sonos decide to drop UPnP as the control protocol. Feel free to use it as you please. Consider donating if you want to support further development. Reach out on the gitter chat if you have issues getting it to run, instead of creating new issues, thank you! From 00efb653a6e22e13adfe62c4e7788aa63696a7d1 Mon Sep 17 00:00:00 2001 From: jsiegenthaler <59387202+jsiegenthaler@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:57:08 +0100 Subject: [PATCH 21/43] Update README.md Fixed small grammar error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 121479c8..3c8bb489 100644 --- a/README.md +++ b/README.md @@ -610,7 +610,7 @@ To get a current list of voices, you would need to use the AWS CLI and invoke th #### Google (default if no other has been configured) -Does not require any API keys. Please note that Google has been known in the past to change the requirements for its Text-to-Speech API, and this may stop working in the future. There is also limiations to have many request one is allowed to do in a specific time period. +Does not require any API keys. Please note that Google has been known in the past to change the requirements for its Text-to-Speech API, and this may stop working in the future. There is also limiations to how many requests one is allowed to do in a specific time period. The following language codes are supported From 2a22f8a6de021af3380c979320d82f19de2cdfaa Mon Sep 17 00:00:00 2001 From: ashenshugarRET <42817877+ashenshugarRET@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:24:19 +0000 Subject: [PATCH 22/43] Adding instruction for BBC Sounds Service (#826) * Update README.md to include BBC Sounds Instructions Update README.md to include BBC Sounds Instructions * Update README.md Completion of documentation for BBC Sounds service * Create bbSounds.js Copying file from @tomslominski pull request to add BBC Sounds to @jishi/node-sonos-http-api * Rename bbSounds.js to bbcSounds.js * Update README.md Correction to stream names and available streams * Delete bbcSounds.js --- README.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/README.md b/README.md index 3c8bb489..a020d082 100644 --- a/README.md +++ b/README.md @@ -851,6 +851,84 @@ The format is: https://music.amazon.de/albums/{albumID}?trackAsin={songID}&ref=d The format is: https://music.amazon.de/albums/{albumID}?ref=dm_sh_97aa-255b-dmcp-c6ba-4ff00&musicTerritory=DE&marketplaceId=A1PA6795UKMFR9 > eg: https://music.amazon.de/albums/B0727SH7LW?ref=dm_sh_97aa-255b-dmcp-c6ba-4ff00&musicTerritory=DE&marketplaceId=A1PA6795UKMFR9 +BBC Sounds +---------------------- +You can specify a BBC station and the station will be played or set depending on the command used. + +To play immediately: +``` +/RoomName/bbcsounds/play/{stream code} +``` +To set the station without playing: +``` +/RoomName/bbcsounds/set/{stream code} +``` + +Refer to the table below for available codes for BBC Radio Stations + +| BBC Radio Station Name | Stream Code | +|----------------------------------|----------------------------------| +| BBC Radio 1 | bbc_radio_one | +| BBC 1Xtra | bbc_1xtra | +| BBC 1Dance | bbc_1dance | +| BBC 1Relax | bbc_1relax | +| BBC Radio 2 | bbc_radio_two | +| BBC Radio 3 | bbc_radio_three | +| BBC Radio 4 | bbc_radio_four | +| BBC Radio 4 Extra | bbc_radio_four_extra | +| BBC Radio 5 Live | bbc_radio_five_live | +| BBC Radio 5 Live Sports Extra | bbc_five_live_sports_extra | +| BBC Radio 6 Music | bbc_6music | +| BBC Asian Network | bbc_asian_network | +| BBC Radio Berkshire | bbc_radio_berkshire | +| BBC Radio Bristol | bbc_radio_bristol | +| BBC Radio Cambridge | bbc_radio_cambridge | +| BBC Radio Cornwall | bbc_radio_cornwall | +| BBC Radio Cumbria | bbc_radio_cumbria | +| BBC Radio Cymru | bbc_radio_cymru | +| BBC Radio Cymru 2 | bbc_radio_cymru_2 | +| BBC Radio CWR | bbc_radio_coventry_warwickshire | +| BBC Radio Derby | bbc_radio_derby | +| BBC Radio Devon | bbc_radio_devon | +| BBC Radio Essex | bbc_radio_essex | +| BBC Radio Foyle | bbc_radio_foyle | +| BBC Radio Gloucestershire | bbc_radio_gloucestershire | +| BBC Radio Guernsey | bbc_radio_guernsey | +| BBC Radio Hereford Worcester | bbc_radio_hereford_worcester | +| BBC Radio Humberside | bbc_radio_humberside | +| BBC Radio Jersey | bbc_radio_jersey | +| BBC Radio Kent | bbc_radio_kent | +| BBC Radio Lancashire | bbc_radio_lancashire | +| BBC Radio Leeds | bbc_radio_leeds | +| BBC Radio Leicester | bbc_radio_leicester | +| BBC Radio Lincolnshire | bbc_radio_lincolnshire | +| BBC Radio London | bbc_london | +| BBC Radio Manchester | bbc_radio_manchester | +| BBC Radio Merseyside | bbc_radio_merseyside | +| BBC Radio nan Gaidheal | bbc_radio_nan_gaidheal | +| BBC Radio Newcastle | bbc_radio_newcastle | +| BBC Radio Norfolk | bc_radio_norfolk | +| BBC Radio Northampton | bbc_radio_northampton | +| BBC Radio Nottingham | bbc_radio_nottingham | +| BBC Radio Oxford | bbc_radio_oxford | +| BBC Radio Scotland FM | bbc_radio_scotland_fm | +| BBC Radio Sheffield | bbc_radio_sheffield | +| BBC Radio Shropshire | bbc_radio_shropshire | +| BBC Radio Solent | bbc_radio_solent | +| BBC Radio Somerset | bbc_radio_somerset_sound | +| BBC Radio Stoke | bbc_radio_stoke | +| BBC Radio Suffolk | bbc_radio_suffolk | +| BBC Radio Surrey | bbc_radio_surrey | +| BBC Radio Sussex | bbc_radio_sussex | +| BBC Radio Tees | bbc_tees | +| BBC Radio Three Counties Radio | bbc_three_counties_radio | +| BBC Radio Ulster | bbc_radio_ulster | +| BBC Radio Wales | bbc_radio_wales_fm | +| BBC Radio Wiltshire | bbc_radio_wiltshire | +| BBC Radio WM | bbc_wm | +| BBC Radio York | bbc_radio_york | +| BBC World_Service | bbc_world_service | +| Cbeebies Radio | cbeebies_radio | SiriusXM ---------------------- From 44096ce9103e30c58832bf4bdf52f2bcb11fd676 Mon Sep 17 00:00:00 2001 From: ashenshugarRET <42817877+ashenshugarRET@users.noreply.github.com> Date: Wed, 30 Mar 2022 07:59:05 +0100 Subject: [PATCH 23/43] Update to README.md to clarify services need to be installed Add clarity that the services need to be installed in the SONOS account for node-sonos-http-api to be able control them. Added clarity that the BBC Sounds service is only available in the UK --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a020d082..4ad12503 100644 --- a/README.md +++ b/README.md @@ -786,7 +786,9 @@ Switch "placement adjustment" or more commonly known as phase. 0 = 0°, 1 = 180 Spotify, Apple Music and Amazon Music (Experimental) ---------------------- -Allows you to perform your own external searches for Apple Music or Spotify songs or albums and play a specified song or track ID. The Music Search funtionality outlined further below performs a search of its own and plays the specified music. +Allows you to perform your own external searches for Spotify, Apple Music or Amazon Music songs or albums and play a specified song or track ID. The Music Search funtionality outlined further below performs a search of its own and plays the specified music. + +Ensure you have added and registered the respective service with your Sonos account, before trying to control your speakers with node-sonos-http-api. Instructions on how to do this can be found here: https://support.sonos.com/s/article/2757?language=en_US The following endpoints are available: @@ -851,8 +853,10 @@ The format is: https://music.amazon.de/albums/{albumID}?trackAsin={songID}&ref=d The format is: https://music.amazon.de/albums/{albumID}?ref=dm_sh_97aa-255b-dmcp-c6ba-4ff00&musicTerritory=DE&marketplaceId=A1PA6795UKMFR9 > eg: https://music.amazon.de/albums/B0727SH7LW?ref=dm_sh_97aa-255b-dmcp-c6ba-4ff00&musicTerritory=DE&marketplaceId=A1PA6795UKMFR9 -BBC Sounds +BBC Sounds (as of 2022 only available in the UK) ---------------------- +Ensure you have added and registered the BBC Sounds service with your Sonos account, before trying to control your speakers with node-sonos-http-api. Instructions on how to do this can be found here: https://www.bbc.co.uk/sounds/help/questions/listening-on-a-smart-speaker/sonos or here: https://support.sonos.com/s/article/2757?language=en_US + You can specify a BBC station and the station will be played or set depending on the command used. To play immediately: From 77420b4f4fae1c229045b9db902f6fc2e567f23a Mon Sep 17 00:00:00 2001 From: Jim Lamb Date: Wed, 9 Nov 2022 09:27:06 +0000 Subject: [PATCH 24/43] Correct BBC Sounds stream code for BBC Radio 4, creating FM and LW variations --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ad12503..0ed74289 100644 --- a/README.md +++ b/README.md @@ -878,7 +878,8 @@ Refer to the table below for available codes for BBC Radio Stations | BBC 1Relax | bbc_1relax | | BBC Radio 2 | bbc_radio_two | | BBC Radio 3 | bbc_radio_three | -| BBC Radio 4 | bbc_radio_four | +| BBC Radio 4 FM | bbc_radio_fourfm | +| BBC Radio 4 LW | bbc_radio_fourlw | | BBC Radio 4 Extra | bbc_radio_four_extra | | BBC Radio 5 Live | bbc_radio_five_live | | BBC Radio 5 Live Sports Extra | bbc_five_live_sports_extra | From 8e6f57992ecc8035472085d566a0356d4c4d6b87 Mon Sep 17 00:00:00 2001 From: jsiegenthaler <59387202+jsiegenthaler@users.noreply.github.com> Date: Tue, 5 Apr 2022 07:42:12 +0200 Subject: [PATCH 25/43] Update README.md Fix spelling mistake, improve readability --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ed74289..d950bb4c 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ The actions supported as of today: * sub (on/off/gain/crossover/polarity) See SUB section for more info * nightmode (on/off/toggle, PLAYBAR only) * speechenhancement (on/off/toggle, PLAYBAR only) -* bass/treble (use -10 thru 10 as value. 0 is neutral) +* bass/treble (use -10 through to 10 as the value. 0 is neutral) State From 61790dbd7e6ea114844d2ab430a7460851616e49 Mon Sep 17 00:00:00 2001 From: ashenshugarRET <42817877+ashenshugarRET@users.noreply.github.com> Date: Fri, 20 Jan 2023 19:12:24 +0000 Subject: [PATCH 26/43] Update BBC Sounds Station references Updating BBC Sounds Station references in the README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d950bb4c..238b3c71 100644 --- a/README.md +++ b/README.md @@ -874,8 +874,8 @@ Refer to the table below for available codes for BBC Radio Stations |----------------------------------|----------------------------------| | BBC Radio 1 | bbc_radio_one | | BBC 1Xtra | bbc_1xtra | -| BBC 1Dance | bbc_1dance | -| BBC 1Relax | bbc_1relax | +| BBC 1Dance | bbc_radio_one_dance | +| BBC 1Relax | bbc_radio_one_relax | | BBC Radio 2 | bbc_radio_two | | BBC Radio 3 | bbc_radio_three | | BBC Radio 4 FM | bbc_radio_fourfm | @@ -917,6 +917,7 @@ Refer to the table below for available codes for BBC Radio Stations | BBC Radio Nottingham | bbc_radio_nottingham | | BBC Radio Oxford | bbc_radio_oxford | | BBC Radio Scotland FM | bbc_radio_scotland_fm | +| BBC Radio Scotland Extra | bbc_radio_scotland_mw | | BBC Radio Sheffield | bbc_radio_sheffield | | BBC Radio Shropshire | bbc_radio_shropshire | | BBC Radio Solent | bbc_radio_solent | @@ -929,6 +930,7 @@ Refer to the table below for available codes for BBC Radio Stations | BBC Radio Three Counties Radio | bbc_three_counties_radio | | BBC Radio Ulster | bbc_radio_ulster | | BBC Radio Wales | bbc_radio_wales_fm | +| BBC Radio Wales Extra | bbc_radio_wales_am | | BBC Radio Wiltshire | bbc_radio_wiltshire | | BBC Radio WM | bbc_wm | | BBC Radio York | bbc_radio_york | From 5d9e5354374bb789daef02fd4d0f2ba88bd6b79e Mon Sep 17 00:00:00 2001 From: Tim Otto Date: Mon, 27 Feb 2023 20:22:25 +0100 Subject: [PATCH 27/43] Add HTTP event source endpoint --- lib/sonos-http-api.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/sonos-http-api.js b/lib/sonos-http-api.js index 3b11c8a4..135d4095 100644 --- a/lib/sonos-http-api.js +++ b/lib/sonos-http-api.js @@ -9,6 +9,7 @@ function HttpAPI(discovery, settings) { const port = settings.port; const webroot = settings.webroot; const actions = {}; + const events = new HttpEventServer(); this.getWebRoot = function () { return webroot; @@ -52,6 +53,11 @@ function HttpAPI(discovery, settings) { return; } + if (req.url === '/events') { + events.addClient(res); + return; + } + if (discovery.zones.length === 0) { const msg = 'No system has yet been discovered. Please see https://github.com/jishi/node-sonos-http-api/issues/77 if it doesn\'t resolve itself in a few seconds.'; logger.error(msg); @@ -122,7 +128,6 @@ function HttpAPI(discovery, settings) { function invokeWebhook(type, data) { var typeName = "type"; var dataName = "data"; - if (!settings.webhook) return; if (settings.webhookType) { typeName = settings.webhookType; } if (settings.webhookData) { dataName = settings.webhookData; } @@ -132,6 +137,10 @@ function HttpAPI(discovery, settings) { [dataName]: data }); + events.sendEvent(jsonBody); + + if (!settings.webhook) return; + const body = new Buffer(jsonBody, 'utf8'); var headers = { @@ -156,4 +165,22 @@ function HttpAPI(discovery, settings) { } +function HttpEventServer() { + let clients = []; + + const removeClient = client => clients = clients.filter(value => value !== client); + + this.addClient = res => clients.push(new HttpEventSource(res, removeClient)); + + this.sendEvent = event => clients.forEach(client => client.sendEvent(event)) +} + +function HttpEventSource(res, done) { + this.sendEvent = event => res.write('data: ' + event + '\n\n') + + res.on('close', () => done(this)) + + res.setHeader('Content-Type', 'text/event-stream'); +} + module.exports = HttpAPI; From 35ccda34178ef63494119fa6527af12a87b89041 Mon Sep 17 00:00:00 2001 From: Tim Otto Date: Sun, 5 Mar 2023 19:53:52 +0100 Subject: [PATCH 28/43] refactoring --- lib/helpers/http-event-server.js | 19 +++++++++++++++++++ lib/sonos-http-api.js | 19 +------------------ 2 files changed, 20 insertions(+), 18 deletions(-) create mode 100644 lib/helpers/http-event-server.js diff --git a/lib/helpers/http-event-server.js b/lib/helpers/http-event-server.js new file mode 100644 index 00000000..56e5d176 --- /dev/null +++ b/lib/helpers/http-event-server.js @@ -0,0 +1,19 @@ +function HttpEventServer() { + let clients = []; + + const removeClient = client => clients = clients.filter(value => value !== client); + + this.addClient = res => clients.push(new HttpEventSource(res, removeClient)); + + this.sendEvent = event => clients.forEach(client => client.sendEvent(event)) +} + +function HttpEventSource(res, done) { + this.sendEvent = event => res.write('data: ' + event + '\n\n') + + res.on('close', () => done(this)) + + res.setHeader('Content-Type', 'text/event-stream'); +} + +module.exports = HttpEventServer; diff --git a/lib/sonos-http-api.js b/lib/sonos-http-api.js index 135d4095..bc38520f 100644 --- a/lib/sonos-http-api.js +++ b/lib/sonos-http-api.js @@ -3,6 +3,7 @@ const requireDir = require('./helpers/require-dir'); const path = require('path'); const request = require('sonos-discovery/lib/helpers/request'); const logger = require('sonos-discovery/lib/helpers/logger'); +const HttpEventServer = require('./helpers/http-event-server'); function HttpAPI(discovery, settings) { @@ -165,22 +166,4 @@ function HttpAPI(discovery, settings) { } -function HttpEventServer() { - let clients = []; - - const removeClient = client => clients = clients.filter(value => value !== client); - - this.addClient = res => clients.push(new HttpEventSource(res, removeClient)); - - this.sendEvent = event => clients.forEach(client => client.sendEvent(event)) -} - -function HttpEventSource(res, done) { - this.sendEvent = event => res.write('data: ' + event + '\n\n') - - res.on('close', () => done(this)) - - res.setHeader('Content-Type', 'text/event-stream'); -} - module.exports = HttpAPI; From aac16a5161ffef5721ed88f11901576bcdca7664 Mon Sep 17 00:00:00 2001 From: Tim Otto Date: Sun, 5 Mar 2023 20:23:40 +0100 Subject: [PATCH 29/43] explain /events endpoint --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index 238b3c71..73ef19eb 100644 --- a/README.md +++ b/README.md @@ -1101,6 +1101,31 @@ or "data" property will be equal to the same data as you would get from /RoomName/state or /zones. There is an example endpoint in the root if this project called test_endpoint.js which you may fire up to get an understanding of what is posted, just invoke it with "node test_endpoint.js" in a terminal, and then start the http-api in another terminal. +Server Sent Events +----- + +As an alternative to the web hook you can also call the `/events` endpoint to receive every state change and topology change as [Server Sent Event](https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events). +Compared to the web hook there is no configuration required on the server, and you can listen for events from multiple clients. + +Because it is a long-polling connection, you must take care of errors in your client code and re-connect if necessary. + +The server sends events formatted as single-line JSON in the format of Server Sent Events: every event starts with the string `data: `, followed by the single-line JSON formatted event, and is terminated by two new line characters. + +There are [several client libraries available](https://en.wikipedia.org/wiki/Server-sent_events#Libraries) to listen for Server Sent Events. +Using `curl` yields the following output for some volume changes: + +```shell +host:~ user$ curl localhost:5005/events +data: {"type":"volume-change","data":{"uuid":"RINCON_E2832F58D9074C45B","previousVolume":13,"newVolume":19,"roomName":"Office"}} + +data: {"type":"volume-change","data":{"uuid":"RINCON_E2832F58D9074C45B","previousVolume":19,"newVolume":25,"roomName":"Office"}} + +data: {"type":"volume-change","data":{"uuid":"RINCON_E2832F58D9074C45B","previousVolume":25,"newVolume":24,"roomName":"Office"}} + +data: {"type":"volume-change","data":{"uuid":"RINCON_E2832F58D9074C45B","previousVolume":23,"newVolume":23,"roomName":"Office"}} + +``` + DOCKER ----- From ec87f092cc720b5f75620f518a18526976d1bcae Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Sun, 2 Apr 2023 15:42:25 -0700 Subject: [PATCH 30/43] add apple music playlist support --- lib/actions/appleMusic.js | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/actions/appleMusic.js b/lib/actions/appleMusic.js index 7099aa8e..015fac90 100644 --- a/lib/actions/appleMusic.js +++ b/lib/actions/appleMusic.js @@ -1,8 +1,9 @@ 'use strict'; + function getMetadata(id, parentUri, type, title) { return ` - "${title}"object.item.audioItem.${type} + "${title}"${type} SA_RINCON52231_X_#Svc52231-0-Token`; } @@ -14,53 +15,63 @@ function getAlbumUri(id) { return `x-rincon-cpcontainer:0004206c${id}`; } +function getPlaylistUri(id) { + return `x-rincon-cpcontainer:1006206c${id}`; +} + const uriTemplates = { song: getSongUri, - album: getAlbumUri + album: getAlbumUri, + playlist: getPlaylistUri, }; const CLASSES = { - song: 'musicTrack', - album: 'musicAlbum' + song: 'object.item.audioItem.musicTrack', + album: 'object.item.audioItem.musicAlbum', + playlist: 'object.container.playlistContainer.#PlaylistView' }; const METADATA_URI_STARTERS = { song: '00032020', - album: '0004206c' + album: '0004206c', + playlist: '1006206c' }; const PARENTS = { song: '0004206calbum%3a', - album: '00020000album%3a' + album: '00020000album%3a', + playlist: '1006206cplaylist%3a' }; function appleMusic(player, values) { const action = values[0]; const trackID = values[1]; const type = trackID.split(':')[0]; - var nextTrackNo = 0; + let nextTrackNo = 0; const metadataID = METADATA_URI_STARTERS[type] + encodeURIComponent(trackID); const metadata = getMetadata(metadataID, PARENTS[type], CLASSES[type], ''); const uri = uriTemplates[type](encodeURIComponent(trackID)); - if (action == 'queue') { + if (action === 'queue') { return player.coordinator.addURIToQueue(uri, metadata); - } else if (action == 'now') { + } else if (action === 'now') { nextTrackNo = player.coordinator.state.trackNo + 1; let promise = Promise.resolve(); if (player.coordinator.avTransportUri.startsWith('x-rincon-queue') === false) { promise = promise.then(() => player.coordinator.setAVTransport(`x-rincon-queue:${player.coordinator.uuid}#0`)); } return promise.then(() => player.coordinator.addURIToQueue(uri, metadata, true, nextTrackNo)) - .then(() => { if (nextTrackNo != 1) player.coordinator.nextTrack() }) + .then(() => { if (nextTrackNo !== 1) player.coordinator.nextTrack(); }) .then(() => player.coordinator.play()); - } else if (action == 'next') { + } else if (action === 'next') { nextTrackNo = player.coordinator.state.trackNo + 1; return player.coordinator.addURIToQueue(uri, metadata, true, nextTrackNo); } + + return null; } -module.exports = function (api) { +module.exports = function appleMusicAction(api) { api.registerAction('applemusic', appleMusic); }; From 7f46c8aa6f04e0bd098f838bac02ee669a5e18fd Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Thu, 30 Mar 2023 00:10:13 -0700 Subject: [PATCH 31/43] fix: use correct variable for shuffle response --- lib/actions/playmode.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/actions/playmode.js b/lib/actions/playmode.js index 2746beee..7aa2f634 100644 --- a/lib/actions/playmode.js +++ b/lib/actions/playmode.js @@ -23,7 +23,7 @@ function shuffle(player, values) { let enable = values[0] === "on"; if(values[0] == "toggle") enable = !player.coordinator.state.playMode.shuffle; return player.coordinator.shuffle(enable).then((response) => { - return { status: 'success', shuffle: mode }; + return { status: 'success', shuffle: enable }; }); } @@ -39,4 +39,4 @@ module.exports = function (api) { api.registerAction('repeat', repeat); api.registerAction('shuffle', shuffle); api.registerAction('crossfade', crossfade); -} \ No newline at end of file +} From 6637dad7cbe5d0249ca5e7c050865a38e2309523 Mon Sep 17 00:00:00 2001 From: "daniel.schroeder" Date: Sun, 22 Jan 2023 10:41:02 +0100 Subject: [PATCH 32/43] support for AWS polly neural engine --- README.md | 4 +- lib/tts-providers/aws-polly.js | 4 + package-lock.json | 2952 +++++++++++++++++++++++++++++++- package.json | 2 +- 4 files changed, 2923 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 73ef19eb..b3bacf0e 100644 --- a/README.md +++ b/README.md @@ -531,7 +531,9 @@ You can also specify it for this application only, using: } ``` -Choose the region where you registered your account, or the one closest to you. Polly is only supported in US East (Northern Virginia), US West (Oregon), US East (Ohio), and EU (Ireland) as of today (dec 2016) +To select the neural engine, append `Neural` to the name, e.g. `DanielNeural`. + +Choose the region where you registered your account, or the one closest to you. If you have your credentials elsewhere and want to stick with the default voice, you still need to make sure that the aws config option is set to trigger AWS TTS: diff --git a/lib/tts-providers/aws-polly.js b/lib/tts-providers/aws-polly.js index bd7aa35e..aab95e63 100644 --- a/lib/tts-providers/aws-polly.js +++ b/lib/tts-providers/aws-polly.js @@ -29,6 +29,10 @@ function polly(phrase, voiceName) { if (voiceName) { synthesizeParameters.VoiceId = voiceName; } + if (synthesizeParameters.VoiceId.endsWith('Neural')) { + synthesizeParameters.Engine = 'neural'; + synthesizeParameters.VoiceId = synthesizeParameters.VoiceId.slice(0, -6); + } const phraseHash = crypto.createHash('sha1').update(phrase).digest('hex'); const filename = `polly-${phraseHash}-${synthesizeParameters.VoiceId}.mp3`; diff --git a/package-lock.json b/package-lock.json index 8ce6f9ce..94f21c64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,2776 @@ { "name": "sonos-http-api", "version": "1.6.9", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "sonos-http-api", + "version": "1.6.9", + "license": "MIT", + "dependencies": { + "anesidora": "^1.2.0", + "aws-sdk": "^2.1299.0", + "basic-auth": "~1.1.0", + "fuse.js": "^6.4.1", + "html-entities": "^1.2.1", + "json5": "^0.5.1", + "mime": "^1.4.1", + "music-metadata": "^1.1.0", + "node-static": "^0.7.9", + "request-promise": "~1.0.2", + "sonos-discovery": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.3.tar.gz", + "wav-file-info": "0.0.8" + }, + "devDependencies": { + "eslint": "^4.8.0", + "eslint-config-airbnb-base": "^12.0.1", + "eslint-plugin-import": "^2.7.0" + }, + "engines": { + "node": ">=4.0.0", + "npm": "^2.0.0" + } + }, + "node_modules/acorn": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", + "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "dependencies": { + "acorn": "^3.0.4" + } + }, + "node_modules/acorn-jsx/node_modules/acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dependencies": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "node_modules/ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true, + "peerDependencies": { + "ajv": "^5.0.0" + } + }, + "node_modules/anesidora": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/anesidora/-/anesidora-1.2.1.tgz", + "integrity": "sha1-/ZWdrLiPx6im5xE+OA8/rQmTipo=", + "dependencies": { + "request": "^2.64.0", + "underscore": "^1.8.3" + } + }, + "node_modules/ansi-escapes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sdk": { + "version": "2.1299.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1299.0.tgz", + "integrity": "sha512-xTh6pmCUEJljkFfTM3sE8UozDxal80uX/5WZl8GcjQ+NbrGeQEdvL6wFWBwEEVbhR0VBVuU37cKPuQlfENbRYA==", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.4.19" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", + "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" + }, + "node_modules/babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "node_modules/babel-code-frame/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "optional": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "dependencies": { + "callsites": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "node_modules/chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "node_modules/circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "deprecated": "CircularJSON is in maintenance only, flatted is its successor.", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "node_modules/cls-bluebird": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-1.1.3.tgz", + "integrity": "sha1-syY8EaCJsDlhhaG3q5BNkPAq1Cg=", + "dependencies": { + "is-bluebird": "^1.0.1", + "shimmer": "^1.1.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "dev": true, + "dependencies": { + "color-name": "1.1.1" + } + }, + "node_modules/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", + "dev": true + }, + "node_modules/colors": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.1.tgz", + "integrity": "sha512-jg/vxRmv430jixZrC+La5kMbUWqIg32/JsYNZb94+JEmzceYbWKTsv1OuTp+7EaqiaWRR2tPcykibwCRgclIsw==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "node_modules/del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "dependencies": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "optional": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "dependencies": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", + "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", + "dev": true, + "dependencies": { + "eslint-restricted-globals": "^0.1.1" + }, + "engines": { + "node": ">= 4" + }, + "peerDependencies": { + "eslint": "^4.9.0", + "eslint-plugin-import": "^2.7.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", + "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "dev": true, + "dependencies": { + "debug": "^2.6.8", + "pkg-dir": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", + "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==", + "dev": true, + "dependencies": { + "contains-path": "^0.1.0", + "debug": "^2.6.8", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.1", + "eslint-module-utils": "^2.2.0", + "has": "^1.0.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.3", + "read-pkg-up": "^2.0.0", + "resolve": "^1.6.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "2.x - 5.x" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true + }, + "node_modules/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "dev": true, + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "dependencies": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "dependencies": { + "estraverse": "^4.0.0" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "dependencies": { + "estraverse": "^4.1.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "dependencies": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "dependencies": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "dev": true, + "dependencies": { + "circular-json": "^0.3.1", + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-extra": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/fuse.js": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.4.1.tgz", + "integrity": "sha512-+hAS7KYgLXontDh/vqffs7wIBw0ceb9Sx8ywZQhOsiQGcSO5zInGhttWOUYQYlvV/yYMJOacQ129Xs3mP3+oZQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^5.1.0", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "node_modules/html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "engines": [ + "node >= 0.4.0" + ] + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bluebird": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", + "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "dependencies": { + "builtin-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "node_modules/is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "node_modules/json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "dependencies": { + "mime-db": "~1.35.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/music-metadata": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-1.1.0.tgz", + "integrity": "sha512-HTIWhewHyLwVQByhh45BGtmxrEDpq4RI4ZwUKYBwj7uPheE+MmudlnRc22emq99GRLGmb16/Q7RgM+3O0Wi2wg==", + "dependencies": { + "bluebird": "^3.5.1", + "debug": "^3.1.0", + "fs-extra": "^6.0.1", + "strtok3": "^1.4.2", + "then-read-stream": "^1.1.3", + "token-types": "^0.9.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/music-metadata/node_modules/bluebird": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" + }, + "node_modules/mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-static": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/node-static/-/node-static-0.7.10.tgz", + "integrity": "sha512-bd7zO5hvCWzdglgwz9t82T4mYTEUzEG5pXnSqEzitvmEacusbhl8/VwuCbMaYR9g2PNK5191yBtAEQLJEmQh1A==", + "dependencies": { + "colors": ">=0.6.0", + "mime": "^1.2.9", + "optimist": ">=0.3.4" + }, + "bin": { + "static": "bin/cli.js" + }, + "engines": { + "node": ">= 0.4.1" + } + }, + "node_modules/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dependencies": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "node_modules/optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/optionator/node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "node_modules/path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "node_modules/path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "dependencies": { + "pify": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "dependencies": { + "find-up": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "dependencies": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/request": { + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/request-promise": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-1.0.2.tgz", + "integrity": "sha1-FV9BBgjZJXwInB0LJvjY96iqhqE=", + "deprecated": "request-promise has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", + "dependencies": { + "bluebird": "^2.3", + "cls-bluebird": "^1.0.1", + "lodash": "^3.10.0", + "request": "^2.34" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/request-promise/node_modules/lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + }, + "node_modules/require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "dependencies": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.5" + } + }, + "node_modules/resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "dependencies": { + "glob": "^7.0.5" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "dependencies": { + "is-promise": "^2.1.0" + }, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "node_modules/rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "dependencies": { + "rx-lite": "*" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + }, + "node_modules/semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-xTCx2vohXC2EWWDqY/zb4+5Mu28D+HYNSOuFzsyRDRvI/e1ICb69afwaUwfjr+25ZXldbOLyp+iDUZHq8UnTag==" + }, + "node_modules/signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "node_modules/slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sonos-discovery": { + "version": "1.7.3", + "resolved": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.3.tar.gz", + "integrity": "sha512-bHog/7+zjirplyZOjclSM9g6rZVZX0bDWX+PzkS6KN0I1/KK6SjotazhkI4nhcrx4NYWnxCQULIO9RvzlyG2uA==", + "dependencies": { + "html-entities": "1.0.x", + "xml-flow": "1.0.2" + } + }, + "node_modules/sonos-discovery/node_modules/html-entities": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.0.10.tgz", + "integrity": "sha1-DepZEw3VDfFU6CxM9x0Iwsnclos=", + "engines": [ + "node >= 0.4.0" + ] + }, + "node_modules/spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "dashdash": "^1.12.0", + "getpass": "^0.1.1", + "safer-buffer": "^2.0.2" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + }, + "optionalDependencies": { + "bcrypt-pbkdf": "^1.0.0", + "ecc-jsbn": "~0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strtok3": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-1.6.0.tgz", + "integrity": "sha512-BDr7b5RJSfvX1wBjJDwpJOGZ0EhfhZaMCm+YaOVAcvFgo8/+nJq/Vurzh7JykAgiW+EOo5kkrfVffBFFp3u8TQ==", + "dependencies": { + "debug": "^3.1.0", + "es6-promise": "^4.2.4", + "then-read-stream": "^1.2.1", + "token-types": "^0.10.0" + }, + "engines": { + "node": ">=0.1.98" + } + }, + "node_modules/strtok3/node_modules/token-types": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-0.10.0.tgz", + "integrity": "sha512-26A0816VoHW8h64OT47dcclsH5M9iwo9zi3KoCPz1NrKoI9T2dlVkisgzTaGK4dPjCbP3ugf7cYqhWOiAzVHgw==", + "engines": { + "node": ">=0.1.98" + } + }, + "node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "dependencies": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/then-read-stream": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/then-read-stream/-/then-read-stream-1.5.1.tgz", + "integrity": "sha512-I+iiemYWhp1ysJQEioqpEICgvHlqHS5WrQGZkboFLs7Jm350Kvq4cN3qRCzHpETUuq5+NsdrdWEg6M0NFxtwtQ==", + "deprecated": "Package renamed to peak-readable.", + "engines": { + "node": ">=8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/token-types": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-0.9.4.tgz", + "integrity": "sha512-KSl/Q1GJ4FoxbqKCLhTiIowVzom2cP0fgWGXKsJupbJQqfnCDmxkdMopIrt+y5Ak6YAGdy9TKpplWDioaBsbEw==", + "engines": { + "node": ">=0.1.98" + } + }, + "node_modules/tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dependencies": { + "punycode": "^1.4.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "node_modules/underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", + "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/wav-file-info": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/wav-file-info/-/wav-file-info-0.0.8.tgz", + "integrity": "sha1-aAp160w0a34/RX55AqexmDUG5N4=" + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xml-flow": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xml-flow/-/xml-flow-1.0.2.tgz", + "integrity": "sha512-TfV52Su2083n8w61l1hGI5K3ZAkn4hmaon3oJHc+TRQo0QkKLMPAPdMpGMJd+5Aik6ZUicPDjBINO8QxLkZGgg==", + "dependencies": { + "sax": "^1.2.4" + } + }, + "node_modules/xml-flow/node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "node_modules/xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + }, "dependencies": { "acorn": { "version": "5.7.1", @@ -116,26 +2884,32 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, "aws-sdk": { - "version": "2.284.1", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.284.1.tgz", - "integrity": "sha512-/fV2RGGhL13LH7xjccmAh/uoNEa3z+MWHRmHq+Arj2hKgpPoRNCC+8lLIAhxKcPLdJt/G9rcm2EnDqT9E/1aSA==", + "version": "2.1299.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1299.0.tgz", + "integrity": "sha512-xTh6pmCUEJljkFfTM3sE8UozDxal80uX/5WZl8GcjQ+NbrGeQEdvL6wFWBwEEVbhR0VBVuU37cKPuQlfENbRYA==", "requires": { - "buffer": "4.9.1", + "buffer": "4.9.2", "events": "1.1.1", - "ieee754": "1.1.8", - "jmespath": "0.15.0", + "ieee754": "1.1.13", + "jmespath": "0.16.0", "querystring": "0.2.0", "sax": "1.2.1", "url": "0.10.3", - "uuid": "3.1.0", + "util": "^0.12.4", + "uuid": "8.0.0", "xml2js": "0.4.19" }, "dependencies": { "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==" } } }, @@ -191,9 +2965,9 @@ "dev": true }, "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "basic-auth": { "version": "1.1.0", @@ -225,9 +2999,9 @@ } }, "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -246,6 +3020,15 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", @@ -774,6 +3557,14 @@ "write": "^0.2.1" } }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -808,8 +3599,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -822,6 +3612,16 @@ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.4.1.tgz", "integrity": "sha512-+hAS7KYgLXontDh/vqffs7wIBw0ceb9Sx8ywZQhOsiQGcSO5zInGhttWOUYQYlvV/yYMJOacQ129Xs3mP3+oZQ==" }, + "get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -864,6 +3664,14 @@ "pinkie-promise": "^2.0.0" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -887,7 +3695,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -907,6 +3714,19 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -938,9 +3758,9 @@ } }, "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "ignore": { "version": "3.3.10", @@ -967,8 +3787,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "inquirer": { "version": "3.3.0", @@ -992,6 +3811,15 @@ "through": "^2.3.6" } }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -1012,12 +3840,25 @@ "builtin-modules": "^1.0.0" } }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -1054,6 +3895,18 @@ "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -1076,9 +3929,9 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" }, "js-tokens": { "version": "3.0.2", @@ -1823,6 +4676,15 @@ "tweetnacl": "~0.14.0" } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -1833,15 +4695,6 @@ "strip-ansi": "^4.0.0" } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -2003,6 +4856,18 @@ } } }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -2048,6 +4913,19 @@ "isexe": "^2.0.0" } }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", diff --git a/package.json b/package.json index c19a4db9..db24d762 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "anesidora": "^1.2.0", - "aws-sdk": "^2.12.0", + "aws-sdk": "^2.1299.0", "basic-auth": "~1.1.0", "fuse.js": "^6.4.1", "html-entities": "^1.2.1", From 7e66c58b4e3c5b0e7f1d89808a721fdfcfb0853a Mon Sep 17 00:00:00 2001 From: mgorsk1 Date: Wed, 20 Dec 2023 09:48:22 +0100 Subject: [PATCH 33/43] :tada: Init --- README.md | 36 ++++++++++++ lib/tts-providers/elevenlabs.js | 99 +++++++++++++++++++++++++++++++++ package.json | 3 +- 3 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 lib/tts-providers/elevenlabs.js diff --git a/README.md b/README.md index b3bacf0e..14c1556d 100644 --- a/README.md +++ b/README.md @@ -403,6 +403,7 @@ Experimental support for TTS. Today the following providers are available: * AWS Polly * Google (default) * macOS say command +* Elevenlabs It will use the one you configure in settings.json. If you define settings for multiple TTS services, it will not be guaranteed which one it will choose! @@ -610,6 +611,41 @@ To get a current list of voices, you would need to use the AWS CLI and invoke th | Welsh | cy-GB | Female | Gwyneth | | Welsh English | en-GB-WLS | Male | Geraint | +#### Elevenlabs + +Elevenlabs is a TTS service enabling generatiung TTS audio files using AI generated voices. + +Requires API Key and optionally default voiceId. + +Since Elevenlabs AI models are multilingual by default, there is no need (nor place) for `language` parameter in +Elevenlabs API. Because of this, `language` parameter in URL is used to inject custom `voiceId` on per-request basis. You will +need to either configure default voiceId in `settings.json` or provide `voiceId` with every HTTP request. + +##### Config + +Minimal: +```json + { + "elevenlabs": { + "apiKey": "" + } + } +``` + +Full: +```json + { + "elevenlabs": { + "apiKey": "", + "voiceId": "", + "stability": 0.5, + "similarityBoost": 0.5, + "speakerBoost": true, + "style": 1 + } + } +``` + #### Google (default if no other has been configured) Does not require any API keys. Please note that Google has been known in the past to change the requirements for its Text-to-Speech API, and this may stop working in the future. There is also limiations to how many requests one is allowed to do in a specific time period. diff --git a/lib/tts-providers/elevenlabs.js b/lib/tts-providers/elevenlabs.js new file mode 100644 index 00000000..e7e7aeb6 --- /dev/null +++ b/lib/tts-providers/elevenlabs.js @@ -0,0 +1,99 @@ +'use strict'; +const crypto = require('crypto'); +const fs = require('fs'); +const http = require('http'); +const path = require('path'); +const ElevenLabs = require("elevenlabs-node"); +const fileDuration = require('../helpers/file-duration'); +const settings = require('../../settings'); +const logger = require('sonos-discovery/lib/helpers/logger'); + +const DEFAULT_SETTINGS = { + stability: 0.5, + similarityBoost: 0.5, + speakerBoost: true, + style: 1, +}; + +// Provider developed based on structure from aws-polly.js. +// In this tts provider language argument from uri is used to inject custom voiceId +function eleven(phrase, voiceId) { + if (!settings.elevenlabs) { + return Promise.resolve(); + } + + // Construct a filesystem neutral filename + const dynamicParameters = { textInput: phrase }; + const synthesizeParameters = Object.assign({}, DEFAULT_SETTINGS, dynamicParameters); + + if (settings.elevenlabs.stability) { + synthesizeParameters.stability = settings.elevenlabs.stability; + } + if (settings.elevenlabs.similarityBoost) { + synthesizeParameters.similarityBoost = settings.elevenlabs.similarityBoost; + } + if (settings.elevenlabs.modelId) { + synthesizeParameters.modelId = settings.elevenlabs.modelId; + } + if (settings.elevenlabs.style) { + synthesizeParameters.style = settings.elevenlabs.style; + } + if (settings.elevenlabs.speakerBoost) { + synthesizeParameters.speakerBoost = settings.elevenlabs.speakerBoost; + } + + let targetVoiceId; + if (voiceId) { + targetVoiceId = voiceId; + } + else if (settings.elevenlabs.voiceId) { + targetVoiceId = settings.elevenlabs.voiceId; + } + else { + console.log('Voice ID not provided neither as language nor in settings.') + return Promise.resolve(); + } + + const phraseHash = crypto.createHash('sha1').update(phrase).digest('hex'); + const filename = `elevenlabs-${phraseHash}-${targetVoiceId}.mp3`; + const filepath = path.resolve(settings.webroot, 'tts', filename); + + synthesizeParameters.fileName = filepath; + + const expectedUri = `/tts/${filename}`; + try { + fs.accessSync(filepath, fs.R_OK); + return fileDuration(filepath) + .then((duration) => { + return { + duration, + uri: expectedUri + }; + }); + } catch (err) { + logger.info(`announce file for phrase "${phrase}" does not seem to exist, downloading`); + } + + const voice = new ElevenLabs( + { + apiKey: settings.elevenlabs.apiKey, // Your API key from Elevenlabs + voiceId: targetVoiceId, // A Voice ID from Elevenlabs + } + ); + + return voice.textToSpeech(synthesizeParameters) + .then((res) => { + console.log('Elevenlabs TTS generated new audio file.'); + }) + .then(() => { + return fileDuration(filepath); + }) + .then((duration) => { + return { + duration, + uri: expectedUri + }; + }); +} + +module.exports = eleven; diff --git a/package.json b/package.json index db24d762..f930b987 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "node-static": "^0.7.9", "request-promise": "~1.0.2", "sonos-discovery": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.3.tar.gz", - "wav-file-info": "0.0.8" + "wav-file-info": "0.0.8", + "elevenlabs-node": "2.0.1" }, "engines": { "node": ">=4.0.0", From b0c81494e53230237c7448306d0c4741e5408f24 Mon Sep 17 00:00:00 2001 From: mgorsk1 Date: Wed, 20 Dec 2023 09:49:55 +0100 Subject: [PATCH 34/43] :fire: Removing code or files. --- lib/tts-providers/elevenlabs.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/tts-providers/elevenlabs.js b/lib/tts-providers/elevenlabs.js index e7e7aeb6..796f7814 100644 --- a/lib/tts-providers/elevenlabs.js +++ b/lib/tts-providers/elevenlabs.js @@ -32,9 +32,6 @@ function eleven(phrase, voiceId) { if (settings.elevenlabs.similarityBoost) { synthesizeParameters.similarityBoost = settings.elevenlabs.similarityBoost; } - if (settings.elevenlabs.modelId) { - synthesizeParameters.modelId = settings.elevenlabs.modelId; - } if (settings.elevenlabs.style) { synthesizeParameters.style = settings.elevenlabs.style; } From 50b5a171b1639acaa5003a328be86296aaf92dc4 Mon Sep 17 00:00:00 2001 From: mgorsk1 Date: Wed, 20 Dec 2023 22:40:12 +0100 Subject: [PATCH 35/43] :ok_hand: Updating code due to code review changes. --- README.md | 20 +++++++++++++------- lib/tts-providers/elevenlabs.js | 33 ++++++++------------------------- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 14c1556d..bc205af3 100644 --- a/README.md +++ b/README.md @@ -627,7 +627,9 @@ Minimal: ```json { "elevenlabs": { - "apiKey": "" + "auth": { + "apiKey": "" + } } } ``` @@ -636,12 +638,16 @@ Full: ```json { "elevenlabs": { - "apiKey": "", - "voiceId": "", - "stability": 0.5, - "similarityBoost": 0.5, - "speakerBoost": true, - "style": 1 + "auth": { + "apiKey": "" + }, + "config": { + "voiceId": "", + "stability": 0.5, + "similarityBoost": 0.5, + "speakerBoost": true, + "style": 1 + } } } ``` diff --git a/lib/tts-providers/elevenlabs.js b/lib/tts-providers/elevenlabs.js index 796f7814..937b1742 100644 --- a/lib/tts-providers/elevenlabs.js +++ b/lib/tts-providers/elevenlabs.js @@ -3,7 +3,7 @@ const crypto = require('crypto'); const fs = require('fs'); const http = require('http'); const path = require('path'); -const ElevenLabs = require("elevenlabs-node"); +const ElevenLabs = require('elevenlabs-node'); const fileDuration = require('../helpers/file-duration'); const settings = require('../../settings'); const logger = require('sonos-discovery/lib/helpers/logger'); @@ -24,35 +24,19 @@ function eleven(phrase, voiceId) { // Construct a filesystem neutral filename const dynamicParameters = { textInput: phrase }; - const synthesizeParameters = Object.assign({}, DEFAULT_SETTINGS, dynamicParameters); + const synthesizeParameters = Object.assign({}, DEFAULT_SETTINGS, dynamicParameters, settings.elevenlabs.config); - if (settings.elevenlabs.stability) { - synthesizeParameters.stability = settings.elevenlabs.stability; - } - if (settings.elevenlabs.similarityBoost) { - synthesizeParameters.similarityBoost = settings.elevenlabs.similarityBoost; - } - if (settings.elevenlabs.style) { - synthesizeParameters.style = settings.elevenlabs.style; - } - if (settings.elevenlabs.speakerBoost) { - synthesizeParameters.speakerBoost = settings.elevenlabs.speakerBoost; - } - - let targetVoiceId; if (voiceId) { - targetVoiceId = voiceId; - } - else if (settings.elevenlabs.voiceId) { - targetVoiceId = settings.elevenlabs.voiceId; + synthesizeParameters.voiceId = voiceId; } - else { - console.log('Voice ID not provided neither as language nor in settings.') + + if (!synthesizeParameters.voiceId) { + console.log('Voice ID not found neither in settings.elevenlabs.config nor in request!') return Promise.resolve(); } const phraseHash = crypto.createHash('sha1').update(phrase).digest('hex'); - const filename = `elevenlabs-${phraseHash}-${targetVoiceId}.mp3`; + const filename = `elevenlabs-${phraseHash}-${synthesizeParameters.voiceId}.mp3`; const filepath = path.resolve(settings.webroot, 'tts', filename); synthesizeParameters.fileName = filepath; @@ -73,8 +57,7 @@ function eleven(phrase, voiceId) { const voice = new ElevenLabs( { - apiKey: settings.elevenlabs.apiKey, // Your API key from Elevenlabs - voiceId: targetVoiceId, // A Voice ID from Elevenlabs + apiKey: settings.elevenlabs.auth.apiKey } ); From ae802fbe882efc574d4eba7ada0bda38ca4ff475 Mon Sep 17 00:00:00 2001 From: mgorsk1 Date: Fri, 22 Dec 2023 08:22:03 +0100 Subject: [PATCH 36/43] add default model multilingual --- lib/tts-providers/elevenlabs.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tts-providers/elevenlabs.js b/lib/tts-providers/elevenlabs.js index 937b1742..a0341f6c 100644 --- a/lib/tts-providers/elevenlabs.js +++ b/lib/tts-providers/elevenlabs.js @@ -13,6 +13,7 @@ const DEFAULT_SETTINGS = { similarityBoost: 0.5, speakerBoost: true, style: 1, + modelId: "eleven_multilingual_v2" }; // Provider developed based on structure from aws-polly.js. From e8e0f21e44ea5bf39a8f244b18e9ca7ab44bd6f7 Mon Sep 17 00:00:00 2001 From: mgorsk1 Date: Fri, 22 Dec 2023 09:02:27 +0100 Subject: [PATCH 37/43] rebase upstream package-lock.json --- package-lock.json | 193 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 183 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 94f21c64..2725c41a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "anesidora": "^1.2.0", "aws-sdk": "^2.1299.0", "basic-auth": "~1.1.0", + "elevenlabs-node": "2.0.1", "fuse.js": "^6.4.1", "html-entities": "^1.2.1", "json5": "^0.5.1", @@ -230,6 +231,40 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -629,6 +664,47 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/elevenlabs-node": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/elevenlabs-node/-/elevenlabs-node-2.0.1.tgz", + "integrity": "sha512-q6vUznhudS1yxYxTVP3sT3xWzSzoXH+y3T+4GE1X8gjGwJw1Inmko/paQfl4d+CpTQXGNWuACAlFUdIk96xebw==", + "dependencies": { + "axios": "^1.4.0", + "fs-extra": "^11.1.1" + } + }, + "node_modules/elevenlabs-node/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/elevenlabs-node/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/elevenlabs-node/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1007,6 +1083,25 @@ "node": ">=0.10.0" } }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -1147,12 +1242,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "engines": { - "node": ">=0.4.0" - } + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/har-schema": { "version": "2.0.0", @@ -2028,6 +2120,11 @@ "node": ">=0.4.0" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -2810,7 +2907,8 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true + "dev": true, + "requires": {} }, "anesidora": { "version": "1.2.1", @@ -2923,6 +3021,36 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" }, + "axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -3250,6 +3378,41 @@ "safer-buffer": "^2.1.0" } }, + "elevenlabs-node": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/elevenlabs-node/-/elevenlabs-node-2.0.1.tgz", + "integrity": "sha512-q6vUznhudS1yxYxTVP3sT3xWzSzoXH+y3T+4GE1X8gjGwJw1Inmko/paQfl4d+CpTQXGNWuACAlFUdIk96xebw==", + "requires": { + "axios": "^1.4.0", + "fs-extra": "^11.1.1" + }, + "dependencies": { + "fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==" + } + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3557,6 +3720,11 @@ "write": "^0.2.1" } }, + "follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -3673,9 +3841,9 @@ } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "har-schema": { "version": "2.0.0", @@ -4364,6 +4532,11 @@ "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", "dev": true }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", From 98f6ffeefef94e0342a51c6ab34124cc9329e33c Mon Sep 17 00:00:00 2001 From: mgorsk1 Date: Sat, 23 Dec 2023 11:11:26 +0100 Subject: [PATCH 38/43] :bulb: Documenting source code. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bc205af3..15806a76 100644 --- a/README.md +++ b/README.md @@ -646,7 +646,8 @@ Full: "stability": 0.5, "similarityBoost": 0.5, "speakerBoost": true, - "style": 1 + "style": 1, + "modelId": "eleven_multilingual_v2" } } } From 1fa4cdc998d6cf7b0448a2c622b51d352dd05a0b Mon Sep 17 00:00:00 2001 From: Barloew Date: Thu, 18 Jan 2024 12:09:53 +0100 Subject: [PATCH 39/43] Update README.md Add SonoBoss reference project, --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 15806a76..bb0b00f9 100644 --- a/README.md +++ b/README.md @@ -1231,3 +1231,8 @@ https://github.com/cjrpaterson/sonos-cron A Node server to receive notifications from node-sonos-http-api and push them via socket.io to the clients. https://github.com/TimoKorinth/sonos-push-server +**SonoBoss (Siri Shortcut)** + +A ChatGPT-assisted Siri Shortcut that acts as a virtual assistant to let you find music and control Sonos through voice and chat. +https://github.com/Barloew/SonoBoss + From fbcb628714fe6811d55492c03f1c135139713876 Mon Sep 17 00:00:00 2001 From: crissmil Date: Tue, 7 May 2024 00:42:07 +0300 Subject: [PATCH 40/43] server.js replace node-static with serve-static --- server.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index b795e13c..f59d6abd 100644 --- a/server.js +++ b/server.js @@ -6,22 +6,22 @@ const auth = require('basic-auth'); const SonosSystem = require('sonos-discovery'); const logger = require('sonos-discovery/lib/helpers/logger'); const SonosHttpAPI = require('./lib/sonos-http-api.js'); -const nodeStatic = require('node-static'); +const serveStatic = require('serve-static'); const settings = require('./settings'); -const fileServer = new nodeStatic.Server(settings.webroot); +const serve = new serveStatic(settings.webroot); const discovery = new SonosSystem(settings); const api = new SonosHttpAPI(discovery, settings); var requestHandler = function (req, res) { req.addListener('end', function () { - fileServer.serve(req, res, function (err) { + serve(req, res, function (err) { // If error, route it. // This bypasses authentication on static files! - if (!err) { - return; - } + //if (!err) { + // return; + //} if (settings.auth) { var credentials = auth(req); From 14798ffa632fdfab948c2773bac3eb08189a89b6 Mon Sep 17 00:00:00 2001 From: crissmil Date: Tue, 7 May 2024 00:48:23 +0300 Subject: [PATCH 41/43] Update package.json with serve-static --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f930b987..5730bd53 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "json5": "^0.5.1", "mime": "^1.4.1", "music-metadata": "^1.1.0", - "node-static": "^0.7.9", + "serve-static": "^1.15.0", "request-promise": "~1.0.2", "sonos-discovery": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.3.tar.gz", "wav-file-info": "0.0.8", From 69ecee8acee9fba7f1a69ef2f056df68b0bd3f92 Mon Sep 17 00:00:00 2001 From: Alex Stevenson-Price Date: Wed, 29 Jan 2025 13:59:02 +0000 Subject: [PATCH 42/43] Update README.md with slightly improved Apple Music instructions (#909) * Update README.md with improved Apple Music instructions - Added instructions on how to play playlists. - Tweaked example links to account for country code. * Fix typo --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bb0b00f9..30cb8063 100644 --- a/README.md +++ b/README.md @@ -846,6 +846,7 @@ The following endpoints are available: # Apple Music /RoomName/applemusic/{now,next,queue}/song:{songID} /RoomName/applemusic/{now,next,queue}/album:{albumID} +/RoomName/applemusic/{now,next,queue}/playlist:{playlistID} # Amazon Music /RoomName/amazonmusic/{now,next,queue}/song:{songID} @@ -872,18 +873,23 @@ It only handles a single **spotify** account currently. It will probably use the You can find **Apple Music** song and album IDs via the [iTunes Search API](https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/). -You can also use iTunes to figure out song and album IDs. Right click on a song or album and select "Share" -> "Copy Link". You can do this when you searched within Apple Music or from your media library as long as the song is available in Apple Music. +You can also use iTunes to figure out song, album, and playlist IDs. Right click on a song, album, or playlist and select "Share" -> "Copy Link". You can do this when you searched within Apple Music or from your media library as long as the song is available in Apple Music. Have a look at the link you just copied. *If you shared the link to a song:* -The format is: https://itunes.apple.com/de/album/{songName}/{albumID}?i={songID} +The format is: https://itunes.apple.com/{countryCode}/album/{songName}/{albumID}?i={songID} > eg: https://itunes.apple.com/de/album/blood-of-my-enemies/355363490?i=355364259 *If you shared the link to an album:* -The format is: https://itunes.apple.com/de/album/{albumName}/{albumID} +The format is: https://itunes.apple.com/{countryCode}/album/{albumName}/{albumID} > eg: https://itunes.apple.com/de/album/f-g-restless/355363490 +*If you shared the link to a playlist:* +The format is: https://itunes.apple.com/{countryCode}/playlist/{playlistName}/{playlistID} +> eg: https://music.apple.com/gb/playlist/lofi-girls-favorites/pl.ed52c9eeaa0740079c21fa8e455b225e + + **Amazon Music** To find **Amazon Music** song and album IDs you can use the Amazon Music App, search for a song or an album and share a link. From 3776f0ee2261c924c7b7204de121a38100a08ca7 Mon Sep 17 00:00:00 2001 From: Jimmy Shimizu Date: Sat, 22 Mar 2025 12:44:16 +0100 Subject: [PATCH 43/43] fix: Stop using keep-alive for http request (to match pre v20 behavior) chore: Fix deprecated new Buffer() calls --- lib/music_services/spotifyDef.js | 42 +-- lib/sonos-http-api.js | 6 +- package-lock.json | 448 ++++++++++++++++++++++++------- package.json | 7 +- 4 files changed, 380 insertions(+), 123 deletions(-) diff --git a/lib/music_services/spotifyDef.js b/lib/music_services/spotifyDef.js index d20b7216..85ba833a 100644 --- a/lib/music_services/spotifyDef.js +++ b/lib/music_services/spotifyDef.js @@ -39,7 +39,7 @@ const spotifyDef = { station: 'item.audioItem.audioBroadcast.#artistRadio', playlist:'container.playlistContainer', }, - + service: setService, term: getSearchTerm, tracks: loadTracks, @@ -50,7 +50,7 @@ const spotifyDef = { authenticate: authenticateService, } -var toBase64 = (string) => new Buffer(string).toString('base64'); +var toBase64 = (string) => Buffer.from(string).toString('base64'); const SPOTIFY_TOKEN_URL = 'https://accounts.spotify.com/api/token'; @@ -118,7 +118,7 @@ function authenticateService() { function getURI(type, id) { if (type == 'album') { return `x-rincon-cpcontainer:0004206c${id}`; - } else + } else if (type == 'song') { return `x-sonos-spotify:spotify%3atrack%3a${id}?sid=${sid}&flags=8224&sn=${accountSN}`; } else @@ -146,7 +146,7 @@ function setService(player, p_accountId, p_accountSN, p_country) sid = player.system.getServiceId('Spotify'); serviceType = player.system.getServiceType('Spotify'); accountId = p_accountId; - accountSN = 14; // GACALD: Hack to fix Spotify p_accountSN; + accountSN = 14; // GACALD: Hack to fix Spotify p_accountSN; country = p_country; } @@ -163,15 +163,15 @@ function getSearchTerm(type, term, artist, album, track) { newTerm += 'track:' + track; } newTerm = encodeURIComponent(newTerm); - + return newTerm; } - + function getMetadata(type, id, name, title) { const token = getServiceToken(); const parentUri = spotifyDef.parent[type] + name; const objectType = spotifyDef.object[type]; - + if (type != 'station') { title = ''; } @@ -194,7 +194,7 @@ function getURIandMetadata(type, resList) }; var items = []; - + if (type == 'album') { items = resList.albums.items; } else @@ -204,15 +204,15 @@ function getURIandMetadata(type, resList) if (type == 'playlist') { items = resList.playlists.items; } - + Id = items[0].id; Title = items[0].name + ((type=='station')?' Radio':''); Name = Title.toLowerCase().replace(' radio','').replace('radio ',''); MetadataID = spotifyDef.metastart[type] + encodeURIComponent(Id); - + UaM.metadata = getMetadata(type, MetadataID, (type=='album' || type=='playlist')?Title.toLowerCase() : Id, Title); UaM.uri = getURI(type, encodeURIComponent((type=='station')?items[0].id:items[0].uri)); - + return UaM; } @@ -222,18 +222,18 @@ function loadTracks(type, tracksJson) isArtist : false, queueTracks : [] }; - + if (tracksJson.tracks.items.length > 0) { // Filtered list of tracks to play tracks.queueTracks = tracksJson.tracks.items.reduce(function(tracksArray, track) { if (track.available_markets == null || track.available_markets.indexOf(country) != -1) { var skip = false; - + for (var j=0; (j < tracksArray.length) && !skip ; j++) { // Skip duplicate songs skip = (track.name == tracksArray[j].trackName); } - + if (!skip) { var metadataID = spotifyDef.metastart['song'] + encodeURIComponent(track.id); var metadata = getMetadata('song', metadataID, track.id, track.name); @@ -242,21 +242,21 @@ function loadTracks(type, tracksJson) tracksArray.push({trackName:track.name, artistName:(track.artists.length>0)?track.artists[0].name:'', uri:uri, metadata:metadata}); tracks.count++; } - } + } return tracksArray; }, []); } - + return tracks; } - + function isEmpty(type, resList) { var count = 0; if (type == 'album') { count = resList.albums.items.length; - } else + } else if (type == 'song') { count = resList.tracks.items.length; } else @@ -266,9 +266,9 @@ function isEmpty(type, resList) if (type == 'playlist') { count = resList.playlists.items.length; } - + return (count == 0); } - + module.exports = spotifyDef; - + diff --git a/lib/sonos-http-api.js b/lib/sonos-http-api.js index bc38520f..fbd09f0f 100644 --- a/lib/sonos-http-api.js +++ b/lib/sonos-http-api.js @@ -67,7 +67,7 @@ function HttpAPI(discovery, settings) { } const params = req.url.substring(1).split('/'); - + // parse decode player name considering decode errors let player; try { @@ -93,7 +93,7 @@ function HttpAPI(discovery, settings) { res.statusCode = code; res.setHeader('Content-Length', Buffer.byteLength(jsonResponse)); res.setHeader('Content-Type', 'application/json;charset=utf-8'); - res.write(new Buffer(jsonResponse)); + res.write(Buffer.from(jsonResponse)); res.end(); } @@ -142,7 +142,7 @@ function HttpAPI(discovery, settings) { if (!settings.webhook) return; - const body = new Buffer(jsonBody, 'utf8'); + const body = Buffer.from(jsonBody, 'utf8'); var headers = { 'Content-Type': 'application/json', diff --git a/package-lock.json b/package-lock.json index 2725c41a..de333814 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,9 +18,9 @@ "json5": "^0.5.1", "mime": "^1.4.1", "music-metadata": "^1.1.0", - "node-static": "^0.7.9", "request-promise": "~1.0.2", - "sonos-discovery": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.3.tar.gz", + "serve-static": "^1.15.0", + "sonos-discovery": "https://github.com/jishi/node-sonos-discovery/archive/v1.8.0.tar.gz", "wav-file-info": "0.0.8" }, "devDependencies": { @@ -29,8 +29,7 @@ "eslint-plugin-import": "^2.7.0" }, "engines": { - "node": ">=4.0.0", - "npm": "^2.0.0" + "node": ">=4 <23" } }, "node_modules/acorn": { @@ -526,14 +525,6 @@ "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", "dev": true }, - "node_modules/colors": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.1.tgz", - "integrity": "sha512-jg/vxRmv430jixZrC+La5kMbUWqIg32/JsYNZb94+JEmzceYbWKTsv1OuTp+7EaqiaWRR2tPcykibwCRgclIsw==", - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/combined-stream": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", @@ -642,6 +633,25 @@ "node": ">=0.4.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -664,6 +674,12 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, "node_modules/elevenlabs-node": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/elevenlabs-node/-/elevenlabs-node-2.0.1.tgz", @@ -705,6 +721,15 @@ "node": ">= 10.0.0" } }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -719,6 +744,12 @@ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -979,6 +1010,15 @@ "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", @@ -1131,6 +1171,15 @@ "node": ">= 0.12" } }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -1338,6 +1387,22 @@ "node >= 0.4.0" ] }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -1395,9 +1460,10 @@ } }, "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/inquirer": { "version": "3.3.0", @@ -1781,11 +1847,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" - }, "node_modules/mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -1843,22 +1904,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node_modules/node-static": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/node-static/-/node-static-0.7.10.tgz", - "integrity": "sha512-bd7zO5hvCWzdglgwz9t82T4mYTEUzEG5pXnSqEzitvmEacusbhl8/VwuCbMaYR9g2PNK5191yBtAEQLJEmQh1A==", - "dependencies": { - "colors": ">=0.6.0", - "mime": "^1.2.9", - "optimist": ">=0.3.4" - }, - "bin": { - "static": "bin/cli.js" - }, - "engines": { - "node": ">= 0.4.1" - } - }, "node_modules/normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -1888,6 +1933,18 @@ "node": ">=0.10.0" } }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1909,15 +1966,6 @@ "node": ">=4" } }, - "node_modules/optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dependencies": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, "node_modules/optionator": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", @@ -1995,6 +2043,15 @@ "node": ">=0.10.0" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -2153,6 +2210,15 @@ "node": ">=0.4.x" } }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -2374,6 +2440,81 @@ "semver": "bin/semver" } }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, "node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -2419,12 +2560,15 @@ } }, "node_modules/sonos-discovery": { - "version": "1.7.3", - "resolved": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.3.tar.gz", - "integrity": "sha512-bHog/7+zjirplyZOjclSM9g6rZVZX0bDWX+PzkS6KN0I1/KK6SjotazhkI4nhcrx4NYWnxCQULIO9RvzlyG2uA==", + "version": "1.8.0", + "resolved": "https://github.com/jishi/node-sonos-discovery/archive/v1.8.0.tar.gz", + "integrity": "sha512-ZDJoW3kcDYMEfGwaxyyk1Tg+Max/FewyLU4YEKaEhBrf7df3eAdrhJADRsZy5UmmKT/ZxavMiShx1IUjE/PYUw==", "dependencies": { "html-entities": "1.0.x", "xml-flow": "1.0.2" + }, + "engines": { + "node": ">=4 <23" } }, "node_modules/sonos-discovery/node_modules/html-entities": { @@ -2499,6 +2643,15 @@ "tweetnacl": "~0.14.0" } }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -2638,6 +2791,15 @@ "node": ">=0.6.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/token-types": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/token-types/-/token-types-0.9.4.tgz", @@ -2805,14 +2967,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3264,11 +3418,6 @@ "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", "dev": true }, - "colors": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.1.tgz", - "integrity": "sha512-jg/vxRmv430jixZrC+La5kMbUWqIg32/JsYNZb94+JEmzceYbWKTsv1OuTp+7EaqiaWRR2tPcykibwCRgclIsw==" - }, "combined-stream": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", @@ -3359,6 +3508,16 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -3378,6 +3537,11 @@ "safer-buffer": "^2.1.0" } }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, "elevenlabs-node": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/elevenlabs-node/-/elevenlabs-node-2.0.1.tgz", @@ -3413,6 +3577,11 @@ } } }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3427,6 +3596,11 @@ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -3637,6 +3811,11 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", @@ -3748,6 +3927,11 @@ "mime-types": "^2.1.12" } }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, "fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -3906,6 +4090,18 @@ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=" }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -3953,9 +4149,9 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "inquirer": { "version": "3.3.0", @@ -4257,11 +4453,6 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" - }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -4316,16 +4507,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node-static": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/node-static/-/node-static-0.7.10.tgz", - "integrity": "sha512-bd7zO5hvCWzdglgwz9t82T4mYTEUzEG5pXnSqEzitvmEacusbhl8/VwuCbMaYR9g2PNK5191yBtAEQLJEmQh1A==", - "requires": { - "colors": ">=0.6.0", - "mime": "^1.2.9", - "optimist": ">=0.3.4" - } - }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -4349,6 +4530,14 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4367,15 +4556,6 @@ "mimic-fn": "^1.0.0" } }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, "optionator": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", @@ -4437,6 +4617,11 @@ "error-ex": "^1.2.0" } }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -4558,6 +4743,11 @@ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -4745,6 +4935,69 @@ "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true }, + "send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "requires": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -4781,8 +5034,8 @@ } }, "sonos-discovery": { - "version": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.3.tar.gz", - "integrity": "sha512-bHog/7+zjirplyZOjclSM9g6rZVZX0bDWX+PzkS6KN0I1/KK6SjotazhkI4nhcrx4NYWnxCQULIO9RvzlyG2uA==", + "version": "https://github.com/jishi/node-sonos-discovery/archive/v1.8.0.tar.gz", + "integrity": "sha512-ZDJoW3kcDYMEfGwaxyyk1Tg+Max/FewyLU4YEKaEhBrf7df3eAdrhJADRsZy5UmmKT/ZxavMiShx1IUjE/PYUw==", "requires": { "html-entities": "1.0.x", "xml-flow": "1.0.2" @@ -4849,6 +5102,11 @@ "tweetnacl": "~0.14.0" } }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -4961,6 +5219,11 @@ "os-tmpdir": "~1.0.2" } }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, "token-types": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/token-types/-/token-types-0.9.4.tgz", @@ -5099,11 +5362,6 @@ "is-typed-array": "^1.1.10" } }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 5730bd53..aa8326c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sonos-http-api", - "version": "1.6.9", + "version": "1.7.0", "description": "A simple node app for controlling a Sonos system with basic HTTP requests", "scripts": { "start": "node server.js", @@ -22,13 +22,12 @@ "music-metadata": "^1.1.0", "serve-static": "^1.15.0", "request-promise": "~1.0.2", - "sonos-discovery": "https://github.com/jishi/node-sonos-discovery/archive/v1.7.3.tar.gz", + "sonos-discovery": "https://github.com/jishi/node-sonos-discovery/archive/v1.8.0.tar.gz", "wav-file-info": "0.0.8", "elevenlabs-node": "2.0.1" }, "engines": { - "node": ">=4.0.0", - "npm": "^2.0.0" + "node": ">=4 <23" }, "main": "lib/sonos-http-api.js", "license": "MIT",