function playerController() { var self = this; var updatetimer = null; var progresstimer = null; var safetytimer = 500; var previoussongid = -1; var AlanPartridge = 0; var plversion = null; var openpl = null; var oldplname; var thenowplayinghack = false; var lastsearchcmd = "search"; var stateChangeCallbacks = new Array(); function updateStreamInfo() { // When playing a stream, mpd returns 'Title' in its status field. // This usually has the form artist - track. We poll this so we know when // the track has changed (note, we rely on radio stations setting their // metadata reliably) // Note that mopidy doesn't quite work this way. It sets Title and possibly Name // - I fixed that bug once but it got broke again if (playlist.getCurrent('type') == "stream") { // debug.trace('STREAMHANDLER','Playlist:',playlist.getCurrent('Title'),playlist.getCurrent('Album'),playlist.getCurrent('trackartist')); var temp = playlist.getCurrentTrack(); if (player.status.Title) { var parts = player.status.Title.split(" - "); if (parts[0] && parts[1]) { temp.trackartist = parts.shift(); temp.Title = parts.join(" - "); temp.metadata.artists = [{name: temp.trackartist, musicbrainz_id: ""}]; temp.metadata.track = {name: temp.Title, musicbrainz_id: ""}; } else if (player.status.Title && player.status.Artist) { temp.trackartist = player.status.Artist; temp.Title = player.status.Title; temp.metadata.artists = [{name: temp.trackartist, musicbrainz_id: ""}]; temp.metadata.track = {name: temp.Title, musicbrainz_id: ""}; } } if (player.status.Name && !player.status.Name.match(/^\//) && temp.Album == rompr_unknown_stream) { // NOTE: 'Name' is returned by MPD - it's the station name as read from the station's stream metadata debug.shout('STREAMHANDLER',"Checking For Stream Name Update"); checkForUpdateToUnknownStream(playlist.getCurrent('StreamIndex'), player.status.Name); temp.Album = player.status.Name; temp.metadata.album = {name: temp.Album, musicbrainz_id: ""}; } // debug.trace('STREAMHANDLER','Current:',temp.Title,temp.Album,temp.trackartist); if (playlist.getCurrent('Title') != temp.Title || playlist.getCurrent('Album') != temp.Album || playlist.getCurrent('trackartist') != temp.trackartist) { debug.log("STREAMHANDLER","Detected change of track",temp); var aa = new albumart_translator(''); temp.key = aa.getKey('stream', '', temp.Album); playlist.setCurrent({Title: temp.Title, Album: temp.Album, trackartist: temp.trackartist }); nowplaying.newTrack(temp, true); } } } function checkForUpdateToUnknownStream(streamid, name) { // If our playlist for this station has 'Unknown Internet Stream' as the // station name, let's see if we can update it from the metadata. debug.log("STREAMHANDLER","Checking For Update to Stream",streamid,name, name); var m = playlist.getCurrent('Album'); if (m.match(/^Unknown Internet Stream/)) { debug.shout("PLAYLIST","Updating Stream",name); yourRadioPlugin.updateStreamName(streamid, name, playlist.getCurrent('file'), playlist.repopulate); } } function setTheClock(callback, timeout) { clearProgressTimer(); progresstimer = setTimeout(callback, timeout); } function initialised(data) { for(var i =0; i < data.length; i++) { var h = data[i].replace(/\:\/\/$/,''); debug.log("PLAYER","URL Handler : ",h); player.urischemes[h] = true; } if (!player.canPlay('spotify')) { $('div.textcentre.textunderline:contains("Music From Spotify")').remove(); } checkSearchDomains(); doMopidyCollectionOptions(); playlist.radioManager.init(); // Need to call this with a callback when we start up so that checkprogress doesn't get called // before the playlist has repopulated. self.do_command_list([],self.ready); if (!player.collectionLoaded) { debug.log("MPD", "Checking Collection"); collectionHelper.checkCollection(false, false); } } this.initialise = function() { $.ajax({ type: 'GET', url: 'player/mpd/geturlhandlers.php', dataType: 'json' }) .done(initialised) .fail(function(data) { debug.error("MPD","Failed to get URL Handlers",data); infobar.permerror(language.gettext('error_noplayer')); }); } this.ready = function() { debug.mark("MPD","Player is ready"); var t = "Connected to "+getCookie('currenthost')+" ("+prefs.player_backend.capitalize() + " at " + player_ip + ")"; infobar.notify(t); self.reloadPlaylists(); } this.do_command_list = function(list, callback) { // Note, if you call this with a callback, your callback MUST call player.controller.checkProgress $.ajax({ type: 'POST', url: 'player/mpd/postcommand.php', data: JSON.stringify(list), // contentType of false prevents jQuery from re-encoding our data, where it // converts %20 to +, which seems to be a bug in jQuery 3.0 contentType: false, dataType: 'json', timeout: 30000 }) .done(function(data) { if (data) { debug.debug("PLAYER",data); if (data.state) { // Clone the object so as not to leave this closure in memory player.status = cloneObject(data); ['radiomode', 'radioparam', 'radiomaster', 'radioconsume'].forEach(function(e) { prefs[e] = player.status[e]; }); if (player.status.playlist !== plversion) { debug.blurt("PLAYER","Player has marked playlist as changed"); plversion = player.status.playlist; playlist.repopulate(); } infobar.setStartTime(player.status.elapsed); checkStateChange(); } } }) .fail(function(jqXHR, textStatus, errorThrown) { debug.error("MPD","Command List Failed",list,textStatus,errorThrown); if (list.length > 0) { infobar.error(language.gettext('error_sendingcommands', [prefs.player_backend])); } }) .always(function() { post_command_list(callback); }); } function post_command_list(callback) { if (callback) { callback(); } else { self.checkProgress(); } infobar.updateWindowValues(); } this.isConnected = function() { return true; } this.addStateChangeCallback = function(sc) { if (player.status.state == sc.state) { sc.callback(); } else { stateChangeCallbacks.push(sc); } } function checkStateChange() { for (var i = 0; i < stateChangeCallbacks.length ; i++) { if (stateChangeCallbacks[i].state == player.status.state) { // If we're looking for a state change to play, check that elapsed > 5. This works around Mopidy's // buffering issue where playback can take a long time to start with streams and ends up starting a // long time after we've started ramping the alarm clock volume debug.log('PLAYER', 'State Change Check. State is',player.status.state,'Elapsed is',player.status.elapsed); if (player.status.state != 'play' || player.status.elapsed > 5) { debug.mark('PLAYER', 'Calling state change callback for state',player.status.state); stateChangeCallbacks[i].callback(); stateChangeCallbacks.splice(i, 1); i--; } } } } this.reloadPlaylists = function() { var openplaylists = []; $('#storedplaylists').find('i.menu.openmenu.playlist.icon-toggle-open').each(function() { openplaylists.push($(this).attr('name')); }) $.get("player/mpd/loadplaylists.php", function(data) { $("#storedplaylists").html(data); layoutProcessor.postAlbumActions(); $('b:contains("'+language.gettext('button_loadplaylist')+'")').parent('.configtitle').append(''); for (var i in openplaylists) { $('i.menu.openmenu.playlist.icon-toggle-closed[name="'+openplaylists[i]+'"]').click(); } if (openplaylists.length > 0) { infobar.markCurrentTrack(); } $('#addtoplaylistmenu').load('player/mpd/loadplaylists.php?addtoplaylistmenu'); }); } this.loadPlaylist = function(name) { self.do_command_list([['load', name]]); return false; } this.loadPlaylistURL = function(name) { if (name == '') { return false; } var data = {url: encodeURIComponent(name)}; $.ajax({ type: "GET", url: "utils/getUserPlaylist.php", cache: false, data: data, dataType: "xml" }) .done(function() { self.reloadPlaylists(); self.addTracks([{type: 'remoteplaylist', name: name}], null, null); }) .fail(function(data, status) { playlist.repopulate(); debug.error("MPD","Failed to save user playlist URL"); }); return false; } this.deletePlaylist = function(name, callback) { openpl = null; name = decodeURIComponent(name); if (callback) { self.do_command_list([['rm',name]], callback); } else { self.do_command_list([['rm',name]], function() { self.reloadPlaylists(); if (typeof(playlistManager) != 'undefined') { playlistManager.reloadAll(); } }); } } this.deleteUserPlaylist = function(name) { openpl = null; var data = {del: encodeURIComponent(name)}; $.ajax({ type: "GET", url: "utils/getUserPlaylist.php", cache: false, data: data, dataType: "xml" }) .done(self.reloadPlaylists) .fail(function(data, status) { debug.error("MPD","Failed to delete user playlist",name); }); } this.renamePlaylist = function(name, e, callback) { openpl = null; oldplname = name; debug.log("MPD","Renaming Playlist",name,e); var fnarkle = new popup({ css: { width: 400, height: 300 }, title: language.gettext("label_renameplaylist"), atmousepos: true, mousevent: e }); var mywin = fnarkle.create(); var d = $('
',{class: 'containerbox'}).appendTo(mywin); var e = $('
',{class: 'expand'}).appendTo(d); var i = $('',{class: 'enter', id: 'newplname', type: 'text', size: '200'}).appendTo(e); var b = $('