diff --git a/data/music.gschema.xml b/data/music.gschema.xml
index e4ffeab87..bbb08d850 100644
--- a/data/music.gschema.xml
+++ b/data/music.gschema.xml
@@ -22,6 +22,11 @@
The last song played by Music
A string representing the uri of the last played music file
+
+ 0
+ Playback progression of the last song played by Music
+ Number of seconds elapsed since the beginning of the last track that was played
+
475
diff --git a/src/PlaybackManager.vala b/src/PlaybackManager.vala
index c759b0807..96b028df4 100644
--- a/src/PlaybackManager.vala
+++ b/src/PlaybackManager.vala
@@ -45,7 +45,6 @@ public class Music.PlaybackManager : Object {
private PlaybackManager () {}
construct {
- settings = new Settings ("io.elementary.music");
queue_liststore = new ListStore (typeof (AudioObject));
playbin = Gst.ElementFactory.make ("playbin", "playbin");
@@ -68,7 +67,8 @@ public class Music.PlaybackManager : Object {
next_action = new SimpleAction (Application.ACTION_NEXT, null);
next_action.activate.connect (() => next ());
- play_pause_action = new SimpleAction.stateful (Application.ACTION_PLAY_PAUSE, null, new Variant.boolean (false));
+ play_pause_action =
+ new SimpleAction.stateful (Application.ACTION_PLAY_PAUSE, null, new Variant.boolean (false));
play_pause_action.change_state.connect (play_pause);
previous_action = new SimpleAction (Application.ACTION_PREVIOUS, null);
@@ -98,8 +98,12 @@ public class Music.PlaybackManager : Object {
bind_property ("has-items", save_playlist_action, "enabled", SYNC_CREATE);
}
+ public void seek_to_progress_nano_seconds (int64 progress) {
+ playbin.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH, progress);
+ }
+
public void seek_to_progress (double percent) {
- playbin.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH, (int64)(percent * current_audio.duration));
+ seek_to_progress_nano_seconds ((int64)(percent * current_audio.duration));
}
// Files[] must not contain any null entries
@@ -214,6 +218,13 @@ public class Music.PlaybackManager : Object {
playbin.query_position (Gst.Format.TIME, out position);
playback_position = position.clamp (0, current_audio.duration);
+ int playback_position_seconds = (int)(playback_position / 1000000000);
+ // Save progress every other second, to reduce disk writes
+ if (playback_position_seconds % 2 == 0) {
+ debug ("setting progress: " + (playback_position_seconds).to_string () + "s");
+ settings.set_int ("progression-last-played", playback_position_seconds);
+ }
+
return Source.CONTINUE;
});
} else {
@@ -409,6 +420,27 @@ public class Music.PlaybackManager : Object {
}
current_audio = (AudioObject) queue_liststore.get_item (position);
+
+ // Read then restore saved progress
+ var progression_last_played_seconds = settings.get_int ("progression-last-played");
+ if (progression_last_played_seconds > 0) {
+ int64 progression_last_played = (int64)progression_last_played_seconds * 1000000000;
+
+ // Wait for current_audio.duration to be set by the object responsible for setting it
+ GLib.Timeout.add (50, () => {
+ if (current_audio.duration != 0) {
+ // Do not seek if duration is inferior to seeking position
+ if (current_audio.duration > progression_last_played) {
+ info ("saved progress found and valid, restoring it: %i", progression_last_played_seconds);
+ seek_to_progress_nano_seconds (progression_last_played);
+ }
+ return Source.REMOVE;
+ }
+
+ // Track metadata are not set yet, continue to wait before restoring playback position
+ return Source.CONTINUE;
+ });
+ }
}
}
diff --git a/src/Views/NowPlayingView.vala b/src/Views/NowPlayingView.vala
index ed8e43b6d..512d865b8 100644
--- a/src/Views/NowPlayingView.vala
+++ b/src/Views/NowPlayingView.vala
@@ -108,10 +108,14 @@ public class Music.NowPlayingView : Gtk.Box {
playback_manager.notify["current-audio"].connect (() => {
if (playback_manager.current_audio != null) {
- playback_manager.current_audio.bind_property ("artist", artist_label, "label", BindingFlags.SYNC_CREATE);
- playback_manager.current_audio.bind_property ("title", title_label, "label", BindingFlags.SYNC_CREATE);
- playback_manager.current_audio.bind_property ("duration", seekbar, "playback-duration", BindingFlags.SYNC_CREATE);
- playback_manager.current_audio.bind_property ("texture", album_image.image, "paintable", BindingFlags.SYNC_CREATE);
+ playback_manager.current_audio.bind_property (
+ "artist", artist_label, "label", BindingFlags.SYNC_CREATE);
+ playback_manager.current_audio.bind_property (
+ "title", title_label, "label", BindingFlags.SYNC_CREATE);
+ playback_manager.current_audio.bind_property (
+ "duration", seekbar, "playback-duration", BindingFlags.SYNC_CREATE);
+ playback_manager.current_audio.bind_property (
+ "texture", album_image.image, "paintable", BindingFlags.SYNC_CREATE);
} else {
album_image.image.clear ();
artist_label.label = _("Not playing");
diff --git a/src/Widgets/TrackRow.vala b/src/Widgets/TrackRow.vala
index 41b4dd465..76e80065e 100644
--- a/src/Widgets/TrackRow.vala
+++ b/src/Widgets/TrackRow.vala
@@ -88,7 +88,8 @@ public class Music.TrackRow : Granite.Bin {
play_icon.spinning = playback_manager.current_audio == audio_object;
});
- var play_pause_action = (SimpleAction) GLib.Application.get_default ().lookup_action (Application.ACTION_PLAY_PAUSE);
+ var play_pause_action =
+ (SimpleAction) GLib.Application.get_default ().lookup_action (Application.ACTION_PLAY_PAUSE);
update_playing (play_pause_action.get_state ().get_boolean ());
GLib.Application.get_default ().action_state_changed.connect ((name, new_state) => {