Created
April 23, 2013 20:56
-
-
Save gquintard/5447321 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 14345b4af1568511e532708cb29eddc0da762905 Mon Sep 17 00:00:00 2001 | |
From: Guillaume Quintard <guillaume.quintard@gmail.com> | |
Date: Tue, 23 Apr 2013 00:55:18 +0200 | |
Subject: [PATCH] Use models as playlists | |
this is a proof-of-concept, using the listStore of the Album view as a | |
playlist if one item is clicked. | |
Various enhacements can be made (embedding model/iter in one object, | |
warning that the song as been paused...) and the theory remains open to | |
discussion | |
--- | |
src/player.js | 64 +++++++++++++++------------ | |
src/view.js | 2 - | |
src/widgets.js | 135 ++++++++++++++++++++++++++++----------------------------- | |
3 files changed, 104 insertions(+), 97 deletions(-) | |
diff --git a/src/player.js b/src/player.js | |
index 28c1d6c..42abd61 100644 | |
--- a/src/player.js | |
+++ b/src/player.js | |
@@ -79,19 +79,18 @@ const Player = new Lang.Class({ | |
_init: function() { | |
Signals.addSignalMethods(Player.prototype); | |
- this.playlist = []; | |
- this.currentTrack = 0; | |
+ this.playlist = null; | |
+ this.playlist_type = null; | |
+ this.playlist_id = null; | |
+ this.playlist_field = null; | |
+ this.currentTrack = null; | |
this.cache = AlbumArtCache.AlbumArtCache.getDefault(); | |
Gst.init(null, 0); | |
this.player = Gst.ElementFactory.make("playbin", "player"); | |
this.player.connect("about-to-finish", Lang.bind(this, | |
function() { | |
- let newCurrentTrack = parseInt(this.currentTrack) + 1; | |
- if (newCurrentTrack < this.playlist.length) { | |
- this.currentTrack = newCurrentTrack; | |
- this.load(this.playlist[this.currentTrack]); | |
- } | |
+ this.playNext(); | |
return true; | |
})); | |
this.bus = this.player.get_bus(); | |
@@ -153,9 +152,9 @@ const Player = new Lang.Class({ | |
if(this.player.get_state(1)[1] != Gst.State.PAUSED) { | |
this.stop(); | |
} | |
- this.load(this.playlist[this.currentTrack]); | |
+ this.load( this.playlist.get_value( this.currentTrack, this.playlist_field)); | |
this.player.set_state(Gst.State.PLAYING); | |
- this.timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 10, Lang.bind(this, this._updatePositionCallback)); | |
+ this.timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, Lang.bind(this, this._updatePositionCallback)); | |
}, | |
pause: function () { | |
@@ -171,30 +170,41 @@ const Player = new Lang.Class({ | |
} | |
}, | |
- appendToPlaylist: function (track) { | |
- this.playlist.push(track); | |
- }, | |
- | |
playNext: function () { | |
- let newCurrentTrack = parseInt(this.currentTrack) + 1; | |
- if (newCurrentTrack < this.playlist.length) { | |
- this.currentTrack = newCurrentTrack; | |
- this.stop(); | |
- this.play(); | |
- } | |
+ if (!this.playlist || !this.currentTrack || !this.playlist.iter_next(this.currentTrack)){ | |
+ this.stop(); | |
+ this.currentTrack=null; | |
+ return; | |
+ } | |
+ this.emit("playlist-item-changed", this.playlist, this.currentTrack); | |
+ this.stop(); | |
+ this.play(); | |
}, | |
playPrevious: function () { | |
- let newCurrentTrack = parseInt(this.currentTrack) - 1; | |
- if (newCurrentTrack >= 0) { | |
- this.currentTrack = newCurrentTrack; | |
- this.stop(); | |
- this.play(); | |
- } | |
+ if (!this.playlist || !this.currentTrack || !this.playlist.iter_previous(this.currentTrack)){ | |
+ this.stop(); | |
+ this.currentTrack=null; | |
+ return;} | |
+ this.emit("playlist-item-changed", this.playlist, this.currentTrack); | |
+ this.stop(); | |
+ this.play(); | |
+ }, | |
+ | |
+ setPlaylist: function (type, id, model, iter, field) { | |
+ this.playlist = model; | |
+ this.playlist_type = type; | |
+ this.playlist_id = id; | |
+ this.currentTrack = iter; | |
+ this.playlist_field = field; | |
+ this.emit("playlist-item-changed", this.playlist, this.currentTrack); | |
}, | |
- setPlaylist: function (playlist) { | |
- this.playlist = playlist; | |
+ runningPlaylist: function (type, id, force){ | |
+ if (type == this.playlist_type && id == this.playlist_id) | |
+ return this.playlist; | |
+ else | |
+ return null; | |
}, | |
setCurrentTrack: function (track) { | |
diff --git a/src/view.js b/src/view.js | |
index 23ac10d..368c420 100644 | |
--- a/src/view.js | |
+++ b/src/view.js | |
@@ -337,7 +337,6 @@ const Songs = new Lang.Class({ | |
_addItem: function(source, param, item) { | |
this.parent(source, param, item); | |
- this.player.appendToPlaylist(item); | |
}, | |
_addListRenderers: function() { | |
@@ -377,7 +376,6 @@ const Songs = new Lang.Class({ | |
}, | |
populate: function() { | |
- this.player.playlist = []; | |
if (grilo.tracker != null) | |
grilo.populateSongs (this._offset, Lang.bind(this, this._addItem, null)); | |
}, | |
diff --git a/src/widgets.js b/src/widgets.js | |
index aa20565..62a76da 100644 | |
--- a/src/widgets.js | |
+++ b/src/widgets.js | |
@@ -40,17 +40,9 @@ const AlbumWidget = new Lang.Class({ | |
_init: function (player) { | |
this.player = player; | |
this.hbox = new Gtk.HBox (); | |
+ this.iterToClean = null; | |
this.scrolledWindow = new Gtk.ScrolledWindow(); | |
- this.model = Gtk.ListStore.new([ | |
- GObject.TYPE_STRING, /*title*/ | |
- GObject.TYPE_STRING, | |
- GObject.TYPE_STRING, | |
- GObject.TYPE_BOOLEAN,/*icon shown*/ | |
- GdkPixbuf.Pixbuf, /*icon*/ | |
- GObject.TYPE_OBJECT, /*song object*/ | |
- GObject.TYPE_BOOLEAN | |
- ]); | |
this.ui = new Gtk.Builder(); | |
this.ui.add_from_resource('/org/gnome/music/AlbumWidget.ui'); | |
this.model = this.ui.get_object("AlbumWidget_model"); | |
@@ -59,12 +51,16 @@ const AlbumWidget = new Lang.Class({ | |
shadow_type: Gtk.ShadowType.NONE | |
}); | |
this.view.set_view_type(Gd.MainViewType.LIST); | |
- this.view.set_model(this.model); | |
+ this.album=null; | |
this.view.connect('item-activated', Lang.bind(this, | |
function(widget, id, path) { | |
- let iter = this.model.get_iter (path)[1]; | |
- let item = this.model.get_value(iter, 5); | |
- this.player.setCurrentTrack(item); | |
+ if (this.iterToClean){ | |
+ let item = this.model.get_value(this.iterToClean, 5); | |
+ this.model.set_value(this.iterToClean, 0, item.get_title()); | |
+ // Hide now playing icon | |
+ this.model.set_value(this.iterToClean, 3, false); | |
+ } | |
+ this.player.setPlaylist("Album", this.album, this.model, this.model.get_iter(path)[1], 5); | |
this.player.play(); | |
}) | |
); | |
@@ -127,36 +123,48 @@ const AlbumWidget = new Lang.Class({ | |
durationRenderer.text = this.player.seconds_to_string(duration); | |
})); | |
}, | |
- | |
update: function (artist, album, item) { | |
- var pixbuf = albumArtCache.lookup (256, artist, item.get_string(Grl.METADATA_KEY_ALBUM)); | |
let released_date = item.get_publication_date(); | |
if (released_date != null) { | |
this.ui.get_object("released_label_info").set_text( | |
released_date.get_year().toString()); | |
} | |
let duration = 0; | |
- this.model.clear() | |
- var tracks = []; | |
- grilo.getAlbumSongs(item.get_id(), Lang.bind(this, function (source, prefs, track) { | |
- if (track != null) { | |
- tracks.push(track); | |
- duration = duration + track.get_duration(); | |
- let iter = this.model.append(); | |
- let path = "/usr/share/icons/gnome/scalable/actions/media-playback-start-symbolic.svg"; | |
- let pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, -1, 16, true); | |
- this.model.set(iter, | |
- [0, 1, 2, 3, 4, 5], | |
- [ track.get_title(), "", "", false, pixbuf, track ]); | |
- this.ui.get_object("running_length_label_info").set_text( | |
- (parseInt(duration/60) + 1) + " min"); | |
- } | |
- })); | |
- | |
- this.player.setPlaylist(tracks); | |
- this.player.setCurrentTrack(tracks[0]); | |
- | |
- pixbuf = albumArtCache.lookup (256, artist, item.get_string(Grl.METADATA_KEY_ALBUM)); | |
+ this.album = album; | |
+ // if the active queue has been set by this album, | |
+ // use it as model, otherwise build the liststore | |
+ let cachedPlaylist = this.player.runningPlaylist("Album", album); | |
+ if (cachedPlaylist){ | |
+ this.model = cachedPlaylist; | |
+ } else { | |
+ this.model = Gtk.ListStore.new([ | |
+ GObject.TYPE_STRING, /*title*/ | |
+ GObject.TYPE_STRING, | |
+ GObject.TYPE_STRING, | |
+ GObject.TYPE_BOOLEAN,/*icon shown*/ | |
+ GdkPixbuf.Pixbuf, /*icon*/ | |
+ GObject.TYPE_OBJECT, /*song object*/ | |
+ GObject.TYPE_BOOLEAN | |
+ ]); | |
+ this.iterToClean = null; | |
+ var tracks = []; | |
+ grilo.getAlbumSongs(item.get_id(), Lang.bind(this, function (source, prefs, track) { | |
+ if (track != null) { | |
+ tracks.push(track); | |
+ duration = duration + track.get_duration(); | |
+ let iter = this.model.append(); | |
+ let path = "/usr/share/icons/gnome/scalable/actions/media-playback-start-symbolic.svg"; | |
+ let pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, -1, 16, true); | |
+ this.model.set(iter, | |
+ [0, 1, 2, 3, 4, 5], | |
+ [ track.get_title(), "", "", false, pixbuf, track ]); | |
+ this.ui.get_object("running_length_label_info").set_text( | |
+ (parseInt(duration/60) + 1) + " min"); | |
+ } | |
+ })); | |
+ } | |
+ this.view.set_model(this.model); | |
+ var pixbuf = albumArtCache.lookup (256, artist, item.get_string(Grl.METADATA_KEY_ALBUM)); | |
if (pixbuf == null) { | |
let path = "/usr/share/icons/gnome/scalable/places/folder-music-symbolic.svg"; | |
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, -1, 256, true); | |
@@ -167,36 +175,29 @@ const AlbumWidget = new Lang.Class({ | |
this.ui.get_object("title_label").set_markup(album); | |
this.ui.get_object("released_label_info").set_text(item.get_creation_date().get_year().toString()); | |
- this.player.connect('song-changed', Lang.bind(this, | |
- function(widget, id) { | |
- // Highlight currently played song as bold | |
- let iter = this.model.get_iter_from_string(id.toString())[1]; | |
- let item = this.model.get_value(iter, 5); | |
- let title = "<b>" + item.get_title() + "</b>"; | |
- this.model.set_value(iter, 0, title); | |
- // Display now playing icon | |
- this.model.set_value(iter, 3, true); | |
- | |
- // Make all previous songs shadowed | |
- for (let i = 0; i < id; i++){ | |
- let iter = this.model.get_iter_from_string(i.toString())[1]; | |
- let item = this.model.get_value(iter, 5); | |
- let title = "<span color='grey'>" + item.get_title() + "</span>"; | |
- this.model.set_value(iter, 0, title); | |
- this.model.set_value(iter, 3, false); | |
- } | |
- | |
- //Remove markup from the following songs | |
- let i = parseInt(id) + 1; | |
- while(this.model.get_iter_from_string(i.toString())[0]) { | |
- let iter = this.model.get_iter_from_string(i.toString())[1]; | |
- let item = this.model.get_value(iter, 5); | |
- this.model.set_value(iter, 0, item.get_title()); | |
- this.model.set_value(iter, 3, false); | |
- i++; | |
- } | |
- return true; | |
- } | |
+ this.player.connect('playlist-item-changed', Lang.bind(this, | |
+ function(player, playlist, iter) { | |
+ //this is not our playlist, disregard the signal | |
+ if (playlist != this.model){ | |
+ print ("Album and"+type + " "+this.album + " and "+id); | |
+ return true;} | |
+ if (this.iterToClean){ | |
+ let item = this.model.get_value(this.iterToClean, 5); | |
+ this.model.set_value(this.iterToClean, 0, item.get_title()); | |
+ // Hide now playing icon | |
+ this.model.set_value(this.iterToClean, 3, false); | |
+ } | |
+ this.iterToClean = iter.copy(); | |
+ | |
+ // Highlight currently played song as bold | |
+ let item = this.model.get_value(iter, 5); | |
+ this.model.set_value(iter, 0, "<b>" + item.get_title() + "</b>"); | |
+ // Display now playing icon | |
+ this.model.set_value(iter, 3, true); | |
+ | |
+ // reset the previous item, if it exists | |
+ return true; | |
+ } | |
)); | |
}, | |
}); | |
@@ -224,8 +225,6 @@ const ArtistAlbums = new Lang.Class({ | |
widgets.push(widget); | |
} | |
this.show_all(); | |
- this.player.setPlaylist(tracks); | |
- this.player.setCurrentTrack(tracks[0]); | |
this.player.connect('song-changed', Lang.bind(this, | |
function(widget, id) { | |
-- | |
1.8.2.1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment