Simple Spotify Now Playing

Simple-Spotify-Now-Playing

A simple web page with Node Red to show Spotify now playing song / top artist when not playing

Description

A very simple webpage for showing the now playing song and album art from a spotify account based on Node Red. page

Be warned quite hacky at this stage, e.g. reloads whole web page based on calculated time to end of current song. Noticeable if you change or skip a song, won't update until song would have finished.

Node Red Flows

flows

To use

  1. Install Node Red
  2. Install required nodes as set out in required_nodes.md
  3. Import spotifynodered.json into Node Red
  4. Set up Spotify Developer Account and new project
  5. Authorise the Spotify node in Node Red using Project ID and Secret and the Scopes here
  6. Now playing web page is available at http://[your.nodered.ip]/spotify

Options

You can:

  1. Change web page in Web Request node

To do

  1. When nothing playing add in recently played songs
[{"id":"f6f2187d.f17ca8","type":"tab","label":"Simple Spotify Now Playing","disabled":false,"info":""},{"id":"cab7badd01b8dbfe","type":"http in","z":"f6f2187d.f17ca8","name":"Web Request","url":"/spotify","method":"get","upload":false,"swaggerDoc":"","x":90,"y":80,"wires":[["1f8621502fd25281"]]},{"id":"97a03cbb753a4ec8","type":"http response","z":"f6f2187d.f17ca8","name":"","statusCode":"","headers":{},"x":370,"y":240,"wires":[]},{"id":"eb5dba838f4a8d4a","type":"template","z":"f6f2187d.f17ca8","name":"html","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<!DOCTYPE html>\n<html>\n<head>\n    <title>{{flow.trackname}}</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n    <meta name=\"description\" content=\"Simple Spotify Now Playing\">\n    <meta http-equiv=\"refresh\" content=\"{{{flow.reload}}}\">\n    <link rel=\"icon\" type=\"image/png\" href=\"{{{flow.favicon}}}\">\n    <style>\n        {{{flow.css}}}\n    </style>\n</head>\n\n<body>\n<div class=\"bg-image\"></div>\n\n<div class=\"playing\">\n  <div class=\"album-data\">\n    <h1>{{{flow.trackname}}}</h1>\n    <img src=\"{{{flow.image}}}\" alt=\"{{{flow.trackname}}} on {{{flow.albumname}}} by {{{flow.artistname}}}\" class=\"image-responsive\"> \n    <h3>{{{flow.albumname}}} by {{{flow.artistname}}}</h3>\n  </div>\n</div>\n</body>\n</html>","output":"str","x":250,"y":240,"wires":[["97a03cbb753a4ec8"]]},{"id":"c03efdbb927399c4","type":"spotify","z":"f6f2187d.f17ca8","name":"Get Current Track","auth":"934bab396b45618f","api":"getMyCurrentPlayingTrack","x":170,"y":140,"wires":[["c179d20b16bbd921","3361c521f8511819"]]},{"id":"c179d20b16bbd921","type":"change","z":"f6f2187d.f17ca8","name":"Update Now Playing Data","rules":[{"t":"set","p":"image","pt":"flow","to":"payload.item.album.images[0].url","tot":"msg"},{"t":"set","p":"trackname","pt":"flow","to":"payload.item.name","tot":"msg"},{"t":"set","p":"artistname","pt":"flow","to":"payload.item.artists[0].name","tot":"msg"},{"t":"set","p":"albumname","pt":"flow","to":"payload.item.album.name","tot":"msg"},{"t":"set","p":"favicon","pt":"flow","to":"payload.item.album.images[2].url","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":160,"wires":[[]]},{"id":"13513f4646d7cf37","type":"template","z":"f6f2187d.f17ca8","name":"css","field":"css","fieldType":"flow","format":"css","syntax":"mustache","template":"body, html {\n  height: 140%;\n  margin: 0;\n  font-family: Arial, Helvetica, sans-serif;\n  background-color: black;\n  overflow: hidden;\n}\n\n.bg-image {\n  background-image: url(\"{{{flow.image}}}\");\n  filter: blur(8px) hue-rotate(190deg) brightness(0.7);\n  -webkit-filter: blur(8px) hue-rotate(190deg) brightness(0.7);\n  height: 110%; \n  background-position: center;\n  background-repeat: no-repeat;\n  background-size: cover;\n}\n\n.playing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  z-index: 2;\n  width: 80%;\n  display: flex;\n}\n\n/* Position text in the middle of the page/image */\n.song-text {\n  background-color: rgb(0,0,0); /* Fallback color */\n  background-color: rgba(0,0,0, 0); /* Black w/opacity/see-through */\n  border-radius: 25px;\n  color: rgb(255, 255, 255);\n  font-weight: bold;\n  text-align: right;\n  align-self: center;\n  padding: 1.5%;\n  display: block;\n  height: fit-content;\n}\n\n/* Position text in the middle of the page/image */\n.album-data {\n  background-color: rgb(0,0,0); /* Fallback color */\n  background-color: rgba(0,0,0, 0); /* Black w/opacity/see-through */\n  color: rgb(255, 255, 255);\n  font-weight: bold;\n  text-align: right;\n  display: block;\n}\n.image-responsive {\n  width: 75%;\n  height: auto;\n  border-radius: 25px;\n}","output":"str","x":130,"y":240,"wires":[["eb5dba838f4a8d4a"]]},{"id":"20f221588d1d91fc","type":"function","z":"f6f2187d.f17ca8","name":"Calc remaining seconds","func":"msg.reload = 1 + ( msg.duration - msg.position ) / 1000;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":200,"wires":[["3cfc234a3f1215a6"]]},{"id":"3cfc234a3f1215a6","type":"change","z":"f6f2187d.f17ca8","name":"Set reload in seconds","rules":[{"t":"set","p":"reload","pt":"flow","to":"reload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":200,"wires":[["13513f4646d7cf37"]]},{"id":"3361c521f8511819","type":"change","z":"f6f2187d.f17ca8","name":"Update Reload Data","rules":[{"t":"set","p":"duration","pt":"msg","to":"payload.item.duration_ms","tot":"msg"},{"t":"set","p":"position","pt":"msg","to":"payload.progress_ms","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":180,"y":200,"wires":[["20f221588d1d91fc"]]},{"id":"a6e9a885ea9425c2","type":"inject","z":"f6f2187d.f17ca8","name":"Initialise","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payloadType":"date","x":100,"y":40,"wires":[["5493655477b5e924"]]},{"id":"a21b4d2f29334b27","type":"change","z":"f6f2187d.f17ca8","name":"Initialise Now Playing Data","rules":[{"t":"set","p":"image","pt":"flow","to":"payload.items[0].track.album.images[0].url","tot":"msg"},{"t":"set","p":"trackname","pt":"flow","to":"payload.items[0].track.name","tot":"msg"},{"t":"set","p":"artistname","pt":"flow","to":"payload.items[0].track.artists[0].name","tot":"msg"},{"t":"set","p":"albumname","pt":"flow","to":"payload.items[0].track.album.name","tot":"msg"},{"t":"set","p":"favicon","pt":"flow","to":"payload.items[0].track.album.images[2].url","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":500,"y":40,"wires":[["9d2cfcaa58ce4ca3"]]},{"id":"7be8214192eafd13","type":"change","z":"f6f2187d.f17ca8","name":"Initialise reload in seconds","rules":[{"t":"set","p":"reload","pt":"flow","to":"15","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":1080,"y":40,"wires":[[]]},{"id":"5493655477b5e924","type":"spotify","z":"f6f2187d.f17ca8","name":"Get Recent Tracks","auth":"934bab396b45618f","api":"getMyRecentlyPlayedTracks","x":270,"y":40,"wires":[["a21b4d2f29334b27"]]},{"id":"bfecb051f3e03267","type":"counter","z":"f6f2187d.f17ca8","inc":1,"name":"","x":380,"y":120,"wires":[["0cc3ca40d6b5af70"]]},{"id":"0cc3ca40d6b5af70","type":"change","z":"f6f2187d.f17ca8","name":"Set Counter","rules":[{"t":"set","p":"reload_counter","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":530,"y":120,"wires":[[]]},{"id":"1f8621502fd25281","type":"spotify","z":"f6f2187d.f17ca8","name":"Get if playing","auth":"934bab396b45618f","api":"getMyCurrentPlaybackState","x":250,"y":80,"wires":[["37c4d814a13814f6","bfecb051f3e03267"]]},{"id":"37c4d814a13814f6","type":"switch","z":"f6f2187d.f17ca8","name":"","property":"payload.is_playing","propertyType":"msg","rules":[{"t":"cont","v":"true","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":630,"y":80,"wires":[["534f6731c4f799ac"],["19e6d616ae22b910"]]},{"id":"534f6731c4f799ac","type":"link out","z":"f6f2187d.f17ca8","name":"","mode":"link","links":["0cfa207ed85d3096"],"x":735,"y":80,"wires":[]},{"id":"86b9203d44e46632","type":"link out","z":"f6f2187d.f17ca8","name":"","mode":"link","links":["4c4e50cd31dd3423","3593b8912a56695a"],"x":1275,"y":100,"wires":[]},{"id":"0cfa207ed85d3096","type":"link in","z":"f6f2187d.f17ca8","name":"","links":["534f6731c4f799ac"],"x":35,"y":140,"wires":[["c03efdbb927399c4"]]},{"id":"0b2f14562edc39ab","type":"http response","z":"f6f2187d.f17ca8","name":"","statusCode":"","headers":{},"x":370,"y":360,"wires":[]},{"id":"b8f6ee61efa8704b","type":"template","z":"f6f2187d.f17ca8","name":"html","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<!DOCTYPE html>\n<html>\n<head>\n    <title>{{flow.trackname}}</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n    <meta name=\"description\" content=\"Simple Spotify Now Playing\">\n    <meta http-equiv=\"refresh\" content=\"{{{flow.reload}}}\">\n    <link rel=\"icon\" type=\"image/png\" href=\"{{{flow.favicon}}}\">\n    <style>\n        {{{flow.css}}}\n    </style>\n</head>\n\n<body>\n<div class=\"bg-image\"></div>\n\n<div class=\"playing\">\n  <div class=\"album-data\">\n    <h1>{{{flow.trackname}}}'s Top Artists</h1>\n    <img src=\"{{{flow.image}}}\" alt=\"{{{flow.trackname}}} on {{{flow.albumname}}} by {{{flow.artistname}}}\" class=\"image-responsive\"> \n    <h3>{{{flow.albumname}}} by {{{flow.artistname}}}</h3>\n  </div>\n</div>\n</body>\n</html>","output":"str","x":250,"y":360,"wires":[["0b2f14562edc39ab"]]},{"id":"ca078428b2bb4395","type":"change","z":"f6f2187d.f17ca8","name":"Update Now Playing Data","rules":[{"t":"set","p":"image","pt":"flow","to":"payload.images[0].url","tot":"msg"},{"t":"set","p":"trackname","pt":"flow","to":"username","tot":"flow"},{"t":"set","p":"artistname","pt":"flow","to":"payload.name","tot":"msg"},{"t":"set","p":"albumname","pt":"flow","to":"The songs ","tot":"str"},{"t":"set","p":"favicon","pt":"flow","to":"payload.images[2].url","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":300,"wires":[["69830c336f657e2d"]]},{"id":"2c017c418b2ad24d","type":"template","z":"f6f2187d.f17ca8","name":"css","field":"css","fieldType":"flow","format":"css","syntax":"mustache","template":"body, html {\n  height: 140%;\n  margin: 0;\n  font-family: Arial, Helvetica, sans-serif;\n  background-color: black;\n  overflow: hidden;\n}\n\n.bg-image {\n  background-image: url(\"{{{flow.image}}}\");\n  filter: blur(8px) hue-rotate(190deg) brightness(0.7);\n  -webkit-filter: blur(8px) hue-rotate(190deg) brightness(0.7);\n  height: 110%; \n  background-position: center;\n  background-repeat: no-repeat;\n  background-size: cover;\n}\n\n.playing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  z-index: 2;\n  width: 80%;\n  display: flex;\n}\n\n/* Position text in the middle of the page/image */\n.song-text {\n  background-color: rgb(0,0,0); /* Fallback color */\n  background-color: rgba(0,0,0, 0); /* Black w/opacity/see-through */\n  border-radius: 25px;\n  color: rgb(255, 255, 255);\n  font-weight: bold;\n  text-align: right;\n  align-self: center;\n  padding: 1.5%;\n  display: block;\n  height: fit-content;\n}\n\n/* Position text in the middle of the page/image */\n.album-data {\n  background-color: rgb(0,0,0); /* Fallback color */\n  background-color: rgba(0,0,0, 0); /* Black w/opacity/see-through */\n  color: rgb(255, 255, 255);\n  font-weight: bold;\n  text-align: right;\n  display: block;\n}\n.image-responsive {\n  width: 75%;\n  height: auto;\n  border-radius: 25px;\n}","output":"str","x":130,"y":360,"wires":[["b8f6ee61efa8704b"]]},{"id":"69830c336f657e2d","type":"change","z":"f6f2187d.f17ca8","name":"Set reload in seconds","rules":[{"t":"set","p":"reload","pt":"flow","to":"60","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":780,"y":300,"wires":[["2c017c418b2ad24d"]]},{"id":"4c4e50cd31dd3423","type":"link in","z":"f6f2187d.f17ca8","name":"","links":["86b9203d44e46632"],"x":45,"y":300,"wires":[["09b1becf0cacaa9a"]]},{"id":"09b1becf0cacaa9a","type":"spotify","z":"f6f2187d.f17ca8","name":"Get Top Artist","auth":"934bab396b45618f","api":"getMyTopArtists","x":160,"y":300,"wires":[["aee9046f9cae91ec"]]},{"id":"aee9046f9cae91ec","type":"random-item","z":"f6f2187d.f17ca8","name":"Random Artist","input":"payload.items","inputType":"msg","output":"payload","outputType":"msg","number":1,"x":340,"y":300,"wires":[["ca078428b2bb4395"]]},{"id":"3f133b32943e9b62","type":"http response","z":"f6f2187d.f17ca8","name":"","statusCode":"","headers":{},"x":370,"y":480,"wires":[]},{"id":"3344a35c3d0619de","type":"template","z":"f6f2187d.f17ca8","name":"html","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<!DOCTYPE html>\n<html>\n<head>\n    <title>{{flow.trackname}}</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n    <meta name=\"description\" content=\"Simple Spotify Now Playing\">\n    <meta http-equiv=\"refresh\" content=\"{{{flow.reload}}}\">\n    <link rel=\"icon\" type=\"image/png\" href=\"{{{flow.favicon}}}\">\n    <style>\n        {{{flow.css}}}\n    </style>\n</head>\n\n<body>\n<div class=\"bg-image\"></div>\n\n<div class=\"playing\">\n  <div class=\"album-data\">\n    <h1>{{{flow.trackname}}}'s Top Songs</h1>\n    <img src=\"{{{flow.image}}}\" alt=\"{{{flow.trackname}}} on {{{flow.albumname}}} by {{{flow.artistname}}}\" class=\"image-responsive\"> \n    <h3>{{{flow.albumname}}} by {{{flow.artistname}}}</h3>\n  </div>\n</div>\n</body>\n</html>","output":"str","x":250,"y":480,"wires":[["3f133b32943e9b62"]]},{"id":"29fa27f379ff3ff6","type":"change","z":"f6f2187d.f17ca8","name":"Update Now Playing Data","rules":[{"t":"set","p":"image","pt":"flow","to":"payload.album.images[0].url","tot":"msg"},{"t":"set","p":"trackname","pt":"flow","to":"username","tot":"flow"},{"t":"set","p":"artistname","pt":"flow","to":"payload.artists[0].name","tot":"msg"},{"t":"set","p":"albumname","pt":"flow","to":"payload.name","tot":"msg"},{"t":"set","p":"favicon","pt":"flow","to":"payload.album.images[2].url","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":420,"wires":[["79d2c18af672b994"]]},{"id":"fa04dd240a5ab2b1","type":"template","z":"f6f2187d.f17ca8","name":"css","field":"css","fieldType":"flow","format":"css","syntax":"mustache","template":"body, html {\n  height: 140%;\n  margin: 0;\n  font-family: Arial, Helvetica, sans-serif;\n  background-color: black;\n  overflow: hidden;\n}\n\n.bg-image {\n  background-image: url(\"{{{flow.image}}}\");\n  filter: blur(8px) hue-rotate(190deg) brightness(0.7);\n  -webkit-filter: blur(8px) hue-rotate(190deg) brightness(0.7);\n  height: 110%; \n  background-position: center;\n  background-repeat: no-repeat;\n  background-size: cover;\n}\n\n.playing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  z-index: 2;\n  width: 80%;\n  display: flex;\n}\n\n/* Position text in the middle of the page/image */\n.song-text {\n  background-color: rgb(0,0,0); /* Fallback color */\n  background-color: rgba(0,0,0, 0); /* Black w/opacity/see-through */\n  border-radius: 25px;\n  color: rgb(255, 255, 255);\n  font-weight: bold;\n  text-align: right;\n  align-self: center;\n  padding: 1.5%;\n  display: block;\n  height: fit-content;\n}\n\n/* Position text in the middle of the page/image */\n.album-data {\n  background-color: rgb(0,0,0); /* Fallback color */\n  background-color: rgba(0,0,0, 0); /* Black w/opacity/see-through */\n  color: rgb(255, 255, 255);\n  font-weight: bold;\n  text-align: right;\n  display: block;\n}\n.image-responsive {\n  width: 75%;\n  height: auto;\n  border-radius: 25px;\n}","output":"str","x":130,"y":480,"wires":[["3344a35c3d0619de"]]},{"id":"79d2c18af672b994","type":"change","z":"f6f2187d.f17ca8","name":"Set reload in seconds","rules":[{"t":"set","p":"reload","pt":"flow","to":"60","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":780,"y":420,"wires":[["fa04dd240a5ab2b1"]]},{"id":"442d9d96f018afff","type":"random-item","z":"f6f2187d.f17ca8","name":"Random Artist","input":"payload.items","inputType":"msg","output":"payload","outputType":"msg","number":1,"x":340,"y":420,"wires":[["29fa27f379ff3ff6"]]},{"id":"19e6d616ae22b910","type":"random","z":"f6f2187d.f17ca8","name":"Random","low":1,"high":"2","inte":"true","property":"random","x":780,"y":120,"wires":[["03e87893769830f2"]]},{"id":"300564b3f2e13fb1","type":"switch","z":"f6f2187d.f17ca8","name":"","property":"random","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"2","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":1190,"y":120,"wires":[["86b9203d44e46632"],["fa8357c91f435f75"]]},{"id":"fa8357c91f435f75","type":"link out","z":"f6f2187d.f17ca8","name":"","mode":"link","links":["214e4540e88ae3e7"],"x":1275,"y":140,"wires":[]},{"id":"659deb8bdd7bd36d","type":"link in","z":"f6f2187d.f17ca8","name":"","links":[],"x":-35,"y":420,"wires":[[]]},{"id":"214e4540e88ae3e7","type":"link in","z":"f6f2187d.f17ca8","name":"","links":["fa8357c91f435f75"],"x":35,"y":420,"wires":[["ae244d6e284b30de"]]},{"id":"ae244d6e284b30de","type":"spotify","z":"f6f2187d.f17ca8","name":"Get Top Tracks","auth":"934bab396b45618f","api":"getMyTopTracks","x":160,"y":420,"wires":[["442d9d96f018afff"]]},{"id":"9d2cfcaa58ce4ca3","type":"spotify","z":"f6f2187d.f17ca8","name":"Get Me","auth":"934bab396b45618f","api":"getMe","x":700,"y":40,"wires":[["fae26c63e2326f5f"]]},{"id":"fae26c63e2326f5f","type":"change","z":"f6f2187d.f17ca8","name":"Initialise Name","rules":[{"t":"set","p":"username","pt":"flow","to":"payload.display_name","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":40,"wires":[["7be8214192eafd13"]]},{"id":"03e87893769830f2","type":"spotify","z":"f6f2187d.f17ca8","name":"Get Me","auth":"934bab396b45618f","api":"getMe","x":920,"y":120,"wires":[["5cc20d5b94acb1ca"]]},{"id":"5cc20d5b94acb1ca","type":"change","z":"f6f2187d.f17ca8","name":"Set Name","rules":[{"t":"set","p":"username","pt":"flow","to":"payload.display_name","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1060,"y":120,"wires":[["300564b3f2e13fb1"]]},{"id":"934bab396b45618f","type":"spotify-auth","name":"Spotify","scope":"user-read-playback-state\nuser-read-private\nuser-follow-read\nuser-library-read\nuser-read-playback-position\nplaylist-read-private\nuser-top-read\nuser-read-currently-playing\nuser-read-recently-played"}]

Flow Info

Created 3 years, 8 months ago
Rating: not yet rated

Owner

Actions

Rate:

Node Types

Core
  • change (x12)
  • function (x1)
  • http in (x1)
  • http response (x3)
  • inject (x1)
  • link in (x4)
  • link out (x3)
  • switch (x2)
  • template (x6)
Other

Tags

  • spotify
  • webpage
  • spotify-api
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option