├── _includes ├── img │ ├── album │ │ └── empty │ └── site │ │ ├── loading.png │ │ ├── audio_volume_high.png │ │ ├── audio_volume_low.png │ │ ├── ajax-loader-transparent.gif │ │ ├── sprite_play_controls_24.png │ │ ├── bg_gradient_black-transparent_24.png │ │ └── bg_gradient_transparent-black_24.png ├── applescripts │ ├── pause.applescript │ ├── next.applescript │ ├── previous.applescript │ ├── volume-down.applescript │ ├── volume-up.applescript │ ├── volume.applescript │ ├── play.applescript │ ├── toggle.applescript │ └── status.applescript ├── icons │ ├── apple.png │ └── favicon.ico ├── php │ ├── Ajax.php │ ├── SpotifyRemote.php │ └── PageBuilder.php ├── js │ └── site │ │ ├── init.js │ │ └── spotify-remote.js └── css │ └── site │ └── screen.css ├── .gitignore ├── index.php └── README.md /_includes/img/album/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _includes/img/album/album.jpg 2 | _includes/img/album/album.tiff -------------------------------------------------------------------------------- /_includes/applescripts/pause.applescript: -------------------------------------------------------------------------------- 1 | tell application "Spotify" 2 | pause 3 | end tell -------------------------------------------------------------------------------- /_includes/applescripts/next.applescript: -------------------------------------------------------------------------------- 1 | tell application "Spotify" 2 | next track 3 | end tell -------------------------------------------------------------------------------- /_includes/applescripts/previous.applescript: -------------------------------------------------------------------------------- 1 | tell application "Spotify" 2 | previous track 3 | end tell -------------------------------------------------------------------------------- /_includes/icons/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/spotify-remote/master/_includes/icons/apple.png -------------------------------------------------------------------------------- /_includes/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/spotify-remote/master/_includes/icons/favicon.ico -------------------------------------------------------------------------------- /_includes/img/site/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/spotify-remote/master/_includes/img/site/loading.png -------------------------------------------------------------------------------- /_includes/img/site/audio_volume_high.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/spotify-remote/master/_includes/img/site/audio_volume_high.png -------------------------------------------------------------------------------- /_includes/img/site/audio_volume_low.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/spotify-remote/master/_includes/img/site/audio_volume_low.png -------------------------------------------------------------------------------- /_includes/img/site/ajax-loader-transparent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/spotify-remote/master/_includes/img/site/ajax-loader-transparent.gif -------------------------------------------------------------------------------- /_includes/img/site/sprite_play_controls_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/spotify-remote/master/_includes/img/site/sprite_play_controls_24.png -------------------------------------------------------------------------------- /_includes/applescripts/volume-down.applescript: -------------------------------------------------------------------------------- 1 | tell application "Spotify" 2 | set _volume to sound volume 3 | set sound volume to _volume - 5 4 | end tell 5 | -------------------------------------------------------------------------------- /_includes/applescripts/volume-up.applescript: -------------------------------------------------------------------------------- 1 | tell application "Spotify" 2 | set _volume to sound volume 3 | set sound volume to _volume + 5 4 | end tell 5 | -------------------------------------------------------------------------------- /_includes/img/site/bg_gradient_black-transparent_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/spotify-remote/master/_includes/img/site/bg_gradient_black-transparent_24.png -------------------------------------------------------------------------------- /_includes/img/site/bg_gradient_transparent-black_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangespaceman/spotify-remote/master/_includes/img/site/bg_gradient_transparent-black_24.png -------------------------------------------------------------------------------- /_includes/applescripts/volume.applescript: -------------------------------------------------------------------------------- 1 | on run args 2 | local arg 3 | set arg to item 1 of args 4 | tell application "Spotify" 5 | set sound volume to arg 6 | end tell 7 | end run -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | buildPage(); -------------------------------------------------------------------------------- /_includes/applescripts/play.applescript: -------------------------------------------------------------------------------- 1 | on run args 2 | try 3 | tell application "Spotify" 4 | play 5 | set output to "play" 6 | end tell 7 | 8 | on error error_message 9 | set output to "{ 10 | \"state\" : \"" & error_message & "\" 11 | }" 12 | end try 13 | 14 | end run -------------------------------------------------------------------------------- /_includes/applescripts/toggle.applescript: -------------------------------------------------------------------------------- 1 | on run args 2 | try 3 | tell application "Spotify" 4 | playpause 5 | set output to "toggled" 6 | end tell 7 | 8 | on error error_message 9 | --set output to "{ 10 | -- \"state\" : \"" & error_message & "\" 11 | --}" 12 | set output to error_message 13 | end try 14 | 15 | end run -------------------------------------------------------------------------------- /_includes/php/Ajax.php: -------------------------------------------------------------------------------- 1 | 0) { 3 | 4 | // check what to do 5 | require_once("./SpotifyRemote.php"); 6 | $spotifyRemote = new SpotifyRemote; 7 | 8 | $method = $_POST['method']; 9 | unset($_POST['method']); 10 | 11 | if (isset($_POST['args'])) { 12 | $args = $_POST['args']; 13 | unset($_POST['args']); 14 | } else { 15 | $args = array(); 16 | } 17 | 18 | // run command 19 | $result = $spotifyRemote->command($method, $args); 20 | echo $result; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /_includes/js/site/init.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Site global JS file 3 | */ 4 | 5 | /** 6 | * on Dom ready functionality 7 | */ 8 | $(document).ready(function() { 9 | 10 | // add an extra class to the element for JS-only styling 11 | $("html").addClass("js"); 12 | 13 | // init vol control 14 | spotifyRemote.init({ 15 | ajaxPath: "./_includes/php/Ajax.php", 16 | interval: 1 17 | }); 18 | }); 19 | 20 | 21 | /* 22 | * Window load calls for all pages 23 | */ 24 | $(window).load(function() { 25 | 26 | }); -------------------------------------------------------------------------------- /_includes/php/SpotifyRemote.php: -------------------------------------------------------------------------------- 1 | 'play', 13 | 'pause' => 'pause', 14 | 'next' => 'next', 15 | 'previous' => 'previous', 16 | 'status' => 'status', 17 | 'toggle' => 'toggle', 18 | 'volume-up' => 'volume-up', 19 | 'volume-down' => 'volume-down' 20 | ); 21 | 22 | 23 | /* 24 | * 25 | */ 26 | public function __construct() { 27 | 28 | } 29 | 30 | 31 | /* 32 | * Check to see if the command is valid 33 | * 34 | * 35 | */ 36 | public function command($command, $args = "") { 37 | if (array_key_exists($command, $this->commands)) { 38 | return $this->_command($this->commands[$command], $args); 39 | } 40 | } 41 | 42 | 43 | /* 44 | * Run command 45 | * 46 | * 47 | */ 48 | private function _command($command, $args) { 49 | $cmd = 'osascript ../applescripts/'.$command.'.applescript'; 50 | if ($args) { 51 | $cmd .= ' "'.$args.'"'; 52 | } 53 | return shell_exec($cmd); 54 | } 55 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spotify Remote 2 | 3 | A basic browser-based remote control for Spotify, optimised for mobile and desktop browsers 4 | 5 | 6 | ## Support 7 | 8 | Should work on a mac that has Spotify, Apache and PHP. 9 | 10 | 11 | ## Installation 12 | 13 | Just copy these files into a local mac web server 14 | 15 | If it doesn't work (possibly with error 10810) then you might need to run it via MAMP 16 | 17 | 18 | 19 | ## Ability 20 | 21 | Setters: 22 | 23 | * Play/Pause 24 | * Next Track 25 | * Previous Track 26 | * Change volume 27 | 28 | Status: 29 | 30 | * Artist 31 | * Track 32 | * Album 33 | * Time elapsed 34 | * Total time 35 | * Album artwork 36 | 37 | 38 | ## Inspiration 39 | 40 | * https://github.com/ferranselles/My-Geeklets/blob/5b017b7b7ba9d293badcf034bae206ba36f905b3/spotify/spotify.applescript 41 | * https://github.com/alexandernilsson/Moody/blob/master/Moody.applescript 42 | * http://www.leancrew.com/all-this/2011/07/spotify-info-on-the-desktop-via-nerdtool/ 43 | * http://blog.lifeupnorth.co.uk/post/8311267208/spotify-and-applescript 44 | * http://www.macosxtips.co.uk/geeklets/music/spotify-now-playing/ 45 | * https://github.com/swinton/spotipy 46 | -------------------------------------------------------------------------------- /_includes/php/PageBuilder.php: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | Spotimote 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
45 |
46 | 47 | 59 | 60 |
61 | 62 | 74 | 75 |
76 |
77 | 78 | 79 | '; 80 | 81 | return $return; 82 | } 83 | } -------------------------------------------------------------------------------- /_includes/applescripts/status.applescript: -------------------------------------------------------------------------------- 1 | -- Init 2 | on run args 3 | 4 | -- is Spotify running? 5 | try 6 | 7 | tell application "Spotify" 8 | 9 | set _state to player state 10 | 11 | -- is Spotify playing? 12 | if _state is not stopped 13 | 14 | local current_album 15 | 16 | -- passed parameter (current album) 17 | set current_album to album of current track 18 | set current_album_escaped to my string_replace("\\\\'", "'", current_album) 19 | 20 | -- set up album artwork directories/parameters 21 | tell application "Finder" 22 | set script_path to container of (path to me) as text 23 | set artwork_dir to script_path & ":img:album:" 24 | set artwork_path to artwork_dir & "album.tiff" 25 | end tell 26 | 27 | -- save track details 28 | set _track to name of current track 29 | set _artist to artist of current track 30 | set _album to album of current track 31 | set _track_number to track number of current track 32 | set _duration to duration of current track 33 | set _position to player position as text 34 | set _volume to sound volume 35 | 36 | set _position to my string_replace(",", ".", _position) 37 | 38 | -- condition : only get artwork if it's a new track 39 | if current_album_escaped is not album of current track then 40 | set album_changed to true 41 | set _artwork to artwork of current track 42 | my save_image(_artwork, artwork_path) 43 | my convert_tiff_to_jpeg(artwork_path, "album.jpg", artwork_dir) 44 | else 45 | set album_changed to false 46 | end if 47 | 48 | set track_escaped to my string_replace("\"", "'", _track) 49 | 50 | -- format JSON 51 | set output to "{ 52 | \"running\" : true, 53 | \"playing\" : true, 54 | \"state\" : \"" & _state & "\", 55 | \"track\": \"" & track_escaped & "\", 56 | \"artist\": \"" & _artist & "\", 57 | \"album\": \"" & _album & "\", 58 | \"duration\": " & _duration & ", 59 | \"position\": " & _position & ", 60 | \"track_number\": " & _track_number & ", 61 | \"volume\": " & _volume & ", 62 | \"album_changed\": " & album_changed & ", 63 | \"current_album\": \"" & current_album & "\" 64 | }" 65 | 66 | -- Spotify not playing 67 | else 68 | set output to "{ 69 | \"state\" : \"" & _state & "\" 70 | }" 71 | end if 72 | 73 | end tell 74 | 75 | -- Spotify not running 76 | on error error_message 77 | set output to "{ 78 | \"state\" : \"" & error_message & "\" 79 | }" 80 | end try 81 | 82 | end run 83 | 84 | 85 | 86 | -- function to save tiff image from spotify 87 | on save_image(artwork, artwork_path) 88 | set fileRef to (open for access artwork_path with write permission) 89 | try 90 | write artwork to fileRef 91 | close access fileRef 92 | on error errorMsg 93 | try 94 | close access fileRef 95 | end try 96 | error errorMsg 97 | end try 98 | end saveImage 99 | 100 | 101 | -- convert tiff to jpeg for web display 102 | on convert_tiff_to_jpeg(source_file, new_name, results_folder) 103 | try 104 | set target_path to ((results_folder as string) & new_name) as string 105 | with timeout of 15 seconds 106 | tell application "Image Events" 107 | launch 108 | 109 | set this_image to open file (source_file as string) 110 | save this_image as JPEG in file target_path 111 | close this_image 112 | 113 | end tell 114 | end timeout 115 | on error error_message 116 | -- hi! 117 | end try 118 | end convert_tiff_to_jpeg 119 | 120 | 121 | -- function to find and replace 122 | on string_replace(needle, haystack, str) 123 | set AppleScript's text item delimiters to needle 124 | set new_str to text items of str 125 | set AppleScript's text item delimiters to haystack 126 | set str to new_str as string 127 | return the str 128 | end string_replace -------------------------------------------------------------------------------- /_includes/css/site/screen.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Screen CSS 3 | */ 4 | /* quick reset */ 5 | * { margin:0; padding:0; } 6 | 7 | /* Hide only visually, but have it available for screenreaders: h5bp.com/v */ 8 | .visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } 9 | 10 | body { 11 | font:62.5%/1.25 Helvetica, Arial, sans-serif; 12 | background:#000; 13 | color:#fff; 14 | } 15 | 16 | p { font-size:12px; } 17 | a { text-decoration:none; color:#fff; } 18 | 19 | 20 | /* layout */ 21 | html, 22 | body, 23 | #horizon, 24 | #wrapper { 25 | background:#000; 26 | width:100%; 27 | height:100%; 28 | overflow:hidden; 29 | } 30 | 31 | 32 | /* header */ 33 | #head { 34 | position:absolute; 35 | top:0; 36 | left:0; 37 | padding-top:25px; /* iOS toolbar */ 38 | height:120px; 39 | width:100%; 40 | text-align:center; 41 | z-index:2; 42 | background:url(../../img/site/bg_gradient_black-transparent_24.png) transparent repeat-x left bottom; 43 | } 44 | 45 | /* track details */ 46 | #track-name { 47 | font-weight:bold; 48 | } 49 | #album { 50 | font-style:italic; 51 | } 52 | 53 | 54 | /* progress bar */ 55 | #progress { 56 | margin-top:5px; 57 | } 58 | 59 | #time-elapsed, 60 | #time-remaining { 61 | display:inline-block; 62 | } 63 | 64 | .progress-bar { 65 | display:inline-block; 66 | position:relative; 67 | height:6px; 68 | width:70%; 69 | margin:0 10px; 70 | top:-1px; 71 | background:#333; 72 | -moz-border-radius: 3px; 73 | -webkit-border-radius: 3px; 74 | border-radius: 3px; 75 | -moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box; /* stop leaking */ 76 | } 77 | 78 | .progress-bar-fill { 79 | position:absolute; 80 | left:0; 81 | top:0; 82 | height:6px; 83 | background:#ccc; 84 | margin-left:-1px; 85 | padding-left:2px; 86 | min-width:1px; 87 | -moz-border-radius: 3px; 88 | -webkit-border-radius: 3px; 89 | border-radius: 3px; 90 | -moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box; /* stop leaking */ 91 | } 92 | 93 | 94 | /* album art */ 95 | #status { 96 | position:absolute; 97 | top:0; 98 | left:0; 99 | width:100%; 100 | height:100%; 101 | z-index:1; 102 | background-repeat:no-repeat; 103 | background-position:50% 50%; 104 | background-attachment:fixed; 105 | background-size:contain; 106 | } 107 | 108 | 109 | /* footer */ 110 | #foot { 111 | position:absolute; 112 | bottom:0; 113 | left:0; 114 | height:70px; 115 | padding-top:20px; 116 | padding-bottom:10px; 117 | width:100%; 118 | text-align:center; 119 | z-index:2; 120 | background:url(../../img/site/bg_gradient_transparent-black_24.png) transparent repeat-x left top; 121 | } 122 | 123 | /* volume */ 124 | #volume { 125 | margin-bottom:5px; 126 | } 127 | 128 | #volume p { 129 | display:inline-block; 130 | position:relative; 131 | top:4px; 132 | } 133 | 134 | #volume a { 135 | display:block; 136 | width:16px; 137 | height:16px; 138 | background:url(../../img/site/audio_volume_low.png) transparent no-repeat; 139 | } 140 | 141 | #volume p#volume-up a { 142 | background-image:url(../../img/site/audio_volume_high.png); 143 | } 144 | 145 | 146 | /* buttons */ 147 | #play-pause, 148 | #next, 149 | #previous { 150 | display:inline-block; 151 | } 152 | 153 | #play-pause a, 154 | #next a, 155 | #previous a { 156 | display:block; 157 | width:50px; 158 | height:50px; 159 | margin:0 5px; 160 | background:url(../../img/site/sprite_play_controls_24.png) #f90 no-repeat; 161 | border-radius:25px; 162 | } 163 | 164 | .playing #play-pause a { background-position:0 -100px; } 165 | #next a { background-position:0 -200px; } 166 | #previous a { background-position:0 -300px; } 167 | 168 | 169 | /* loader */ 170 | span#loading { 171 | position:absolute; 172 | right:10px; 173 | bottom:10px; 174 | display:block; 175 | width:16px; 176 | height:16px; 177 | background-image:url(../../img/site/ajax-loader-transparent.gif); 178 | background-position:right bottom; 179 | background-repeat:no-repeat; 180 | display:none; 181 | z-index:5; 182 | } 183 | 184 | span#loading.show { 185 | display:block; 186 | } 187 | 188 | 189 | /* 190 | * play states 191 | */ 192 | .loading #status, 193 | .loading #artist, 194 | .loading #album, 195 | .loading #time-elapsed, 196 | .loading #time-remaining, 197 | .loading #progress, 198 | .loading #volume, 199 | .loading #controls, 200 | 201 | .closed #status, 202 | .closed #artist, 203 | .closed #album, 204 | .closed #time-elapsed, 205 | .closed #time-remaining, 206 | .closed #progress, 207 | .closed #volume, 208 | .closed #controls, 209 | 210 | .stopped #status, 211 | .stopped #artist, 212 | .stopped #album, 213 | .stopped #time-elapsed, 214 | .stopped #time-remaining, 215 | .stopped #progress, 216 | .stopped #volume { 217 | display:none; 218 | } 219 | -------------------------------------------------------------------------------- /_includes/js/site/spotify-remote.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Spotify Remote 3 | * 4 | */ 5 | var spotifyRemote = function(){ 6 | 7 | // obj: status checking interval 8 | var statusInterval = null, 9 | 10 | // obj: loading element 11 | $loader = null, 12 | 13 | // get all command elements 14 | $commands = null, 15 | 16 | // misc HTML elements 17 | $play = null, 18 | $body = null, 19 | $status = null, 20 | $trackName = null, 21 | $artist = null, 22 | $album = null, 23 | $timeElapsed = null, 24 | $timeRemaining = null, 25 | $progress = null, 26 | $volume = null, 27 | 28 | // the current album (not non-null default) 29 | currentAlbum = ".", 30 | 31 | /** 32 | * The options passed through to this function 33 | * 34 | * @var Object 35 | * @private 36 | */ 37 | options = { 38 | 39 | /** 40 | * The location of the AJAX script on the server 41 | * 42 | * @var String 43 | */ 44 | ajaxPath : null, 45 | 46 | /** 47 | * The interval time (in seconds) between status checks 48 | * 49 | * 50 | */ 51 | interval : 1 52 | }, 53 | 54 | 55 | /** 56 | * Initialise the functionality 57 | * @param {Object} options The initialisation options 58 | * @return void 59 | * @public 60 | */ 61 | init = function(initOptions) { 62 | 63 | // save any options sent through to the intialisation script, if set 64 | for (var option in options) { 65 | if (!!initOptions[option] || initOptions[option] === false) { 66 | options[option] = initOptions[option]; 67 | } 68 | 69 | // error check, if no element is specified then stop 70 | if (!options[option] && options[option] !== false && options[option] !== 0) { 71 | throw('Required option not specified: ' + option); 72 | //return false; 73 | } 74 | } 75 | 76 | // get elements for later use 77 | $body = $("body"); 78 | $status = $("#status"); 79 | $trackName = $("#track-name"); 80 | $artist = $("#artist"); 81 | $album = $("#album"); 82 | $timeElapsed = $("#time-elapsed"); 83 | $timeRemaining = $("#time-remaining"); 84 | $progress = $("#progress"); 85 | $volume = $("#volume"); 86 | 87 | // hide things initially 88 | $body.addClass("loading"); 89 | 90 | 91 | // get all command elements 92 | $commands = $("a[data-command]"); 93 | $commands.bind("click", function(e){ 94 | e.preventDefault(); 95 | runCommand($(this).data('command')); 96 | }); 97 | 98 | 99 | // add loader 100 | $loader = $("") 101 | .attr('id', 'loading') 102 | .appendTo('#wrapper'); 103 | 104 | 105 | // check status every x seconds 106 | statusInterval = setInterval(getStatus, options.interval * 1000); 107 | }, 108 | 109 | 110 | 111 | /* 112 | * Check status 113 | */ 114 | getStatus = function() { 115 | _ajax("status", currentAlbum); 116 | }, 117 | 118 | 119 | 120 | /* 121 | * Run a command 122 | */ 123 | runCommand = function(command) { 124 | _ajax(command); 125 | }, 126 | 127 | 128 | 129 | /* 130 | * Ajax! 131 | */ 132 | _ajax = function(method, args) { 133 | 134 | showLoader(); 135 | 136 | var postData, response, result; 137 | 138 | postData = 'method='+method; 139 | 140 | // if specific arguments have been sent through, append 141 | if (!!args) { 142 | args = args.replace(/\'/g, "\\'"); 143 | args = encodeURIComponent(args); 144 | postData += '&args='+args; 145 | } 146 | 147 | postData += '&random='+Math.random(); 148 | 149 | // submit request 150 | response = $.post( 151 | options.ajaxPath, 152 | postData, 153 | function(data, textStatus){ 154 | 155 | hideLoader(); 156 | result = $.parseJSON(data); 157 | 158 | // if this is a status update, update display 159 | if (method == "status") { 160 | updateDisplay(result); 161 | } 162 | }); 163 | }, 164 | 165 | 166 | /* 167 | * show...loader 168 | */ 169 | showLoader = function() { 170 | $loader.addClass('show'); 171 | }, 172 | 173 | 174 | 175 | /* 176 | * hide...loader 177 | */ 178 | hideLoader = function() { 179 | $loader.removeClass('show'); 180 | }, 181 | 182 | 183 | /* 184 | * update display based on ajax json return 185 | */ 186 | updateDisplay = function(status) { 187 | 188 | var bodyClass; 189 | 190 | // set state 191 | if (status && status.state) { 192 | 193 | // switch on status types 194 | switch(status.state) { 195 | 196 | case "stopped": 197 | $trackName.text("Spotify ain't playing!"); 198 | bodyClass = status.state; 199 | break; 200 | 201 | case "playing": 202 | case "paused": 203 | 204 | var position = Math.round(status.position); 205 | 206 | // set text values 207 | $trackName.text(status.track); 208 | $artist.text(status.artist); 209 | $album.text(status.album); 210 | $timeElapsed.text(secondsToMinutes(position)); 211 | $timeRemaining.text(secondsToMinutes(status.duration - position)); 212 | 213 | // progress bar 214 | var progressBarWidth = ((status.position / status.duration) * 100).toFixed(2); 215 | $progress.find(".progress-bar-fill").css({ width: progressBarWidth+"%"}); 216 | 217 | // volume bar 218 | $volume.find(".progress-bar-fill").css({ width: status.volume+"%"}); 219 | 220 | // load new image? 221 | if (status.album_changed) { 222 | var time = new Date().getTime(); 223 | $status.animate({opacity:0}, 250, function(){ 224 | $status 225 | .delay(1000) 226 | .css({ "background-image":"url(./_includes/img/album/album.jpg?"+time+")"}) 227 | .animate({opacity:1}, 250); 228 | }); 229 | } 230 | 231 | // store current album, if set - for checking next time 232 | if (status && status['album']) { 233 | currentAlbum = status.album; 234 | } 235 | 236 | bodyClass = status.state; 237 | 238 | break; 239 | 240 | case "closed": 241 | $trackName.text("Spotify ain't running!"); 242 | bodyClass = status.state; 243 | break; 244 | 245 | 246 | default: 247 | $trackName.text("Error: " + status.state); 248 | bodyClass = "closed"; 249 | break; 250 | } 251 | 252 | 253 | $body.attr("class", bodyClass); 254 | } 255 | }, 256 | 257 | 258 | /* 259 | * convert seconds to minutes (and seconds) 260 | */ 261 | secondsToMinutes = function(secs) { 262 | var mins = Math.floor(secs/60); 263 | secs = secs - (mins*60); 264 | if (mins < 10) { mins = "0"+mins; } 265 | if (secs < 10) { secs = "0"+secs; } 266 | return mins+":"+secs; 267 | }; 268 | 269 | 270 | /* 271 | * Return value, expose certain methods above 272 | */ 273 | return { 274 | init: init 275 | }; 276 | }(); --------------------------------------------------------------------------------