Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Make playlist diffing track oriented, don't attempt to sync metadaata…

…. Add UTIL.sortByProperty/Method helper methods. Add a PlaylistTrack.toString. Introduce concept of incremental subscriptions, that only add tracks versus those that just replace the track list wholesale. Updating podcasts/XSPFs versus syncing Last.fm playlists. Make fetchTracks only operate if the Playlist has no tracks loaded yet.
  • Loading branch information...
commit 2908e7d180ea1bd24f7125838a1f3cd08d1fee11 1 parent ae3ea05
@jwheare authored
View
19 src/js/controllers/playlist.controller.js
@@ -484,17 +484,24 @@ Playlist.prototype = {
// Add callback and exception handler to the arguments
args.push(function callback (newPlaylist) {
// compare with saved playlist and update/warn for conflicts?
- var diffs = 0;
- for (var field in playlist.diff(newPlaylist)) {
- diffs++;
- console.info(playlist[field], newPlaylist[field]);
+ var diff = playlist.diffTracks(newPlaylist);
+ var added = [];
+ for (var field in diff) {
+ if (diff[field].change === true) {
+ added.push(diff[field].track);
+ }
}
- if (!diffs) {
- console.info('no updates');
+ if (added.length) {
+ console.log(playlist.toString(), playlist.isIncrementalSubscription());
+ UTIL.sortByMethod(added, 'get_position');
+ $.each(added, function (i, playlist_track) {
+ console.info(playlist_track.toString());
+ });
}
});
args.push(function exceptionHandler (exception) {
// show a warning icon and message?
+ console.warn(exception);
exception.diagnose();
});
IMPORTERS[sub.namespace][sub.method].apply(this, args);
View
6 src/js/importers/lastfm.js
@@ -99,7 +99,8 @@ LastFm.getUserPlaylist = function (data, callback, exceptionHandler) {
subscription: {
namespace: 'LastFm',
method: 'getUserPlaylist',
- arguments: [data]
+ arguments: [data],
+ incremental: false
}
};
var image = $.grep(data.image, function (value, i) {
@@ -175,7 +176,8 @@ LastFm.lovedTracks = function (user, callback, exceptionHandler) {
subscription: {
namespace: 'LastFm',
method: 'lovedTracks',
- arguments: [user]
+ arguments: [user],
+ incremental: false
}
});
// Load tracks
View
3  src/js/importers/url.js
@@ -67,7 +67,8 @@ Url.url = function (source, callback, exceptionHandler) {
subscription: {
namespace: 'Url',
method: 'url',
- arguments: [source]
+ arguments: [source],
+ incremental: true
}
};
if (jspf) {
View
10 src/js/main/playdar.js
@@ -55,15 +55,7 @@ var PLAYDAR = {
var resultsTable = $('<table cellspacing="0"></table>');
var foundPerfect = false;
- response.results.sort(function (a, b) {
- if (a.score > b.score) {
- return -1;
- }
- if (a.score < b.score) {
- return 1;
- }
- return 0;
- });
+ UTIL.sortByProperty(response.results, 'score', true);
$.each(response.results, function (i, result) {
// Register sound
Playdar.player.register_stream(result, {
View
117 src/js/models/playlist.model.js
@@ -85,6 +85,9 @@ Playlist.prototype = {
isSubscription: function () {
return this.type == 'subscription' && this.subscription;
},
+ isIncrementalSubscription: function () {
+ return this.isSubscription() && this.subscription.incremental === true;
+ },
isEditable: function () {
return !this.isAlbum() && !this.isSubscription();
},
@@ -104,25 +107,36 @@ Playlist.prototype = {
* Fetch tracks from Couch
**/
fetchTracks: function () {
- try {
- var response = MODELS.couch.view("playlist/all", {
- "key": this._id
- });
- MODELS.couch_up_handler('fetchTracks', response);
- var row = response.rows[0];
- var value = row.value;
- // Load tracks
- var playlist = this;
- var elements = $.map(value.tracks, function (track_data, i) {
- var playlist_track = playlist.add_track(new MODELS.Track(track_data.track));
- // Build DOM element
- return playlist_track.element.get();
- });
- return elements;
- } catch (result) {
- MODELS.couch_down_handler('fetchTracks', result);
+ if (!this.tracks.length) {
+ try {
+ var response = MODELS.couch.view("playlist/all", {
+ "key": this._id
+ });
+ MODELS.couch_up_handler('fetchTracks', response);
+ var row = response.rows[0];
+ var value = row.value;
+ // Load tracks
+ var playlist = this;
+ var elements = $.map(value.tracks, function (track_data, i) {
+ var playlist_track = playlist.add_track(new MODELS.Track(track_data.track));
+ // Build DOM element
+ return playlist_track.element.get();
+ });
+ return elements;
+ } catch (result) {
+ MODELS.couch_down_handler('fetchTracks', result);
+ }
}
},
+ getTrackHash: function () {
+ this.fetchTracks();
+ var hash = {};
+ var track, key;
+ $.each(this.tracks, function (i, playlist_track) {
+ hash[playlist_track.track.getDiffKey()] = playlist_track;
+ });
+ return hash;
+ },
/**
* Load tracks to the DOM, fetching from Couch if needed
**/
@@ -339,42 +353,47 @@ Playlist.prototype = {
return doc;
},
/**
- * Coarse comparison of data with another playlist
- * Returns an object containing differing fields
+ * Coarse comparison of track data with another playlist
+ * Returns an object containing differing tracks
**/
- diff: function (playlist) {
- // Get the data
- var thisDoc = this.get_doc();
- var playlistDoc = playlist.get_doc();
- // Store anything that differs in an object
- var diff = {};
- var field, i, arrayLen;
- for (field in thisDoc) {
- // Only care about single level arrays, if anything differs add the whole array
- if ($.isArray(thisDoc[field])) {
- arrayLen = thisDoc[field].length;
- if (arrayLen !== playlistDoc[field].length) {
- // Lengths differ
- diff[field] = playlistDoc[field];
- } else {
- // Check if any of the elements differ
- for (i = 0; i < arrayLen; i++) {
- if (JSON.stringify(thisDoc[field][i]) !== JSON.stringify(playlistDoc[field][i])) {
- diff[field] = playlistDoc[field];
- break;
- }
- }
+ diffTracks: function (playlist) {
+ var trackDiffs = {};
+ var anyChanges = false;
+ var thisTracks = this.getTrackHash();
+ var playlistTracks = playlist.getTrackHash();
+ var trackKey;
+ for (trackKey in thisTracks) {
+ var change;
+ if (!playlistTracks[trackKey]) {
+ // Added
+ change = false;
+ } else {
+ // Moved
+ change = thisTracks[trackKey].get_position() - playlistTracks[trackKey].get_position();
+ // Don't include non changers
+ if (change === 0) {
+ continue;
}
- } else if (JSON.stringify(thisDoc[field]) !== JSON.stringify(playlistDoc[field])) {
- diff[field] = playlistDoc[field];
}
+ anyChanges = true;
+ trackDiffs[trackKey] = {
+ change: change,
+ track: thisTracks[trackKey].get_doc()
+ };
+ }
+ for (trackKey in playlistTracks) {
+ if (!thisTracks[trackKey]) {
+ // Removed
+ anyChanges = true;
+ trackDiffs[trackKey] = {
+ change: true,
+ track: playlistTracks[trackKey]
+ };
+ }
+ }
+ if (anyChanges) {
+ return trackDiffs;
}
- // Certain keys will always differ
- delete diff._id;
- delete diff._rev;
- delete diff.date;
-
- return diff;
}
};
/**
View
5 src/js/models/playlisttrack.model.js
@@ -53,9 +53,12 @@ PlaylistTrack.prototype = {
},
get_doc: function () {
var doc = {
- position: this.position,
+ position: this.get_position(),
track: this.track.get_doc()
};
return doc;
+ },
+ toString: function () {
+ return this.get_position() + ': ' + this.track.toString();
}
};
View
9 src/js/models/track.model.js
@@ -53,9 +53,14 @@ Track.prototype = {
duration: this.duration,
size: this.size,
mimetype: this.mimetype,
- bitrate: this.bitrate,
- type: this.type
+ bitrate: this.bitrate
};
return doc;
+ },
+ getDiffKey: function () {
+ return this.url || (this.artist + this.album + this.name);
+ },
+ diff: function (track) {
+ return this.getDiffKey() != track.getDiffKey();
}
};
View
20 src/js/util.js
@@ -53,5 +53,25 @@ var UTIL = {
var text = match.replace(/^http:\/\//, '').replace(/\/$/, '');
return '<a href="' + url + '">' + text + '</a>';
});
+ },
+
+ sortBy: function (list, property, callable, descending) {
+ list.sort(function (a, b) {
+ var aSort = callable ? a[property]() : a[property];
+ var bSort = callable ? b[property]() : b[property];
+ if (aSort > bSort) {
+ return descending ? -1 : 1;
+ }
+ if (aSort < bSort) {
+ return descending ? 1 : -1;
+ }
+ return 0;
+ });
+ },
+ sortByProperty: function (list, property, descending) {
+ UTIL.sortBy(list, property, false, descending);
+ },
+ sortByMethod: function (list, method, descending) {
+ UTIL.sortBy(list, method, true, descending);
}
};
Please sign in to comment.
Something went wrong with that request. Please try again.