Skip to content

Instantly share code, notes, and snippets.

@gquintard
Created April 23, 2013 20:56
Show Gist options
  • Save gquintard/5447321 to your computer and use it in GitHub Desktop.
Save gquintard/5447321 to your computer and use it in GitHub Desktop.
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