var snapcast = function() { var groups = new Array(); var streams = new Array(); var updatetimer = null; var id = 0; var lastid = 0; var ew = null; function snapcastRequest(parms, callback) { clearTimeout(updatetimer); id++; parms.id = id; parms.jsonrpc = "2.0"; $.ajax({ type: 'POST', url: 'snapcast/snapapi.php', data: JSON.stringify(parms) }) .done(callback) .fail(function(jqXHR, textStatus, errorThrown) { debug.error("SNAPCAST","Command Failed",parms,textStatus,errorThrown); callback({error: language.gettext('snapcast_notthere')}); }) } function findGroup(arr, id) { for (var i in arr) { if (arr[i].getId() == id) { return i; } } return false; } return { updateStatus: function() { clearTimeout(updatetimer); if (prefs.snapcast_server != '' && prefs.snapcast_port != '') { snapcastRequest({ method: "Server.GetStatus" }, snapcast.gotStatus); $('#snapheader').removeClass('invisible'); } }, gotStatus: function(data) { debug.trace("SNAPCAST", "Server Status", data); if (data.hasOwnProperty('error') && lastid != id) { if (ew === null) { ew = $('
', {class: "fullwidth textcentre", style: "padding:4px"}).insertBefore('#snapcastgroups'); $('#snapcastgroups').addClass('canbefaded').css({opacity: '0.4'}); } ew.html(''+data.error+''); } else if (data.hasOwnProperty('id') && parseInt(data.id) == id) { lastid = id; if (ew !== null) { ew.remove(); ew = null; $('#snapcastgroups').removeClass('canbefaded').css({opacity: ''}); } streams = data.result.server.streams; var newgroups = new Array(); for (var i in data.result.server.groups) { var group_exists = findGroup(groups, data.result.server.groups[i].id); if (group_exists === false) { debug.log('SNAPCAST','Creating new group',data.result.server.groups[i].id); var g = new snapcastGroup(); newgroups.push(g); g.initialise(); g.update(i, data.result.server.groups[i]); } else { debug.trace('SNAPCAST','Updating group',data.result.server.groups[i].id); newgroups.push(groups[group_exists]); groups[group_exists].update(i, data.result.server.groups[i]); } } // Find removed groups for (var i in groups) { if (findGroup(newgroups, groups[i].getId()) === false) { debug.log('SNAPCAST','Group',groups[i].getId(),'has been removed'); groups[i].removeSelf(); groups[i] = null; } } groups = newgroups; } else { debug.shout('SNAPCAST','Got response with id',data.id,'expecting',id); } updatetimer = setTimeout(snapcast.updateStatus, 60000); }, streamInfo: function(streamid) { for (var i in streams) { if (streams[i].id == streamid) { var h = streams[i].status.capitalize()+' '; h += streams[i].meta.STREAM; h += ' ('+streams[i].uri.query.codec+' '+streams[i].uri.query.sampleformat+')'; return h; } } return 'Unknown Stream'; }, getAllStreams: function() { return streams; }, getAllGroups: function() { var retval = new Array(); for (var i in groups) { retval.push(groups[i].getInfo()); } return retval; }, setClientVolume: function(id, volume, muted) { clearTimeout(updatetimer); snapcastRequest({ method: "Client.SetVolume", params: { id: id, volume: { muted: muted, percent: volume } } }, snapcast.updateStatus); }, setGroupMute: function(id, muted) { clearTimeout(updatetimer); snapcastRequest({ method: "Group.SetMute", params: { id: id, mute: muted } }, snapcast.updateStatus); }, deleteClient: function(id) { clearTimeout(updatetimer); snapcastRequest({ method: "Server.DeleteClient", params: { id: id } }, snapcast.gotStatus); }, setClientName: function(id, name) { clearTimeout(updatetimer); snapcastRequest({ method: "Client.SetName", params: { id: id, name: name } }, snapcast.updateStatus); }, setClientLatency: function(id, latency) { clearTimeout(updatetimer); snapcastRequest({ method: "Client.SetLatency", params: { id: id, latency: parseInt(latency) } }, snapcast.updateStatus); }, setStream: function(group, stream) { clearTimeout(updatetimer); snapcastRequest({ method: "Group.SetStream", params: { id: group, stream_id: stream } }, snapcast.updateStatus); }, addClientToGroup: function(client, group) { clearTimeout(updatetimer); var groupindex = findGroup(groups, group); var clients = groups[groupindex].getClients(); clients.push(client); snapcastRequest({ method: "Group.SetClients", params: { clients: clients, id: group } }, snapcast.gotStatus); }, clearEverything: function() { clearTimeout(updatetimer); streams = []; groups = []; $('#snapcastgroups').empty(); } } }(); function snapcastGroup() { var self = this; var clients = new Array(); var holder; var id = ''; var muted; var streammenu; var ind; var name; function findClient(arr, id) { for (var i in arr) { if (arr[i].getId() == id) { return i; } } return false; } this.initialise = function() { holder = $('
', {class: 'snapcastgroup fullwidth'}).appendTo('#snapcastgroups'); var title = $('
', {class: 'containerbox snapgrouptitle dropdown-container'}).appendTo(holder); title.append('
'); title.append('
'); var m = $('', {class: "podicon fixed icon-menu clickicon"}).appendTo(title).on('click', self.setStream); m = $('', {class: "podicon fixed clickicon", name: "groupmuted"}).appendTo(title).on('click', self.setMute); streammenu = $('
', {class: 'toggledown invisible'}).insertAfter(title); } this.removeSelf = function() { holder.remove(); } this.getId = function() { return id; } this.update = function(index, data) { ind = index; id = data.id; muted = data.muted; name = data.name; var g = language.gettext('snapcast_group')+index; if (data.name) { g += ' ('+data.name+')'; } holder.find('div[name="groupname"]').html(g); holder.find('div[name="groupstream"]').html(snapcast.streamInfo(data.stream_id)); var icon = data.muted ? 'icon-output-mute' : 'icon-output'; holder.find('i[name="groupmuted"]').removeClass('icon-output icon-output-mute').addClass(icon); var newclients = new Array(); for (var i in data.clients) { var client_exists = findClient(clients, data.clients[i].id); if (client_exists === false) { debug.log('SNAPCAST','Creating new client',data.clients[i].id); var g = new snapcastClient(); newclients.push(g); g.initialise(holder); g.update(id, data.clients[i]); } else { debug.trace('SNAPCAST','Updating client',data.clients[i].id); newclients.push(clients[client_exists]); clients[client_exists].update(id, data.clients[i]); } } // Find removed groups for (var i in clients) { if (findClient(newclients, clients[i].getId()) === false) { debug.log('SNAPCAST','Client',clients[i].getId(),'has been removed'); clients[i].removeSelf(); clients[i] = null; } } clients = newclients; } this.setMute = function() { snapcast.setGroupMute(id, !muted); } this.setStream = function() { streammenu.empty(); var s = snapcast.getAllStreams(); var a = $('
', {class: 'menuitem textcentre'}).appendTo(streammenu); a.html('Change Stream'); for (var i in s) { var d = $('
', {class: 'backhi clickitem', name: s[i].id}).appendTo(streammenu).on('click', self.changeStream); d.html(snapcast.streamInfo(s[i].id)); } streammenu.slideToggle('fast'); } this.changeStream = function(e) { var streamid = $(this).attr('name'); debug.log('SNAPCAST', 'Group',id,'changing stream to',streamid); snapcast.setStream(id, streamid); streammenu.slideToggle('fast'); } this.getInfo = function() { return {index: ind, id: id, name: name}; } this.getClients = function() { var retval = new Array(); for (var i in clients) { retval.push(clients[i].getId()); } return retval; } } function snapcastClient() { var self = this; var holder; var id = ''; var volume; var volumepc; var muted; var vc; var groupmenu; var grouplist; var groupid; var connected; this.initialise = function(parentdiv) { holder = $('
', {class: 'snapcastclient'}).appendTo(parentdiv); var title = $('
', {class: 'containerbox dropdown-container'}).appendTo(holder); var n = $('', {type: "text", class: "expand tag snapclientname", name: "clientname"}).appendTo(title); var but = $('