diff --git a/fgfm.js b/fgfm.js index 8bb2204..81fe2f5 100755 --- a/fgfm.js +++ b/fgfm.js @@ -13,6 +13,7 @@ const GHOBS = require('./lib/ghobs'); const FGFM = require('./lib/fgfm'); const cooldowns = require('./lib/cooldowns'); const util = require('./lib/util'); +const Spotify = require('./lib/spotify'); // Read internal configuration let config = require('./config.json'); @@ -96,6 +97,13 @@ const streamInit = (config, twitch) => { director.on('CREDITS_SHOWN', (secondsUntilEnd) => { twitch.editorChat.say(config.twitch.channel, `Thanks to everyone for watching and lurking! Have a wonderful night and stay comfy. greenhComfy`); }); + + // Spotify integration + const spotify = new Spotify(config.spotify); + spotify.init() + .then(() => { + spotify.getPlaybackState(); + }); // Chat commands const commands = { diff --git a/lib/spotify.js b/lib/spotify.js new file mode 100755 index 0000000..03fe8c9 --- /dev/null +++ b/lib/spotify.js @@ -0,0 +1,77 @@ +var SpotifyWebApi = require('spotify-web-api-node'); + +function Spotify(config) { + // Set up initial state + this.config = config; + + this.credentials = { + clientId: this.config.clientId, + clientSecret: this.config.clientSecret, + redirectUri: this.config.redirectUri + }; + + const spotifyApi = new SpotifyWebApi(this.credentials); + + // The code that's returned as a query parameter to the redirect URI + const code = this.config.userCode; + + this.init = () => { + return new Promise((resolve, reject) => { + // Retrieve an access token and a refresh token + spotifyApi.authorizationCodeGrant(code).then( + function(data) { + console.log('The token expires in ' + data.body['expires_in']); + console.log('The access token is ' + data.body['access_token']); + console.log('The refresh token is ' + data.body['refresh_token']); + + // Set the access token on the API object to use it in later calls + spotifyApi.setAccessToken(data.body['access_token']); + spotifyApi.setRefreshToken(data.body['refresh_token']); + + // clientId, clientSecret and refreshToken has been set on the api object previous to this call. + setInterval(() => { + spotifyApi.refreshAccessToken().then( + function(data) { + console.log('The access token has been refreshed!'); + + // Save the access token so that it's used in future calls + spotifyApi.setAccessToken(data.body['access_token']); + }, + function(err) { + console.log('Could not refresh access token', err); + } + ); + }, data.body['expires_in']*1000); + + resolve(); + }, + function(err) { + console.log('Something went wrong!', JSON.stringify(err)); + reject(err); + } + ); + }); + }; + + this.getMe = () => { + spotifyApi.getMe() + .then(function(data) { + console.log('Some information about the authenticated user', data.body); + }, function(err) { + console.log('Something went wrong!', err); + }); + }; + + this.getPlaybackState = () => { + spotifyApi.getMyCurrentPlaybackState({ + }) + .then(function(data) { + // Output items + console.log("Now Playing: ",data.body); + }, function(err) { + console.log('Something went wrong!', err); + }); + } +} + +module.exports = Spotify; diff --git a/package-lock.json b/package-lock.json index 504393d..551f275 100644 --- a/package-lock.json +++ b/package-lock.json @@ -116,11 +116,29 @@ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "requires": { + "delayed-stream": "1.0.0" + } + }, "commander": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", "integrity": "sha1-FXFS/R56bI2YpbcVzzdt+SgARWM=" }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, "core-js": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", @@ -203,6 +221,11 @@ "safer-buffer": "2.1.2" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -237,6 +260,21 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.7", + "mime-types": "2.1.21" + } + }, + "formidable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", + "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==" + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -316,6 +354,11 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -388,6 +431,29 @@ "resolved": "https://registry.npmjs.org/memcache/-/memcache-0.3.0.tgz", "integrity": "sha1-vbuXjqS+4P3TFmmXsYg9KX4IWdw=" }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" + }, + "mime-types": { + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", + "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "requires": { + "mime-db": "1.37.0" + } + }, "moment": { "version": "2.22.2", "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", @@ -508,6 +574,11 @@ "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" }, + "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==" + }, "psl": { "version": "1.1.29", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", @@ -518,6 +589,25 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "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" + } + }, "ref": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ref/-/ref-1.3.5.tgz", @@ -643,6 +733,14 @@ "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.2.0.tgz", "integrity": "sha512-sWpjPhIZJtqO77GN+LD8dDsDKcWZ9GCOJNqKzi1tvtjGIzwfoyuRH8S0psunmc6Z5P+qfDqztSbwYR5X/e1UTg==" }, + "spotify-web-api-node": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spotify-web-api-node/-/spotify-web-api-node-4.0.0.tgz", + "integrity": "sha512-FQAX4qiP9xfjmJpkSfF5PEVr7RVorUZiLvcdVTlhVFLYAmQ8VSsZlyb0yTK0GExKhAcgJy9GfWxqjSB2r9SrjA==", + "requires": { + "superagent": "3.8.3" + } + }, "sshpk": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", @@ -659,6 +757,46 @@ "tweetnacl": "0.14.5" } }, + "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==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "requires": { + "component-emitter": "1.2.1", + "cookiejar": "2.1.2", + "debug": "3.2.6", + "extend": "3.0.2", + "form-data": "2.3.3", + "formidable": "1.2.1", + "methods": "1.1.2", + "mime": "1.6.0", + "qs": "6.5.2", + "readable-stream": "2.3.6" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "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==" + } + } + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -682,6 +820,11 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "optional": true }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", diff --git a/package.json b/package.json index 166e1e7..97fa8d8 100755 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "node-opus": "^0.2.9", "node-schedule": "^1.3.0", "obs-websocket-js": "^1.2.0", - "request": "^2.88.0" + "request": "^2.88.0", + "spotify-web-api-node": "^4.0.0" }, "devDependencies": {}, "scripts": { diff --git a/spotify-auth-url.js b/spotify-auth-url.js new file mode 100755 index 0000000..021d642 --- /dev/null +++ b/spotify-auth-url.js @@ -0,0 +1,19 @@ +var SpotifyWebApi = require('spotify-web-api-node'); +let config = require('./config.json'); + +var scopes = ['streaming', 'app-remote-control', 'user-read-currently-playing', 'user-read-playback-state', 'user-modify-playback-state', 'user-read-recently-played', 'playlist-read-collaborative', 'playlist-modify-private', 'playlist-modify-public', 'playlist-read-private'], + redirectUri = 'http://forevergrind.fm/spotify', + clientId = config.spotify.clientId, + state = 'some-state-of-my-choice'; + +// Setting credentials can be done in the wrapper's constructor, or using the API object's setters. +var spotifyApi = new SpotifyWebApi({ + redirectUri: redirectUri, + clientId: clientId +}); + +// Create the authorization URL +var authorizeURL = spotifyApi.createAuthorizeURL(scopes, state); + +// https://accounts.spotify.com:443/authorize?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https://example.com/callback&scope=user-read-private%20user-read-email&state=some-state-of-my-choice +console.log(authorizeURL); \ No newline at end of file