1345 lines
55 KiB
JavaScript
1345 lines
55 KiB
JavaScript
var playlist = function() {
|
|
|
|
var tracklist = [];
|
|
var currentalbum = -1;
|
|
var finaltrack = -1;
|
|
var do_delayed_update = false;
|
|
var pscrolltimer = null;
|
|
var pageloading = true;
|
|
var lookforcurrenttrack = false;
|
|
var reqid = 0;
|
|
var last_reqid = 0;
|
|
var update_error = false;
|
|
var retrytimer;
|
|
var popmovetimer = null;
|
|
var popmoveelement = null;
|
|
var popmovetimeout = 2000;
|
|
|
|
// Minimal set of information - just what infobar requires to make sure
|
|
// it blanks everything out
|
|
// playlistpos is for radioManager
|
|
// backendid must not be undefined
|
|
var emptyTrack = {
|
|
Album: "",
|
|
trackartist: "",
|
|
file: "",
|
|
Title: "",
|
|
type: "",
|
|
Pos: 0,
|
|
Id: -1,
|
|
progress: 0,
|
|
images: null
|
|
};
|
|
|
|
var currentTrack = emptyTrack;
|
|
|
|
function addSearchDir(element) {
|
|
var options = new Array();
|
|
element.next().find('.playable').each(function(index, elem){
|
|
if ($(elem).hasClass('searchdir')) {
|
|
options.concat(addSearchDir($(elem)));
|
|
} else {
|
|
options.push({
|
|
type: 'uri',
|
|
name: decodeURIComponent($(elem).attr('name'))
|
|
});
|
|
}
|
|
});
|
|
return options;
|
|
}
|
|
|
|
function personalRadioManager() {
|
|
|
|
var self = this;
|
|
var mode = '';
|
|
var param = null;
|
|
var radios = new Object();
|
|
var rptimer = null;
|
|
var startplaybackfrom = null;
|
|
|
|
function actuallyRepopulate() {
|
|
debug.log("RADIO MANAGER","Repopulate Timer Has Fired");
|
|
debug.log("RADIO MANAGER","mode is",mode);
|
|
debug.trace("RADIO MANAGER","prefs.radiomode is",prefs.radiomode);
|
|
debug.trace("RADIO MANAGER","prefs.radioparam is",prefs.radioparam);
|
|
debug.trace("RADIO MANAGER","prefs.browser_id is",prefs.browser_id);
|
|
debug.trace("RADIO MANAGER","prefs.radiomaster is",prefs.radiomaster);
|
|
|
|
if ((mode && mode != prefs.radiomode) || (mode && param && param != prefs.radioparam)) {
|
|
radios[mode].func.stop();
|
|
}
|
|
|
|
param = prefs.radioparam;
|
|
|
|
if (prefs.radiomode != mode) {
|
|
mode = prefs.radiomode;
|
|
if (mode) {
|
|
playlist.preventControlClicks(false);
|
|
player.controller.takeBackControl();
|
|
if (radios[mode].script && radios[mode].loaded == false) {
|
|
debug.shout("RADIO MANAGER","Loading Script",radios[mode].script,"for",mode);
|
|
$.getScript(radios[mode].script+'?version='+rompr_version)
|
|
.done(function() {
|
|
radios[mode].loaded = true;
|
|
actuallyActuallyRepopulate();
|
|
})
|
|
.fail(function(data,thing,wotsit) {
|
|
debug.error("RADIO MANAGER","Failed to Load Script",wotsit);
|
|
mode = null;
|
|
player.controller.checkConsume(prefs.radioconsume);
|
|
playlist.repopulate();
|
|
infobar.error(language.gettext('label_general_error'));
|
|
});
|
|
} else {
|
|
actuallyActuallyRepopulate();
|
|
}
|
|
} else {
|
|
player.controller.checkConsume(prefs.radioconsume);
|
|
playlist.preventControlClicks(true);
|
|
setHeader();
|
|
}
|
|
} else {
|
|
actuallyActuallyRepopulate();
|
|
}
|
|
}
|
|
|
|
function actuallyActuallyRepopulate() {
|
|
setHeader();
|
|
var fromend = playlist.getfinaltrack()+1;
|
|
if (currentTrack.playlistpos) {
|
|
fromend -= currentTrack.playlistpos;
|
|
}
|
|
var tracksneeded = prefs.smartradio_chunksize - fromend;
|
|
if (tracksneeded > 1 && prefs.radiomaster != prefs.browser_id) {
|
|
debug.mark("RADIO MANAGER","Looks like master has gone away. Taking over");
|
|
prefs.save({radiomaster: prefs.browser_id});
|
|
}
|
|
debug.log("RADIO MANAGER","Repopulate Check : Final Track :",playlist.getfinaltrack()+1,"Fromend :",fromend,"Chunksize :",prefs.smartradio_chunksize,"Mode :",mode);
|
|
if (reqid == last_reqid && mode && prefs.radiomaster == prefs.browser_id) {
|
|
// Don't do anything if we're waiting on playlist updates
|
|
if (fromend < prefs.smartradio_chunksize) {
|
|
debug.shout("RADIO MANAGER","Repopulating");
|
|
playlist.waiting();
|
|
radios[mode].func.populate(prefs.radioparam, tracksneeded);
|
|
}
|
|
}
|
|
}
|
|
|
|
function setHeader() {
|
|
var html = '';
|
|
if (mode && radios[mode].func.modeHtml) {
|
|
var x = radios[mode].func.modeHtml(prefs.radioparam);
|
|
if (x) {
|
|
html = x + '<i class="icon-cancel-circled playlisticon clickicon" style="margin-left:8px" onclick="playlist.radioManager.stop()"></i>';
|
|
}
|
|
}
|
|
layoutProcessor.setRadioModeHeader(html);
|
|
}
|
|
|
|
return {
|
|
|
|
register: function(name, fn, script) {
|
|
debug.log("RADIO MANAGER","Registering Plugin",name);
|
|
radios[name] = {func: fn, script: script, loaded: false};
|
|
},
|
|
|
|
init: function() {
|
|
for(var i in radios) {
|
|
debug.log("RADIO MANAGER","Activating Plugin",i);
|
|
radios[i].func.setup();
|
|
}
|
|
if (prefs.player_backend == "mopidy") {
|
|
$("#radiodomains").addClass('tiny').makeDomainChooser({
|
|
default_domains: prefs.mopidy_radio_domains,
|
|
sources_not_to_choose: {
|
|
bassdrive: 1,
|
|
dirble: 1,
|
|
tunein: 1,
|
|
audioaddict: 1,
|
|
oe1: 1,
|
|
podcast: 1,
|
|
}
|
|
});
|
|
$("#radiodomains").find('input.topcheck').each(function() {
|
|
$(this).on('click', function() {
|
|
prefs.save({mopidy_radio_domains: $("#radiodomains").makeDomainChooser("getSelection")});
|
|
});
|
|
});
|
|
uiHelper.setupPersonalRadio();
|
|
}
|
|
},
|
|
|
|
load: function(which, param) {
|
|
if (prefs.debug_enabled > 0) {
|
|
infobar.longnotify(language.gettext('warning_smart_debug'));
|
|
}
|
|
if (!mode) {
|
|
prefs.save({radioconsume: player.status.consume});
|
|
}
|
|
layoutProcessor.playlistLoading();
|
|
prefs.save({radiomode: which, radioparam: param, radiomaster: prefs.browser_id}, player.controller.clearPlaylist);
|
|
startplaybackfrom = 0;
|
|
},
|
|
|
|
playbackStartPos: function() {
|
|
// startplaybackfrom is set to 0 when we first start a new radio. This makes the radio populate
|
|
// functions start playback when the first populate. After that it's set to null, because otherwise
|
|
// the user can stop playback, we repopulate, and playback starts again.
|
|
var a = startplaybackfrom;
|
|
startplaybackfrom = null;
|
|
return a;
|
|
},
|
|
|
|
repopulate: function() {
|
|
debug.debug("RADIO MANAGER","Setting Repopulate Timer");
|
|
// The timer is a mechanism to stop us repeatedly calling this when
|
|
// lots of asynchronous stuff is happening at once. There are several routes
|
|
// that call into this function to handle all the cases we need to handle
|
|
// but we only want to act on one of them.
|
|
clearTimeout(rptimer);
|
|
rptimer = setTimeout(actuallyRepopulate, 1000);
|
|
},
|
|
|
|
stop: function(callback) {
|
|
debug.log("RADIO MANAGER","Stopping");
|
|
// Not stricly ncessary, but does make the UI more responsive
|
|
layoutProcessor.setRadioModeHeader('');
|
|
callback = (callback || playlist.repopulate);
|
|
prefs.save({radiomode: '', radioparam: null}, callback);
|
|
},
|
|
|
|
isRunning: function() {
|
|
return (mode != '');
|
|
},
|
|
|
|
loadFromUiElement: function(element) {
|
|
var params = element.attr('name').split('+');
|
|
playlist.radioManager.load(params[0], params[1] ? params[1] : null);
|
|
},
|
|
|
|
standardBox: function(station, param, icon, label) {
|
|
var container = $('<div>', {
|
|
class: 'menuitem containerbox playable smartradio',
|
|
name: station + (param ? '+'+param : '')
|
|
});
|
|
container.append('<div class="svg-square fixed '+icon+'"></div>');
|
|
container.append('<div class="expand">'+label+'</div>');
|
|
return container;
|
|
},
|
|
|
|
dropdownHeader: function(station, param, icon, label, dropid) {
|
|
var container = $('<div>', {
|
|
class: 'menuitem containerbox playable smartradio',
|
|
name: station + (param ? '+'+param : '')
|
|
});
|
|
container.append($('<i>', {
|
|
class: 'icon-toggle-closed menu openmenu mh fixed',
|
|
name: dropid
|
|
}));
|
|
container.append('<div class="svg-square noindent fixed '+icon+'"></div>');
|
|
container.append('<div class="expand">'+label+'</div>');
|
|
return container;
|
|
},
|
|
|
|
dropdownHolder: function(id) {
|
|
return $('<div>', {
|
|
class: 'toggledown invisible expand',
|
|
id: id
|
|
});
|
|
},
|
|
|
|
textEntry: function(icon, label, id) {
|
|
var html = '<div class="menuitem containerbox fullwidth">';
|
|
html += '<div class="svg-square fixed '+icon+'"></div>';
|
|
html += '<div class="expand dropdown-holder"><input class="enter clearbox" id="'+id+'" type="text" placeholder="'+label+'" /></div>';
|
|
html += '<button class="fixed alignmid" name="'+id+'">'+language.gettext('button_playradio')+'</button>';
|
|
html += '</div>';
|
|
return html;
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
|
|
rolledup: [],
|
|
|
|
radioManager: new personalRadioManager(),
|
|
|
|
repopulate: function() {
|
|
if (last_reqid == reqid) {
|
|
debug.shout("PLAYLIST","Repopulating....");
|
|
reqid++;
|
|
player.controller.getPlaylist(reqid);
|
|
coverscraper.clearCallbacks();
|
|
} else {
|
|
debug.log("PLAYLIST","Deferring repopulate request");
|
|
reqid++;
|
|
clearTimeout(retrytimer);
|
|
retrytimer = setTimeout(playlist.repopulate, 500);
|
|
}
|
|
},
|
|
|
|
updateFailure: function(jqxhr, response, error) {
|
|
debug.error("PLAYLIST","Got notified that an update FAILED",error,response,jqxhr);
|
|
if (update_error === false) {
|
|
update_error = infobar.permerror(language.gettext("label_playlisterror"));
|
|
}
|
|
clearTimeout(retrytimer);
|
|
last_reqid = reqid;
|
|
retrytimer = setTimeout(playlist.repopulate, 2000);
|
|
},
|
|
|
|
newXSPF: function(request_id, list) {
|
|
var count = -1;
|
|
var current_album = "";
|
|
var current_artist = "";
|
|
var current_type = "";
|
|
|
|
if (request_id != reqid) {
|
|
debug.mark("PLAYLIST","Response from player does not match current request ID");
|
|
last_reqid = reqid;
|
|
return 0;
|
|
}
|
|
|
|
last_reqid = reqid;
|
|
|
|
if (update_error !== false) {
|
|
infobar.removenotify(update_error);
|
|
update_error = false;
|
|
}
|
|
debug.log("PLAYLIST","Got Playlist from backend",list);
|
|
finaltrack = -1;
|
|
currentalbum = -1;
|
|
tracklist = [];
|
|
var totaltime = 0;
|
|
|
|
for (var i in list) {
|
|
list[i].Time = parseFloat(list[i].Time);
|
|
totaltime += list[i].Time;
|
|
var sortartist = (list[i].albumartist == "") ? list[i].trackartist : list[i].albumartist;
|
|
if ((sortartist.toLowerCase() != current_artist.toLowerCase()) ||
|
|
list[i].Album.toLowerCase() != current_album.toLowerCase() ||
|
|
list[i].type != current_type)
|
|
{
|
|
current_type = list[i].type;
|
|
current_artist = sortartist;
|
|
current_album = list[i].Album;
|
|
count++;
|
|
switch (list[i].type) {
|
|
case "local":
|
|
var hidden = (playlist.rolledup[sortartist+list[i].Album]) ? true : false;
|
|
tracklist[count] = new Album(sortartist, list[i].Album, count, hidden);
|
|
break;
|
|
case "stream":
|
|
// Streams are hidden by default - hence we use the opposite logic for the flag
|
|
var hidden = (playlist.rolledup["StReAm"+list[i].Album]) ? false : true;
|
|
tracklist[count] = new Stream(count, list[i].Album, hidden);
|
|
break;
|
|
default:
|
|
tracklist[count] = new Album(sortartist, list[i].Album, count);
|
|
break;
|
|
|
|
}
|
|
}
|
|
tracklist[count].newtrack(list[i]);
|
|
if (list[i].Id == player.status.songid) {
|
|
currentalbum = count;
|
|
currentTrack.Pos = list[i].Pos;
|
|
}
|
|
finaltrack = parseInt(list[i].Pos);
|
|
|
|
}
|
|
|
|
// After all that, which will have taken a finite time - which could be a long time on
|
|
// a slow device or with a large playlist, let's check that no more updates are pending
|
|
// before we put all this stuff into the window. (More might have come in while we were organising this one)
|
|
// This might all seem like a faff, but you do not want stuff you've just removed
|
|
// suddenly re-appearing in front of your eyes and then vanishing again. It looks crap.
|
|
if (request_id != reqid) {
|
|
debug.mark("PLAYLIST","Response from player does match current request ID after processing");
|
|
return 0;
|
|
}
|
|
|
|
$("#sortable").empty();
|
|
for (var i in tracklist) {
|
|
tracklist[i].presentYourself();
|
|
}
|
|
|
|
if (finaltrack > -1) {
|
|
$("#pltracks").html((finaltrack+1).toString() +' '+language.gettext("label_tracks"));
|
|
$("#pltime").html(language.gettext("label_duration")+' : '+formatTimeString(totaltime));
|
|
} else {
|
|
$("#pltracks").html("");
|
|
$("#pltime").html("");
|
|
}
|
|
|
|
// Invisible empty div tacked on the end is where we add our 'Incoming' animation
|
|
$("#sortable").append('<div id="waiter" class="containerbox"></div>');
|
|
layoutProcessor.setPlaylistHeight();
|
|
if (lookforcurrenttrack !== false) {
|
|
playlist.trackHasChanged(lookforcurrenttrack);
|
|
lookforcurrenttrack = false;
|
|
} else {
|
|
playlist.doUpcomingCrap();
|
|
}
|
|
player.controller.postLoadActions();
|
|
playlist.radioManager.repopulate();
|
|
uiHelper.postPlaylistLoad();
|
|
},
|
|
|
|
doUpcomingCrap: function() {
|
|
var upcoming = new Array();
|
|
debug.trace("PLAYLIST","Doing Upcoming Crap",currentalbum);
|
|
if (currentalbum >= 0 && player.status.random == 0) {
|
|
tracklist[currentalbum].getrest(currentTrack.Id, upcoming);
|
|
var i = parseInt(currentalbum)+1;
|
|
while (i < tracklist.length) {
|
|
tracklist[i].getrest(null, upcoming);
|
|
i++;
|
|
}
|
|
debug.trace("PLAYLIST","Upcoming list is",upcoming);
|
|
} else if (tracklist.length > 0) {
|
|
var i = 0;
|
|
while (i < tracklist.length) {
|
|
tracklist[i].getrest(null, upcoming);
|
|
i++;
|
|
}
|
|
}
|
|
layoutProcessor.playlistupdate(upcoming);
|
|
},
|
|
|
|
clear: function() {
|
|
debug.log("PLAYLIST","Stopping Radio Manager");
|
|
playlist.radioManager.stop(player.controller.clearPlaylist);
|
|
},
|
|
|
|
handleClick: function(event) {
|
|
event.stopImmediatePropagation();
|
|
var clickedElement = $(this);
|
|
if (clickedElement.hasClass("playid")) {
|
|
player.controller.playId(clickedElement.attr("romprid"));
|
|
} else if (clickedElement.hasClass("clickremovetrack")) {
|
|
playlist.delete(clickedElement.attr("romprid"));
|
|
} else if (clickedElement.hasClass("clickremovealbum")) {
|
|
playlist.deleteGroup(clickedElement.attr("name"));
|
|
} else if (clickedElement.hasClass("clickaddwholealbum")) {
|
|
playlist.addAlbumToCollection(clickedElement.attr("name"));
|
|
} else if (clickedElement.hasClass("clickrollup")) {
|
|
playlist.hideItem(clickedElement.attr("romprname"));
|
|
} else if (clickedElement.hasClass("clickaddfave")) {
|
|
playlist.addFavourite(clickedElement.attr("name"));
|
|
} else if (clickedElement.hasClass("playlistup")) {
|
|
playlist.moveTrackUp(clickedElement.findPlParent(), event);
|
|
} else if (clickedElement.hasClass("playlistdown")) {
|
|
playlist.moveTrackDown(clickedElement.findPlParent(), event);
|
|
} else if (clickedElement.hasClass('rearrange_playlist')) {
|
|
clickedElement.findPlParent().addBunnyEars();
|
|
}
|
|
},
|
|
|
|
draggedToEmpty: function(event, ui) {
|
|
debug.log("PLAYLIST","Something was dropped on the empty playlist area",event,ui);
|
|
playlist.addItems($('.selected').filter(removeOpenItems), parseInt(finaltrack)+1);
|
|
doSomethingUseful('waiter', language.gettext('label_incoming'));
|
|
},
|
|
|
|
dragstopped: function(event, ui) {
|
|
debug.trace("PLAYLIST","Drag Stopped",event,ui);
|
|
if (event) {
|
|
event.stopImmediatePropagation();
|
|
}
|
|
var moveto = (function getMoveTo(i) {
|
|
if (i !== null) {
|
|
debug.trace("PLAYLIST", "Finding Next Item In List",i.next(),i.parent());
|
|
if (i.next().hasClass('track') || i.next().hasClass('booger')) {
|
|
debug.trace("PLAYLIST","Next Item Is Track");
|
|
return parseInt(i.next().attr("name"));
|
|
}
|
|
if (i.next().hasClass('trackgroup') && i.next().is(':hidden')) {
|
|
debug.trace("PLAYLIST","Next Item is hidden trackgroup");
|
|
// Need to account for these - you can't see them so it
|
|
// looks like you're dragging to the next item below it therfore
|
|
// that's how we must behave
|
|
return getMoveTo(i.next());
|
|
}
|
|
if (i.next().hasClass('item') || i.next().hasClass('trackgroup')) {
|
|
debug.trace("PLAYLIST","Next Item Is Item or Trackgroup",
|
|
parseInt(i.next().attr("name")),
|
|
tracklist[parseInt(i.next().attr("name"))].getFirst());
|
|
return tracklist[parseInt(i.next().attr("name"))].getFirst();
|
|
}
|
|
if (i.parent().hasClass('trackgroup')) {
|
|
debug.trace("PLAYLIST","Parent Item is Trackgroup");
|
|
return getMoveTo(i.parent());
|
|
}
|
|
debug.trace("PLAYLIST","Dropped at end?");
|
|
}
|
|
return (parseInt(finaltrack))+1;
|
|
})(ui);
|
|
|
|
if (ui.hasClass("draggable")) {
|
|
// Something dragged from the albums list
|
|
debug.log("PLAYLIST","Something was dropped from the albums list");
|
|
doSomethingUseful(ui.attr('id'), language.gettext('label_incoming'));
|
|
playlist.addItems($('.selected').filter(removeOpenItems), moveto);
|
|
} else if (ui.hasClass('track') || ui.hasClass('item')) {
|
|
// Something dragged within the playlist
|
|
var elementmoved = ui.hasClass('track') ? 'track' : 'item';
|
|
switch (elementmoved) {
|
|
case "track":
|
|
var firstitem = parseInt(ui.attr("name"));
|
|
var numitems = 1;
|
|
break;
|
|
case "item":
|
|
var firstitem = tracklist[parseInt(ui.attr("name"))].getFirst();
|
|
var numitems = tracklist[parseInt(ui.attr("name"))].getSize();
|
|
break;
|
|
}
|
|
// If we move DOWN we have to calculate what the position will be AFTER the items have been moved.
|
|
// It's understandable, but slightly counter-intuitive
|
|
if (firstitem < moveto) {
|
|
moveto = moveto - numitems;
|
|
if (moveto < 0) { moveto = 0; }
|
|
}
|
|
player.controller.move(firstitem, numitems, moveto);
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
addItems: function(elements, moveto) {
|
|
var tracks = new Array();
|
|
$.each(elements, function (index, element) {
|
|
var uri = $(element).attr("name");
|
|
debug.log("PLAYLIST","Adding",uri);
|
|
if (uri) {
|
|
if ($(element).hasClass('searchdir')) {
|
|
var s = addSearchDir($(element));
|
|
// concat doesn't work if the first array is empty????? WTF????
|
|
if (tracks.length == 0) {
|
|
tracks = s;
|
|
} else {
|
|
tracks.concat(s);
|
|
}
|
|
} else if ($(element).hasClass('directory')) {
|
|
tracks.push({
|
|
type: "uri",
|
|
name: decodeURIComponent($(element).children('input').first().attr('value'))
|
|
});
|
|
} else if ($(element).hasClass('clickalbum')) {
|
|
tracks.push({
|
|
type: "item",
|
|
name: uri
|
|
});
|
|
} else if ($(element).hasClass('clickartist')) {
|
|
tracks.push({
|
|
type: "artist",
|
|
name: uri
|
|
});
|
|
} else if ($(element).hasClass('clickcue')) {
|
|
tracks.push({
|
|
type: "cue",
|
|
name: decodeURIComponent(uri)
|
|
});
|
|
} else if ($(element).hasClass('clickstream')) {
|
|
tracks.push({
|
|
type: "stream",
|
|
url: decodeURIComponent(uri),
|
|
image: $(element).attr('streamimg') || 'null',
|
|
station: $(element).attr('streamname') || 'null'
|
|
});
|
|
} else if ($(element).hasClass('clickloadplaylist')) {
|
|
tracks.push({
|
|
type: "playlist",
|
|
name: decodeURIComponent($(element).children('input[name="dirpath"]').val())
|
|
});
|
|
} else if ($(element).hasClass('clickloaduserplaylist')) {
|
|
tracks.push({
|
|
type: 'remoteplaylist',
|
|
name: decodeURIComponent($(element).children('input[name="dirpath"]').val())
|
|
});
|
|
} else if ($(element).hasClass('playlisttrack') && prefs.cdplayermode) {
|
|
tracks.push({
|
|
type: 'playlisttoend',
|
|
playlist: $(element).prev().prev().val(),
|
|
frompos: $(element).prev().val()
|
|
});
|
|
} else if ($(element).hasClass('smartradio')) {
|
|
playlist.radioManager.loadFromUiElement($(element));
|
|
} else if ($(element).hasClass('podcastresume')) {
|
|
var is_already_in_playlist = playlist.findIdByUri(decodeURIComponent(uri));
|
|
if (is_already_in_playlist !== false) {
|
|
player.controller.do_command_list([
|
|
['playid', is_already_in_playlist],
|
|
['seekpodcast', is_already_in_playlist, $(element).next().val()]
|
|
])
|
|
} else {
|
|
tracks.push({
|
|
type: 'resumepodcast',
|
|
resumefrom: $(element).next().val(),
|
|
uri: uri,
|
|
pos: prefs.cdplayermode ? 0 : playlist.getfinaltrack()+1
|
|
});
|
|
moveto = null;
|
|
}
|
|
} else {
|
|
tracks.push({ type: "uri",
|
|
name: decodeURIComponent(uri)});
|
|
}
|
|
}
|
|
});
|
|
if (tracks.length > 0) {
|
|
if (moveto === null) { playlist.waiting(); }
|
|
var playpos = (moveto === null) ? playlist.playFromEnd() : null;
|
|
player.controller.addTracks(tracks, playpos, moveto);
|
|
$('.selected').removeClass('selected');
|
|
}
|
|
},
|
|
|
|
setButtons: function() {
|
|
var c = (player.status.xfade === undefined || player.status.xfade === null || player.status.xfade == 0) ? "off" : "on";
|
|
$("#crossfade").flowToggle(c);
|
|
$.each(['random', 'repeat', 'consume'], function(i,v) {
|
|
c = player.status[v] == 0 ? 'off' : 'on';
|
|
$("#"+v).flowToggle(c);
|
|
});
|
|
if (player.status.replay_gain_mode) {
|
|
$.each(["off","track","album","auto"], function(i,v) {
|
|
if (player.status.replay_gain_mode == v) {
|
|
$("#replaygain_"+v).switchToggle("on");
|
|
} else {
|
|
$("#replaygain_"+v).switchToggle("off");
|
|
}
|
|
});
|
|
}
|
|
if (player.status.xfade !== undefined && player.status.xfade !== null &&
|
|
player.status.xfade > 0 && player.status.xfade != prefs.crossfade_duration) {
|
|
prefs.save({crossfade_duration: player.status.xfade});
|
|
$("#crossfade_duration").val(player.status.xfade);
|
|
}
|
|
},
|
|
|
|
preventControlClicks: function(t) {
|
|
if (t) {
|
|
$('#random').on('click', player.controller.toggleRandom);
|
|
$('#repeat').on('click', player.controller.toggleRepeat);
|
|
$('#consume').on('click', player.controller.toggleConsume);
|
|
$('#crossfade').on('click', player.controller.toggleCrossfade);
|
|
$('#flowcontrols').removeClass('notenabled');
|
|
} else {
|
|
$('#random').off('click').addClass('notenabled');
|
|
$('#repeat').off('click').addClass('notenabled');
|
|
$('#consume').off('click').addClass('notenabled');
|
|
$('#crossfade').off('click').addClass('notenabled');
|
|
$('#flowcontrols').removeClass('notenabled').addClass('notenabled');
|
|
}
|
|
},
|
|
|
|
delete: function(id) {
|
|
$('.track[romprid="'+id.toString()+'"]').remove();
|
|
player.controller.removeId([parseInt(id)]);
|
|
},
|
|
|
|
waiting: function() {
|
|
$("#waiter").empty();
|
|
doSomethingUseful('waiter', language.gettext("label_incoming"));
|
|
},
|
|
|
|
hideItem: function(i) {
|
|
tracklist[i].rollUp();
|
|
},
|
|
|
|
playFromEnd: function() {
|
|
if (player.status.state != "play") {
|
|
debug.trace("PLAYLIST","Playfromend",finaltrack+1);
|
|
return finaltrack+1;
|
|
} else {
|
|
debug.trace("PLAYLIST","Disabling auto-play");
|
|
return null;
|
|
}
|
|
},
|
|
|
|
getfinaltrack: function() {
|
|
return finaltrack;
|
|
},
|
|
|
|
checkPodcastProgress: function() {
|
|
if (player.status.state == 'play' || player.status.state == 'pause') {
|
|
var durationfraction = currentTrack.progress/currentTrack.Time;
|
|
var progresstostore = (durationfraction > 0.05 && durationfraction < 0.98) ? currentTrack.progress : 0;
|
|
if (currentTrack.type == "podcast") {
|
|
podcasts.storePlaybackProgress({uri: currentTrack.file, progress: Math.round(progresstostore)});
|
|
} else if (currentTrack.type == 'audiobook') {
|
|
nowplaying.storePlaybackProgress(Math.round(progresstostore), null);
|
|
}
|
|
}
|
|
},
|
|
|
|
trackHasChanged: function(backendid) {
|
|
if (reqid != last_reqid) {
|
|
debug.log("PLAYLIST","Deferring looking for current track - there is an ongoing update");
|
|
lookforcurrenttrack = backendid;
|
|
return;
|
|
}
|
|
var force = (currentTrack.Id == -1) ? true : false;
|
|
lookforcurrenttrack = false;
|
|
if (backendid != currentTrack.Id) {
|
|
debug.log("PLAYLIST","Looking For Current Track",backendid);
|
|
$("#pscroller .playlistcurrentitem").removeClass('playlistcurrentitem').addClass('playlistitem');
|
|
$('.track[romprid="'+backendid+'"],.booger[romprid="'+backendid+'"]').removeClass('playlistitem').addClass('playlistcurrentitem');
|
|
if (backendid && tracklist.length > 0) {
|
|
for(var i in tracklist) {
|
|
var c = tracklist[i].findcurrent(backendid);
|
|
if (c !== false) {
|
|
currentTrack = c;
|
|
if (currentalbum != i) {
|
|
currentalbum = i;
|
|
$(".playlistcurrenttitle").removeClass('playlistcurrenttitle').addClass('playlisttitle');
|
|
$('.item[name="'+i+'"]').removeClass('playlisttitle').addClass('playlistcurrenttitle');
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
currentTrack = emptyTrack;
|
|
}
|
|
playlist.radioManager.repopulate();
|
|
nowplaying.newTrack(playlist.getCurrentTrack(), force);
|
|
}
|
|
playlist.doUpcomingCrap();
|
|
clearTimeout(pscrolltimer);
|
|
if (pageloading) {
|
|
pscrolltimer = setTimeout(playlist.scrollToCurrentTrack, 3000);
|
|
} else {
|
|
playlist.scrollToCurrentTrack();
|
|
}
|
|
},
|
|
|
|
scrollToCurrentTrack: function() {
|
|
pageloading = false;
|
|
layoutProcessor.scrollPlaylistToCurrentTrack();
|
|
},
|
|
|
|
stopafter: function() {
|
|
if (currentTrack.type == "stream") {
|
|
infobar.error(language.gettext("label_notforradio"));
|
|
} else if (player.status.state == "play") {
|
|
if (player.status.single == 0) {
|
|
player.controller.stopafter();
|
|
} else {
|
|
player.controller.cancelSingle();
|
|
}
|
|
|
|
}
|
|
},
|
|
|
|
previous: function() {
|
|
if (currentalbum >= 0) {
|
|
tracklist[currentalbum].previoustrackcommand();
|
|
}
|
|
},
|
|
|
|
next: function() {
|
|
if (currentalbum >= 0) {
|
|
tracklist[currentalbum].nexttrackcommand();
|
|
}
|
|
},
|
|
|
|
deleteGroup: function(index) {
|
|
tracklist[index].deleteSelf();
|
|
},
|
|
|
|
addAlbumToCollection: function(index) {
|
|
tracklist[index].addToCollection();
|
|
},
|
|
|
|
addFavourite: function(index) {
|
|
debug.log("PLAYLIST","Adding Fave Station, index",index, tracklist[index].Album);
|
|
var data = tracklist[index].getFnackle();
|
|
yourRadioPlugin.addFave(data);
|
|
},
|
|
|
|
getCurrent: function(thing) {
|
|
return currentTrack[thing];
|
|
},
|
|
|
|
getCurrentTrack: function() {
|
|
return cloneObject(currentTrack);
|
|
},
|
|
|
|
setCurrent: function(items) {
|
|
for (var i in items) {
|
|
currentTrack[i] = items[i];
|
|
}
|
|
},
|
|
|
|
getId: function(id) {
|
|
for(var i in tracklist) {
|
|
if (tracklist[i].findById(id) !== false) {
|
|
return tracklist[i].getByIndex(tracklist[i].findById(id));
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
findIdByUri: function(uri) {
|
|
for (var i in tracklist) {
|
|
if (tracklist[i].findByUri(uri) !== false) {
|
|
return tracklist[i].findByUri(uri);
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
|
|
getAlbum: function(i) {
|
|
debug.log("PLAYLIST","Getting Tracks For",i);
|
|
return tracklist[i].getTracks();
|
|
},
|
|
|
|
getCurrentAlbum: function() {
|
|
return currentalbum;
|
|
},
|
|
|
|
getDomainIcon: function(track, def) {
|
|
var s = track.file.split(':');
|
|
var d = s.shift();
|
|
switch (d) {
|
|
case "spotify":
|
|
case "gmusic":
|
|
case "youtube":
|
|
case "internetarchive":
|
|
case "soundcloud":
|
|
case "podcast":
|
|
case "dirble":
|
|
return '<i class="icon-'+d+'-circled playlisticon fixed"></i>';
|
|
break;
|
|
|
|
case 'tunein':
|
|
return '<i class="icon-tunein playlisticon fixed"></i>';
|
|
break;
|
|
}
|
|
if (track.type == 'podcast') {
|
|
return '<i class="icon-podcast-circled playlisticon fixed"></i>';
|
|
}
|
|
return def;
|
|
},
|
|
|
|
// Functions for moving things around by clicking icons
|
|
// To be honest, if I hadn't decided to do trackgroups in the playlist
|
|
// this would be a fuck of a lot easier. But then trackgroups simplify other things, so....
|
|
|
|
moveTrackUp: function(element, event) {
|
|
clearTimeout(popmovetimer);
|
|
popmoveelement = element;
|
|
var startoffset = uiHelper.getElementPlaylistOffset(element);
|
|
var tracks = null;
|
|
if (element.hasClass('item')) {
|
|
tracks = element.next();
|
|
}
|
|
var p = element.findPreviousPlaylistElement();
|
|
if (p.length > 0) {
|
|
element.detach().insertBefore(p);
|
|
}
|
|
if (tracks !== null) {
|
|
tracks.detach().insertAfter(element);
|
|
}
|
|
var offsetnow = uiHelper.getElementPlaylistOffset(element);
|
|
var scrollnow = $('#pscroller').scrollTop();
|
|
$('#pscroller').scrollTop(scrollnow+offsetnow-startoffset);
|
|
popmovetimer = setTimeout(playlist.doPopMove, popmovetimeout);
|
|
},
|
|
|
|
moveTrackDown: function(element, event) {
|
|
clearTimeout(popmovetimer);
|
|
popmoveelement = element;
|
|
var startoffset = uiHelper.getElementPlaylistOffset(element);
|
|
var tracks = null;
|
|
if (element.hasClass('item')) {
|
|
tracks = element.next();
|
|
}
|
|
var n = element.findNextPlaylistElement();
|
|
if (n.length > 0) {
|
|
element.detach().insertAfter(n);
|
|
}
|
|
if (tracks !== null) {
|
|
tracks.detach().insertAfter(element);
|
|
}
|
|
var offsetnow = uiHelper.getElementPlaylistOffset(element);
|
|
var scrollnow = $('#pscroller').scrollTop();
|
|
$('#pscroller').scrollTop(scrollnow+offsetnow-startoffset);
|
|
popmovetimer = setTimeout(playlist.doPopMove, popmovetimeout);
|
|
},
|
|
|
|
doPopMove: function() {
|
|
if (popmoveelement !== null) {
|
|
if (popmoveelement.hasClass('item')) {
|
|
popmoveelement.next().remove();
|
|
}
|
|
playlist.dragstopped(null, popmoveelement);
|
|
popmoveelement = null;
|
|
}
|
|
},
|
|
|
|
getCurrentTrackElement: function() {
|
|
var scrollto = $('#sortable .playlistcurrentitem');
|
|
if (!scrollto.is(':visible')) {
|
|
scrollto = scrollto.parent().prev();
|
|
}
|
|
return scrollto;
|
|
}
|
|
|
|
}
|
|
|
|
}();
|
|
|
|
function Album(artist, album, index, rolledup) {
|
|
|
|
var self = this;
|
|
var tracks = [];
|
|
this.artist = artist;
|
|
this.album = album;
|
|
this.index = index;
|
|
|
|
this.newtrack = function (track) {
|
|
tracks.push(track);
|
|
}
|
|
|
|
this.presentYourself = function() {
|
|
var holder = $('<div>', { name: self.index, romprid: tracks[0].Id, class: 'item fullwidth sortable playlistalbum playlisttitle'}).appendTo('#sortable');
|
|
if (self.index == playlist.getCurrentAlbum()) {
|
|
holder.removeClass('playlisttitle').addClass('playlistcurrenttitle');
|
|
}
|
|
|
|
var inner = $('<div>', {class: 'containerbox'}).appendTo(holder);
|
|
var albumDetails = $('<div>', {name: self.index, romprid: tracks[0].Id, class: 'expand clickplaylist playid containerbox'}).appendTo(inner);
|
|
|
|
if (prefs.use_albumart_in_playlist) {
|
|
self.image = $('<img>', {class: 'smallcover fixed', name: tracks[0].ImgKey });
|
|
self.image.on('error', self.getart);
|
|
var imgholder = $('<div>', { class: 'smallcover fixed clickplaylist clickicon clickrollup', romprname: self.index}).appendTo(albumDetails);
|
|
if (tracks[0].images.small) {
|
|
self.image.attr('src', tracks[0].images.small).appendTo(imgholder);
|
|
} else {
|
|
if (tracks[0].Searched == 0) {
|
|
self.image.addClass('notexist').appendTo(imgholder);
|
|
self.getart();
|
|
} else {
|
|
self.image.addClass('notfound').appendTo(imgholder);
|
|
}
|
|
}
|
|
}
|
|
|
|
var title = $('<div>', {class: 'containerbox vertical expand'}).appendTo(albumDetails);
|
|
title.append('<div class="bumpad">'+self.artist+'</div><div class="bumpad">'+self.album+'</div>');
|
|
|
|
var controls = $('<div>', {class: 'containerbox vertical fixed'}).appendTo(inner)
|
|
controls.append('<div class="expand clickplaylist clickicon clickremovealbum" name="'+self.index+'"><i class="icon-cancel-circled playlisticonr tooltip" title="'+language.gettext('label_removefromplaylist')+'"></i></div>');
|
|
if (tracks[0].metadata.album.uri && tracks[0].metadata.album.uri.substring(0,7) == "spotify") {
|
|
controls.append('<div class="fixed clickplaylist clickicon clickaddwholealbum" name="'+self.index+'"><i class="icon-music playlisticonr tooltip" title="'+language.gettext('label_addtocollection')+'"></i></div>');
|
|
}
|
|
|
|
var trackgroup = $('<div>', {class: 'trackgroup', name: self.index }).appendTo('#sortable');
|
|
if (rolledup) {
|
|
trackgroup.addClass('invisible');
|
|
}
|
|
for (var trackpointer in tracks) {
|
|
var trackdiv = $('<div>', {name: tracks[trackpointer].Pos, romprid: tracks[trackpointer].Id, class: 'track sortable fullwidth playlistitem menuitem'}).appendTo(trackgroup);
|
|
if (tracks[trackpointer].Id == player.status.songid) {
|
|
trackdiv.removeClass('playlistitem').addClass('playlistcurrentitem');
|
|
}
|
|
|
|
var trackOuter = $('<div>', {class: 'containerbox dropdown-container'}).appendTo(trackdiv);
|
|
var trackDetails = $('<div>', {class: 'expand playid clickplaylist containerbox dropdown-container', romprid: tracks[trackpointer].Id}).appendTo(trackOuter);
|
|
|
|
if (tracks[trackpointer].Track) {
|
|
var trackNodiv = $('<div>', {class: 'tracknumber fixed'}).appendTo(trackDetails);
|
|
if (tracks.length > 99 || tracks[trackpointer].Track > 99) {
|
|
trackNodiv.css('width', '3em');
|
|
}
|
|
trackNodiv.html(format_tracknum(tracks[trackpointer].Track));
|
|
}
|
|
|
|
trackDetails.append(playlist.getDomainIcon(tracks[trackpointer], ''));
|
|
|
|
var trackinfo = $('<div>', {class: 'containerbox vertical expand'}).appendTo(trackDetails);
|
|
trackinfo.append('<div class="line">'+tracks[trackpointer].Title+'</div>');
|
|
if ((tracks[trackpointer].albumartist != "" && tracks[trackpointer].albumartist != tracks[trackpointer].trackartist)) {
|
|
trackinfo.append('<div class="line playlistrow2">'+tracks[trackpointer].trackartist+'</div>');
|
|
}
|
|
if (tracks[trackpointer].metadata.track.usermeta) {
|
|
if (tracks[trackpointer].metadata.track.usermeta.Rating > 0) {
|
|
trackinfo.append('<div class="fixed playlistrow2 trackrating"><i class="icon-'+tracks[trackpointer].metadata.track.usermeta.Rating+'-stars rating-icon-small"></i></div>');
|
|
}
|
|
var t = tracks[trackpointer].metadata.track.usermeta.Tags.join(', ');
|
|
if (t != '') {
|
|
trackinfo.append('<div class="fixed playlistrow2 tracktags"><i class="icon-tags playlisticon"></i>'+t+'</div>');
|
|
}
|
|
}
|
|
|
|
trackDetails.append('<div class="tracktime tiny fixed">'+formatTimeString(tracks[trackpointer].Time)+'</div>');
|
|
trackOuter.append('<i class="icon-cancel-circled playlisticonr fixed clickplaylist clickicon clickremovetrack tooltip" title="'+language.gettext('label_removefromplaylist')+'" romprid="'+tracks[trackpointer].Id+'"></i>');
|
|
|
|
}
|
|
}
|
|
|
|
this.getart = function() {
|
|
coverscraper.GetNewAlbumArt({
|
|
artist: tracks[0].albumartist,
|
|
album: tracks[0].Album,
|
|
mbid: tracks[0].metadata.album.musicbrainz_id,
|
|
albumpath: tracks[0].folder,
|
|
albumuri: tracks[0].metadata.album.uri,
|
|
imgkey: tracks[0].ImgKey,
|
|
type: tracks[0].type,
|
|
cb: self.updateImages
|
|
});
|
|
}
|
|
|
|
this.getFnackle = function() {
|
|
return { album: tracks[0].Album,
|
|
image: tracks[0].images.small,
|
|
location: tracks[0].file,
|
|
stream: tracks[0].stream,
|
|
streamid: tracks[0].StreamIndex
|
|
};
|
|
}
|
|
|
|
this.rollUp = function() {
|
|
$('.trackgroup[name="'+self.index+'"]').slideToggle('slow');
|
|
rolledup = !rolledup;
|
|
if (rolledup) {
|
|
playlist.rolledup[this.artist+this.album] = true;
|
|
} else {
|
|
playlist.rolledup[this.artist+this.album] = undefined;
|
|
}
|
|
}
|
|
|
|
this.updateImages = function(data) {
|
|
debug.debug("PLAYLIST","Updating track images with",data);
|
|
for (var trackpointer in tracks) {
|
|
tracks[trackpointer].images = data;
|
|
}
|
|
}
|
|
|
|
this.getFirst = function() {
|
|
return parseInt(tracks[0].Pos);
|
|
}
|
|
|
|
this.getSize = function() {
|
|
return tracks.length;
|
|
}
|
|
|
|
this.isLast = function(id) {
|
|
if (id == tracks[tracks.length - 1].Id) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
this.findcurrent = function(which) {
|
|
for(var i in tracks) {
|
|
if (tracks[i].Id == which) {
|
|
return tracks[i];
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
this.findById = function(which) {
|
|
for(var i in tracks) {
|
|
if (tracks[i].Id == which) {
|
|
return i;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
this.findByUri = function(uri) {
|
|
for(var i in tracks) {
|
|
if (tracks[i].file == uri) {
|
|
return tracks[i].Id;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
this.getByIndex = function(i) {
|
|
return tracks[i];
|
|
}
|
|
|
|
this.getTracks = function() {
|
|
return tracks;
|
|
}
|
|
|
|
this.getrest = function(id, arr) {
|
|
var i = 0;
|
|
if (id !== null) {
|
|
while (i < tracks.length && tracks[i].Id != id) {
|
|
i++;
|
|
}
|
|
i++;
|
|
}
|
|
while (i < tracks.length) {
|
|
arr.push(tracks[i]);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
this.deleteSelf = function() {
|
|
var todelete = [];
|
|
$('.item[name="'+self.index+'"]').next().remove();
|
|
$('.item[name="'+self.index+'"]').remove();
|
|
for(var i in tracks) {
|
|
todelete.push(tracks[i].Id);
|
|
}
|
|
player.controller.removeId(todelete)
|
|
}
|
|
|
|
this.previoustrackcommand = function() {
|
|
player.controller.previous();
|
|
}
|
|
|
|
this.nexttrackcommand = function() {
|
|
player.controller.next();
|
|
}
|
|
|
|
this.addToCollection = function() {
|
|
debug.log("PLAYLIST","Adding album to collection");
|
|
if (tracks[0].metadata.album.uri && tracks[0].metadata.album.uri.substring(0,14) == "spotify:album:") {
|
|
spotify.album.getInfo(tracks[0].metadata.album.uri.substring(14,tracks[0].metadata.album.uri.length),
|
|
function(data) {
|
|
metaHandlers.fromSpotifyData.addAlbumTracksToCollection(data, tracks[0].albumartist)
|
|
},
|
|
function(data) {
|
|
debug.fail("ADD ALBUM","Failed to add album",data);
|
|
infobar.error(language.gettext('label_general_error'));
|
|
},
|
|
false);
|
|
} else {
|
|
debug.error("PLAYLIST","Trying to add non-spotify album to the collection!");
|
|
}
|
|
}
|
|
|
|
function format_tracknum(tracknum) {
|
|
var r = /^(\d+)/;
|
|
var result = r.exec(tracknum) || "";
|
|
return result[1] || "";
|
|
}
|
|
|
|
}
|
|
|
|
function Stream(index, album, rolledup) {
|
|
var self = this;
|
|
var tracks = [];
|
|
this.index = index;
|
|
var rolledup = rolledup;
|
|
this.album = album;
|
|
|
|
this.newtrack = function (track) {
|
|
tracks.push(track);
|
|
}
|
|
|
|
this.presentYourself = function() {
|
|
var header = $('<div>', {name: self.index, romprid: tracks[0].Id, class: 'item sortable fullwidth playlistalbum playlisttitle'}).appendTo('#sortable');
|
|
if (self.index == playlist.getCurrentAlbum()) {
|
|
header.removeClass('playlisttitle').addClass('playlistcurrenttitle');
|
|
}
|
|
|
|
var inner = $('<div>', {class: 'containerbox'}).appendTo(header);
|
|
var albumDetails = $('<div>', {name: self.index, romprid: tracks[0].Id, class: 'expand playid clickplaylist containerbox'}).appendTo(inner);
|
|
|
|
if (prefs.use_albumart_in_playlist) {
|
|
self.image = $('<img>', {class: 'smallcover fixed', name: tracks[0].ImgKey });
|
|
self.image.on('error', self.getart);
|
|
var imgholder = $('<div>', { class: 'smallcover fixed clickplaylist clickicon clickrollup', romprname: self.index}).appendTo(albumDetails);
|
|
if (tracks[0].images.small) {
|
|
self.image.attr('src', tracks[0].images.small).appendTo(imgholder);
|
|
} else {
|
|
if (tracks[0].Searched == 0) {
|
|
self.image.addClass('notexist stream').appendTo(imgholder);
|
|
if (tracks[0].album != rompr_unknown_stream) {
|
|
self.getart();
|
|
}
|
|
} else {
|
|
self.image.addClass('notfound').appendTo(imgholder);
|
|
}
|
|
}
|
|
}
|
|
|
|
var title = $('<div>', {class: 'containerbox vertical expand'}).appendTo(albumDetails);
|
|
title.append('<div class="bumpad">'+tracks[0].Album+'</div>');
|
|
var buttons = $('<div>', {class: 'containerbox vertical fixed'}).appendTo(inner);
|
|
buttons.append('<div class="clickplaylist clickicon clickremovealbum expand" name="'+self.index+'"><i class="icon-cancel-circled playlisticonr tooltip" title="'+language.gettext('label_removefromplaylist')+'"></i></div>');
|
|
buttons.append('<div class="clickplaylist clickicon clickaddfave fixed" name="'+self.index+'"><i class="icon-radio-tower playlisticonr tooltip" title="'+language.gettext('label_addtoradio')+'"></i></div>');
|
|
|
|
var trackgroup = $('<div>', {class: 'trackgroup', name: self.index }).appendTo('#sortable');
|
|
if (self.visible()) {
|
|
trackgroup.addClass('invisible');
|
|
}
|
|
for (var trackpointer in tracks) {
|
|
var trackdiv = $('<div>', {name: tracks[trackpointer].Pos, romprid: tracks[trackpointer].Id, class: 'booger playid clickplaylist containerbox playlistitem menuitem'}).appendTo(trackgroup);
|
|
trackdiv.append(playlist.getDomainIcon(tracks[trackpointer], '<i class="icon-radio-tower playlisticon fixed"></i>'));
|
|
var h = $('<div>', {class: 'containerbox vertical expand' }).appendTo(trackdiv);
|
|
if (tracks[trackpointer].stream && tracks[trackpointer].stream != 'null') {
|
|
h.append('<div class="playlistrow2 line">'+tracks[trackpointer].stream+'</div>');
|
|
}
|
|
h.append('<div class="tiny line">'+tracks[trackpointer].file+'</div>');
|
|
}
|
|
}
|
|
|
|
this.getFnackle = function() {
|
|
return { album: tracks[0].Album,
|
|
image: tracks[0].images.small,
|
|
location: tracks[0].file,
|
|
stream: tracks[0].stream,
|
|
streamid: tracks[0].StreamIndex
|
|
};
|
|
}
|
|
|
|
this.findById = function(which) {
|
|
for(var i in tracks) {
|
|
if (tracks[i].Id == which) {
|
|
return i;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
this.getByIndex = function(i) {
|
|
return tracks[i];
|
|
}
|
|
|
|
this.getTracks = function() {
|
|
return tracks;
|
|
}
|
|
|
|
this.rollUp = function() {
|
|
$('.trackgroup[name="'+self.index+'"]').slideToggle('slow');
|
|
if (self.visible()) {
|
|
playlist.rolledup["StReAm"+this.album] = true;
|
|
} else {
|
|
playlist.rolledup["StReAm"+this.album] = undefined;
|
|
}
|
|
rolledup = !rolledup;
|
|
}
|
|
|
|
this.getFirst = function() {
|
|
return parseInt(tracks[0].Pos);
|
|
}
|
|
|
|
this.getSize = function() {
|
|
return tracks.length;
|
|
}
|
|
|
|
this.isLast = function(id) {
|
|
if (id == tracks[tracks.length - 1].Id) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
this.findcurrent = function(which) {
|
|
for(var i in tracks) {
|
|
if (tracks[i].Id == which) {
|
|
return tracks[i];
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
this.findByUri = function(uri) {
|
|
for(var i in tracks) {
|
|
if (tracks[i].file == uri) {
|
|
return tracks[i].Id;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
this.getrest = function(id, arr) {
|
|
|
|
}
|
|
|
|
this.getart = function() {
|
|
coverscraper.GetNewAlbumArt({
|
|
artist: 'STREAM',
|
|
type: 'stream',
|
|
album: tracks[0].Album,
|
|
imgkey: tracks[0].ImgKey,
|
|
cb: self.updateImages
|
|
});
|
|
}
|
|
|
|
this.updateImages = function(data) {
|
|
debug.trace("PLAYLIST","Updating track images with",data);
|
|
for (var trackpointer in tracks) {
|
|
tracks[trackpointer].images = data;
|
|
}
|
|
}
|
|
|
|
this.deleteSelf = function() {
|
|
var todelete = [];
|
|
for(var i in tracks) {
|
|
$('.booger[name="'+tracks[i].Pos+'"]').remove();
|
|
todelete.push(tracks[i].Id);
|
|
}
|
|
$('.item[name="'+self.index+'"]').remove();
|
|
player.controller.removeId(todelete)
|
|
}
|
|
|
|
this.previoustrackcommand = function() {
|
|
player.controller.playByPosition(parseInt(tracks[0].Pos)-1);
|
|
}
|
|
|
|
this.nexttrackcommand = function() {
|
|
player.controller.playByPosition(parseInt(tracks[(tracks.length)-1].Pos)+1);
|
|
}
|
|
|
|
this.visible = function() {
|
|
if (self.album == rompr_unknown_stream) {
|
|
return !rolledup;
|
|
} else {
|
|
return rolledup;
|
|
}
|
|
}
|
|
}
|
|
|
|
jQuery.fn.findNextPlaylistElement = function() {
|
|
var next = $(this).next();
|
|
while (next.length > 0 && !next.is(':visible')) {
|
|
next = next.next();
|
|
}
|
|
if (next.length == 0 && $(this).parent().hasClass('trackgroup')) {
|
|
next = $(this).parent().next();
|
|
}
|
|
if (next.hasClass('item')) {
|
|
if (next.next().is(':hidden')) {
|
|
next = next.next();
|
|
} else {
|
|
next = next.next().children().first();
|
|
}
|
|
}
|
|
return next;
|
|
}
|
|
|
|
jQuery.fn.findPreviousPlaylistElement = function() {
|
|
var prev = $(this).prev();
|
|
while (prev.length >0 && !prev.is(':visible')) {
|
|
prev = prev.prev();
|
|
}
|
|
if (prev.length == 0 && $(this).parent().hasClass('trackgroup')) {
|
|
prev = $(this).parent().prev().prev();
|
|
}
|
|
if (prev.hasClass('trackgroup')) {
|
|
if (prev.is(':hidden')) {
|
|
prev = prev.prev();
|
|
} else {
|
|
prev = prev.children().last();
|
|
}
|
|
}
|
|
return prev;
|
|
}
|