/*********************************** * play tracks from a browse list * ***********************************/ function playBrowsedTracks(action, trackIndex) { $('#popupBrowse').popup('close'); toast('Loading...'); if (typeof trackIndex === 'undefined') { trackIndex = $('#popupBrowse').data("tlid"); } if (action == PLAY_ALL) { mopidy.tracklist.clear(); // Default for radio streams is to just add the selected URI. if (isStreamUri(browseTracks[trackIndex].uri)) { action = PLAY_NOW; } } var trackUris = []; switch (action) { case PLAY_NOW: case PLAY_NEXT: case ADD_THIS_BOTTOM: trackUris.push(browseTracks[trackIndex].uri); break; case PLAY_ALL: case ADD_ALL_BOTTOM: trackUris = getUris(browseTracks); break; default: break; } var maybePlay = function(tlTracks) { if (action === PLAY_NOW || action === PLAY_ALL) { var playIndex = (action === PLAY_ALL) ? trackIndex : 0; mopidy.playback.play({'tl_track': tlTracks[playIndex]}); } }; switch (action) { case PLAY_NOW: case PLAY_NEXT: mopidy.tracklist.index().then(function (currentIndex) { mopidy.tracklist.add({'at_position': currentIndex + 1, 'uris': trackUris}).then(maybePlay); }); break; case ADD_THIS_BOTTOM: case ADD_ALL_BOTTOM: case PLAY_ALL: mopidy.tracklist.add({'uris': trackUris}).then(maybePlay); break; default: break; } return false; } /********************************* * play an uri from a tracklist * *********************************/ function playTrack(action) { var hash = document.location.hash.split('?'); var divid = hash[0].substr(1); // Search page default click behaviour adds and plays selected track only. if (action == PLAY_NOW && divid == 'search') { action = PLAY_NOW_SEARCH; } $('#popupTracks').popup('close'); $('#controlspopup').popup('close'); toast('Loading...'); playlisturi = $('#popupTracks').data("list"); uri = $('#popupTracks').data("track"); var trackUris = getTracksFromUri(playlisturi); //find track that was selected for (var selected = 0; selected < trackUris.length; selected++) { if (trackUris[selected] == uri) { break; } } switch (action) { case ADD_THIS_BOTTOM: case PLAY_NEXT: case PLAY_NOW_SEARCH: trackUris = [trackUris[selected]]; selected = 0; } switch (action) { case PLAY_NOW: case PLAY_NOW_SEARCH: mopidy.tracklist.clear().then( mopidy.tracklist.add({'uris': trackUris}).then( function(tlTracks) { mopidy.playback.play({'tl_track': tlTracks[selected]}) } ) ); break; case PLAY_NEXT: mopidy.tracklist.index().then(function(currentIndex) { mopidy.tracklist.add({'at_position': currentIndex + 1, 'uris': trackUris}); }); break; case ADD_THIS_BOTTOM: case ADD_ALL_BOTTOM: mopidy.tracklist.add({'uris': trackUris}); break; } return false; } /*** * Plays a Track given by an URI from the given playlist URI. * @param track_uri, playlist_uri * @returns {boolean} */ function playTrackByUri(track_uri, playlist_uri) { function findAndPlayTrack(tltracks) { if (tltracks.length > 0) { // Find track that was selected for (var selected = 0; selected < tltracks.length; selected++) { if (tltracks[selected].track.uri == track_uri) { mopidy.playback.play({'tl_track': tltracks[selected]}); return; } } } console.error('Failed to find and play selected track ', track_uri); return; } // Stop directly, for user feedback mopidy.tracklist.clear(); //this is deprecated, remove when popuptracks is removed completly $('#popupTracks').popup('close'); $('#controlspopup').popup('close'); //end of deprecated toast('Loading...'); mopidy.tracklist.add({'uris': [playlist_uri]}).then(function(tltracks) { // Can fail for all sorts of reasons. If so, just add individually. if (tltracks.length == 0) { var trackUris = getTracksFromUri(playlist_uri, false); mopidy.tracklist.add({'uris': trackUris}).then(findAndPlayTrack); } else { findAndPlayTrack(tltracks); } }); return false; } /******************************************************** * play an uri from the queue *********************************************************/ /*** * Plays a Track from a Playlist. * @param uri * @param tlid * @returns {boolean} */ function playTrackQueueByTlid(uri, tlid) { //stop directly, for user feedback mopidy.playback.stop(); $('#popupQueue').popup('close'); toast('Loading...'); tlid = parseInt(tlid); mopidy.tracklist.filter({ 'tlid': [tlid] }).then( function(tltracks) { if (tltracks.length > 0) { mopidy.playback.play({'tl_track': tltracks[0]}); return; } console.log('Failed to play selected track ', tlid); } ); return false; } /*** * @deprecated * @returns {boolean} */ function playTrackQueue() { uri = $('#popupQueue').data("track"); tlid = $('#popupQueue').data("tlid"); return playTrackQueueByTlid(uri, tlid); } /*********************************** * remove a track from the queue * ***********************************/ function removeTrack() { $('#popupQueue').popup('close'); toast('Deleting...'); tlid = parseInt($('#popupQueue').data("tlid")); console.log(tlid); mopidy.tracklist.remove({'tlid': [tlid]}); } function clearQueue() { mopidy.playback.stop(); resetSong(); mopidy.tracklist.clear(); resetSong(); return false; } function saveQueue() { mopidy.tracklist.getTracks().then(function(tracks) { if (tracks.length > 0) { var plname = window.prompt("Playlist name:", "").trim(); if (plname != null && plname != "") { mopidy.playlists.filter({"name": plname}).then(function(existing) { var exists = false; for (var i = 0; i < existing.length; i++) { exists = exists || existing[i].uri.indexOf("m3u:") == 0 || existing[i].uri.indexOf("local:") == 0; } if (!exists || window.confirm("Overwrite existing playlist \"" + plname + "\"?")) { mopidy.playlists.create({'name': plname, 'uri_scheme': "local"}).then(function(playlist) { playlist.tracks = tracks; mopidy.playlists.save({'playlist': playlist}).then(); getPlaylists(); }); } }); } } }); return false; } function refreshPlaylists() { mopidy.playlists.refresh(); return false; } /************* * Buttons * *************/ function doShuffle() { mopidy.playback.stop(); mopidy.tracklist.shuffle(); mopidy.playback.play(); } /* Toggle state of play button */ function setPlayState(nwplay) { if (nwplay) { $("#btplayNowPlaying >i").removeClass('fa-play').addClass('fa-pause'); $("#btplayNowPlaying").attr('title', 'Pause'); $("#btplay >i").removeClass('fa-play').addClass('fa-pause'); $("#btplay").attr('title', 'Pause'); } else { $("#btplayNowPlaying >i").removeClass('fa-pause').addClass('fa-play'); $("#btplayNowPlaying").attr('title', 'Play'); $("#btplay >i").removeClass('fa-pause').addClass('fa-play'); $("#btplay").attr('title', 'Play'); } play = nwplay; } //play or pause function doPlay() { toast('Please wait...', 250); if (!play) { mopidy.playback.play(); } else { if(isStreamUri(songdata.track.uri)) { mopidy.playback.stop(); } else { mopidy.playback.pause(); } } setPlayState(!play); } function doPrevious() { toast('Playing previous track...'); mopidy.playback.previous(); } function doNext() { toast('Playing next track...'); mopidy.playback.next(); } function backbt() { history.back(); return false; } /************* * Options * *************/ function setTracklistOption(name, new_value) { if (!new_value) { $("#"+name+"bt").attr('style', 'color:#2489ce'); } else { $("#"+name+"bt").attr('style', 'color:#66DD33'); } return new_value } function setRepeat(nwrepeat) { if (repeat != nwrepeat) { repeat = setTracklistOption("repeat", nwrepeat); } } function setRandom(nwrandom) { if (random != nwrandom) { random = setTracklistOption("random", nwrandom); } } function setConsume(nwconsume) { if (consume != nwconsume) { consume = setTracklistOption("consume", nwconsume); } } function setSingle(nwsingle) { if (single != nwsingle) { single = setTracklistOption("single", nwsingle); } } function doRandom() { mopidy.tracklist.setRandom({'value': !random}).then(); } function doRepeat() { mopidy.tracklist.setRepeat({'value': !repeat}).then(); } function doConsume() { mopidy.tracklist.setConsume({'value': !consume}).then(); } function doSingle() { mopidy.tracklist.setSingle({'value': !single}).then(); } /*********************************************** * Track Slider * * Use a timer to prevent looping of commands * ***********************************************/ function doSeekPos(value) { var val = $("#trackslider").val(); newposition = Math.round(val); if (!initgui) { pausePosTimer(); //set timer to not trigger it too much clearTimeout(seekTimer); $("#songelapsed").html(timeFromSeconds(val / 1000)); seekTimer = setTimeout(triggerPos, 500); } } function triggerPos() { if (mopidy) { posChanging = true; mopidy.playback.seek({'time_position': newposition}); resumePosTimer(); posChanging = false; } } function setPosition(pos) { if (posChanging) { return; } var oldval = initgui; if (pos > songlength) { pos = songlength; pausePosTimer(); } currentposition = pos; initgui = true; $("#trackslider").val(currentposition).slider('refresh'); initgui = oldval; $("#songelapsed").html(timeFromSeconds(currentposition / 1000)); } /*********************************************** * Volume slider * * Use a timer to prevent looping of commands * ***********************************************/ function setVolume(value) { if ($("#volumeslider").val() != value) { $("#volumeslider").val(value).slider('refresh'); } } function doVolume(value) { volumeChanging = value; clearInterval(volumeTimer); volumeTimer = setTimeout(triggerVolume, 500); } function triggerVolume() { mopidy.playback.setVolume({'volume': parseInt(volumeChanging)}); volumeChanging = 0; } function setMute(nwmute) { if (mute != nwmute) { mute = nwmute; if (mute) { $("#mutebt").attr('class', 'fa fa-volume-off'); } else { $("#mutebt").attr('class', 'fa fa-volume-up'); } } } function doMute() { mopidy.mixer.setMute({'mute': !mute}); } /************************** * Track position timer * **************************/ //timer function to update interface function updatePosTimer() { currentposition += TRACK_TIMER; setPosition(currentposition); } function resumePosTimer() { pausePosTimer(); if (songlength > 0) { posTimer = setInterval(updatePosTimer, TRACK_TIMER); } } function initPosTimer() { pausePosTimer(); // setPosition(0); resumePosTimer(); } function pausePosTimer() { clearInterval(posTimer); } /************ * Stream * ************/ function streamPressed(key) { if (key == 13) { playStreamUri(); return false; } return true; } function playStreamUri(uri) { //value of name is based on the passing of an uri as a parameter or not var nwuri = uri || $('#streamuriinput').val().trim(); var service = $('#selectstreamservice').val(); if (!uri && service) { nwuri = service + ':' + nwuri; } if (isServiceUri(nwuri) || isStreamUri(nwuri) || validUri(nwuri)) { toast('Playing...'); //stop directly, for user feedback mopidy.playback.stop(); //hide ios/android keyboard document.activeElement.blur(); clearQueue(); $("input").blur(); mopidy.tracklist.add({'uris': [nwuri]}); mopidy.playback.play(); } else { toast('No valid url!'); } return false; } function getCurrentlyPlaying() { $('#streamuriinput').val(songdata.track.uri); var name = songdata.track.name; if (songdata.track.artists) { var artistStr = artistsToString(songdata.track.artists); if (artistStr) { name = artistStr + ' - ' + name; } } $('#streamnameinput').val(name); return true; } function getUriSchemes() { uriSchemes = {}; return mopidy.getUriSchemes().then(function(schemes) { for (var i = 0; i < schemes.length; i++) { uriSchemes[schemes[i].toLowerCase()] = true; } }); } function getPlaylistByName(name, scheme, create) { var uri_scheme = scheme || ''; var uri = ''; if (uri_scheme && !uriSchemes[uri_scheme]) { return Mopidy.when(false); } return mopidy.playlists.asList().catch(console.error.bind(console)).then(function(plists) { for (var i = 0; i < plists.length; i++) { if ((plists[i].name === name) && (uri_scheme === '' || getScheme(plists[i].uri) === uri_scheme)) { return plists[i]; } } if (create) { return mopidy.playlists.create({'name': name, 'uri_scheme': uri_scheme}).done(function(plist) { console.log("Created playlist '%s'", plist.name); return plist; }); } console.log("Can't find playist '%s", name); return Mopidy.when(false); }); } function getPlaylistFull(uri) { return mopidy.playlists.lookup({'uri': uri}).then(function(pl) { playlists[uri] = pl; return pl; }); } function getFavourites() { return getPlaylistByName(STREAMS_PLAYLIST_NAME, STREAMS_PLAYLIST_SCHEME, true).then(function(playlist) { if (playlist) { return getPlaylistFull(playlist.uri); } return Mopidy.when(false); }); } function addToFavourites(newTracks) { getFavourites().catch(console.error.bind(console)).then(function(favourites) { if (favourites) { if (favourites.tracks) { Array.prototype.push.apply(favourites.tracks, newTracks) } else { favourites.tracks = newTracks; } mopidy.playlists.save({'playlist': favourites}).then(function(s) { showFavourites(); }); } }); } function addFavourite(uri, name) { var uri = uri || $('#streamuriinput').val().trim(); var name = name || $('#streamnameinput').val().trim(); mopidy.library.lookup({'uris': [uri]}).then(function(results) { var newTracks = results[uri]; if (newTracks.length == 1) { // TODO: Supporting adding an entire playlist? if (name) { newTracks[0].name = name; // User overrides name. } addToFavourites(newTracks); } else { if (newTracks.length == 0) { console.log('No tracks to add'); } else { console.log('Too many tracks (%d) to add', tracks.length); } } }); } function deleteFavourite(index) { getFavourites().then(function(favourites) { if (favourites && favourites.tracks && index < favourites.tracks.length) { var name = favourites.tracks[index].name; if (confirm("Are you sure you want to remove '" + name + "'?")) { favourites.tracks.splice(index, 1); mopidy.playlists.save({'playlist': favourites}).then(function(s) { showFavourites(); }); } } }); } function showFavourites() { $('#streamuristable').empty(); getFavourites().then(function(favourites) { if (!favourites) { return; } var tmp = ''; $.cookie.json = true; if ($.cookie('streamUris')) { tmp = '' } if (favourites.tracks) { var child = ''; for (var i = 0; i < favourites.tracks.length; i++) { child = '