', {
class: 'toggledown invisible expand',
id: id
});
},
textEntry: function(icon, label, id) {
var html = '';
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('
');
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 '
';
break;
case 'tunein':
return '
';
break;
}
if (track.type == 'podcast') {
return '
';
}
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 = $('
', { 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 = $('
', {class: 'containerbox'}).appendTo(holder);
var albumDetails = $('
', {name: self.index, romprid: tracks[0].Id, class: 'expand clickplaylist playid containerbox'}).appendTo(inner);
if (prefs.use_albumart_in_playlist) {
self.image = $('
', {class: 'smallcover fixed', name: tracks[0].ImgKey });
self.image.on('error', self.getart);
var imgholder = $('
', { 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 = $('
', {class: 'containerbox vertical expand'}).appendTo(albumDetails);
title.append('
'+self.artist+'
'+self.album+'
');
var controls = $('
', {class: 'containerbox vertical fixed'}).appendTo(inner)
controls.append('
');
if (tracks[0].metadata.album.uri && tracks[0].metadata.album.uri.substring(0,7) == "spotify") {
controls.append('
');
}
var trackgroup = $('
', {class: 'trackgroup', name: self.index }).appendTo('#sortable');
if (rolledup) {
trackgroup.addClass('invisible');
}
for (var trackpointer in tracks) {
var trackdiv = $('
', {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 = $('
', {class: 'containerbox dropdown-container'}).appendTo(trackdiv);
var trackDetails = $('
', {class: 'expand playid clickplaylist containerbox dropdown-container', romprid: tracks[trackpointer].Id}).appendTo(trackOuter);
if (tracks[trackpointer].Track) {
var trackNodiv = $('
', {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 = $('
', {class: 'containerbox vertical expand'}).appendTo(trackDetails);
trackinfo.append('
'+tracks[trackpointer].Title+'
');
if ((tracks[trackpointer].albumartist != "" && tracks[trackpointer].albumartist != tracks[trackpointer].trackartist)) {
trackinfo.append('
'+tracks[trackpointer].trackartist+'
');
}
if (tracks[trackpointer].metadata.track.usermeta) {
if (tracks[trackpointer].metadata.track.usermeta.Rating > 0) {
trackinfo.append('
');
}
var t = tracks[trackpointer].metadata.track.usermeta.Tags.join(', ');
if (t != '') {
trackinfo.append('
'+t+'
');
}
}
trackDetails.append('
'+formatTimeString(tracks[trackpointer].Time)+'
');
trackOuter.append('
');
}
}
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 = $('
', {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 = $('
', {class: 'containerbox'}).appendTo(header);
var albumDetails = $('
', {name: self.index, romprid: tracks[0].Id, class: 'expand playid clickplaylist containerbox'}).appendTo(inner);
if (prefs.use_albumart_in_playlist) {
self.image = $('
', {class: 'smallcover fixed', name: tracks[0].ImgKey });
self.image.on('error', self.getart);
var imgholder = $('
', { 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 = $('
', {class: 'containerbox vertical expand'}).appendTo(albumDetails);
title.append('
'+tracks[0].Album+'
');
var buttons = $('
', {class: 'containerbox vertical fixed'}).appendTo(inner);
buttons.append('
');
buttons.append('
');
var trackgroup = $('
', {class: 'trackgroup', name: self.index }).appendTo('#sortable');
if (self.visible()) {
trackgroup.addClass('invisible');
}
for (var trackpointer in tracks) {
var trackdiv = $('
', {name: tracks[trackpointer].Pos, romprid: tracks[trackpointer].Id, class: 'booger playid clickplaylist containerbox playlistitem menuitem'}).appendTo(trackgroup);
trackdiv.append(playlist.getDomainIcon(tracks[trackpointer], '
'));
var h = $('
', {class: 'containerbox vertical expand' }).appendTo(trackdiv);
if (tracks[trackpointer].stream && tracks[trackpointer].stream != 'null') {
h.append('
'+tracks[trackpointer].stream+'
');
}
h.append('
'+tracks[trackpointer].file+'
');
}
}
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;
}