diff --git a/data/com.github.needleandthread.vocal.gschema.xml b/data/com.github.needleandthread.vocal.gschema.xml
index 69f28b3..7a3da90 100644
--- a/data/com.github.needleandthread.vocal.gschema.xml
+++ b/data/com.github.needleandthread.vocal.gschema.xml
@@ -67,18 +67,18 @@
- "~/vocal"
+ "~/.local/share/vocal"
The directory where podcasts are stored
The directory where podcasts are stored
-
- ""
+
+ []
The podcast and episode that was last playing
- The podcast and episode that was last played, in podcast_name,episode_title format
+ The podcast and episode that was last played.
diff --git a/src/Controller.vala b/src/Controller.vala
index d152523..501eda4 100644
--- a/src/Controller.vala
+++ b/src/Controller.vala
@@ -47,7 +47,7 @@ namespace Vocal {
public bool first_run = true;
public bool newly_launched = true;
- public bool should_quit_immediately = true;
+ public bool should_quit_immediately = false;
public bool plugins_are_installing = false;
public bool checking_for_updates = false;
public bool is_closing = false;
@@ -63,7 +63,7 @@ namespace Vocal {
/* References, pointers, and containers */
- public Episode current_episode;
+ private Episode current_episode;
public Podcast highlighted_podcast;
/* Miscellaneous global variables */
@@ -118,6 +118,9 @@ namespace Vocal {
MPRIS mpris = new MPRIS (this);
mpris.initialize ();
+ // Restore last played Episode after MPRIS has been initialized
+ mpris.initialized.connect (restore_episode);
+
// Connect the new player position available signal from the player
// to set the new progress on the playback box
@@ -368,6 +371,60 @@ namespace Vocal {
}
}
+ public void set_episode (Episode? e) {
+ if (current_episode != null) {
+ library.set_episode_playback_position (current_episode);
+ }
+
+ current_episode = e;
+ if (current_episode != null) {
+ try {
+ player.set_episode (current_episode);
+ window.toolbar.playback_box.set_info_title (current_episode.title.replace ("%27", "'"), current_episode.parent.name.replace ("%27", "'"));
+ window.toolbar.playback_box.set_artwork_image_image (current_episode.parent.coverart_uri);
+ track_changed (current_episode.title, current_episode.parent.name, current_episode.parent.coverart_uri, (uint64) player.duration);
+ settings.last_played_media = {current_episode.guid, current_episode.link, current_episode.podcast_uri};
+ window.artwork_popover.set_notes_text (current_episode.description);
+ } catch (Error e) {
+ warning (e.message);
+ }
+
+ window.toolbar.show_playback_box ();
+ } else {
+ window.toolbar.hide_playback_box ();
+ }
+ }
+
+ public Episode get_episode () {
+ return current_episode;
+ }
+
+ private void restore_episode () {
+ if (settings.last_played_media != null && settings.last_played_media.length > 2) {
+
+ info ("Restoring last played media.");
+
+ // Split the media into two different strings
+ string[] fields = settings.last_played_media;
+ bool found = false;
+ foreach (Podcast podcast in library.podcasts) {
+
+ if (!found) {
+ if (podcast.feed_uri == fields[2]) {
+ found = true;
+
+ // Attempt to find the matching episode, set it as the current episode, and display the information in the box
+ foreach (Episode episode in podcast.episodes) {
+ if (episode.guid == fields[0] && episode.link == fields[1]) {
+ set_episode (episode);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
/*
* Playback related methods
*/
@@ -437,25 +494,6 @@ namespace Vocal {
player.play ();
playback_status_changed ("Playing");
- // Seek if necessary
- if (current_episode.last_played_position > 0 && current_episode.last_played_position > player.get_position ()) {
-
- // If it's a streaming episode, seeking takes longer
- // Temporarily pause the track and give it some time to seek
- if (current_episode.current_download_status == DownloadStatus.NOT_DOWNLOADED) {
- player.pause ();
- }
-
- player.set_position (current_episode.last_played_position);
-
- // Pause for about a second to give time to catch up
- if (current_episode.current_download_status == DownloadStatus.NOT_DOWNLOADED) {
- player.pause ();
- Thread.usleep (700000);
- player.play ();
- }
- }
-
var playpause_image = new Gtk.Image.from_icon_name ("media-playback-pause-symbolic", Gtk.IconSize.LARGE_TOOLBAR);
window.toolbar.set_play_pause_image (playpause_image);
window.toolbar.set_play_pause_text (_ ("Pause"));
@@ -551,13 +589,7 @@ namespace Vocal {
}
}
- // Hide the shownotes button
- window.toolbar.playback_box.hide_artwork_image ();
- window.toolbar.playback_box.hide_volume_button ();
- window.toolbar.hide_playlist_button ();
-
window.show_infobar (_ ("Adding new podcast: " + feed + ""), MessageType.INFO);
- window.toolbar.show_playback_box ();
var loop = new MainLoop ();
bool success = false;
@@ -573,6 +605,7 @@ namespace Vocal {
});
loop.run ();
+ window.hide_infobar ();
if (success) {
@@ -594,8 +627,6 @@ namespace Vocal {
gpodder_loop.run ();
}
- window.toolbar.show_playlist_button ();
-
if (!player.playing)
window.toolbar.hide_playback_box ();
diff --git a/src/Library.vala b/src/Library.vala
index 848d24e..21da2ba 100644
--- a/src/Library.vala
+++ b/src/Library.vala
@@ -100,7 +100,7 @@ namespace Vocal {
local_library_path = settings.library_location.replace ("~", GLib.Environment.get_home_dir ());
#if HAVE_LIBUNITY
- launcher = Unity.LauncherEntry.get_for_desktop_id ("vocal.desktop");
+ launcher = Unity.LauncherEntry.get_for_desktop_id ("com.github.needleandthread.vocal.desktop");
launcher.count = new_episode_count;
#endif
@@ -717,8 +717,12 @@ namespace Vocal {
foreach (Podcast p in podcasts) {
output_line =
- """
- """.printf (p.name.replace ("\"", "'").replace ("&", "and"), p.feed_uri);
+"""
+
+ rss
+
+
+""".printf (p.name, p.feed_uri);
stream.output_stream.write (output_line.data);
}
@@ -905,7 +909,7 @@ namespace Vocal {
FROM Episode e
LEFT JOIN Podcast p on p.feed_uri = e.podcast_uri
WHERE podcast_uri = '%s'
- ORDER BY e.rowid ASC".printf (podcast.feed_uri);
+ ORDER BY e.released ASC".printf (podcast.feed_uri);
ec = db.prepare_v2 (prepared_query_str, prepared_query_str.length, out stmt);
if (ec != Sqlite.OK) {
warning ("Error: %d: %s\n", db.errcode (), db.errmsg ());
@@ -1227,7 +1231,7 @@ namespace Vocal {
if (settings.library_location == null) {
settings.library_location = GLib.Environment.get_user_data_dir () + """/vocal""";
}
- local_library_path = settings.library_location.replace ("~", GLib.Environment.get_user_data_dir ());
+ local_library_path = settings.library_location.replace ("~", GLib.Environment.get_home_dir ());
// If the new local_library_path has been modified, update the setting
if (settings.library_location != local_library_path) {
diff --git a/src/MainWindow.vala b/src/MainWindow.vala
index f45c85c..7879bd0 100644
--- a/src/MainWindow.vala
+++ b/src/MainWindow.vala
@@ -331,7 +331,11 @@ namespace Vocal {
});
new_episodes_view.add_all_new_to_queue.connect ((episodes) => {
foreach (Episode e in episodes) {
- enqueue_episode (e);
+ if (controller.get_episode () == null) {
+ controller.set_episode (e);
+ } else {
+ enqueue_episode (e);
+ }
}
});
@@ -348,6 +352,7 @@ namespace Vocal {
all_flowbox = new Gtk.FlowBox ();
all_art = new Gee.ArrayList ();
all_flowbox.get_style_context ().add_class ("notebook-art");
+ all_flowbox.max_children_per_line = 20;
all_flowbox.selection_mode = Gtk.SelectionMode.SINGLE;
all_flowbox.activate_on_single_click = true;
all_flowbox.child_activated.connect (on_child_activated);
@@ -466,7 +471,6 @@ namespace Vocal {
toolbar.play_pause_selected.connect (controller.play_pause);
toolbar.seek_forward_selected.connect (controller.seek_forward);
toolbar.seek_backward_selected.connect (controller.seek_backward);
- toolbar.playlist_button.clicked.connect (() => { artwork_popover.queue_box.show_all (); });
toolbar.store_selected.connect (() => {
details.pane_should_hide ();
@@ -620,58 +624,6 @@ namespace Vocal {
all_art.clear ();
}
- //TODO: Move this to the controller
-
- info ("Restoring last played media.");
- // If the program was just launched, check to see what the last played media was
- if (controller.newly_launched) {
-
- current_widget = all_scrolled;
-
- if (controller.settings.last_played_media != null && controller.settings.last_played_media.length > 1) {
-
- // Split the media into two different strings
- string[] fields = controller.settings.last_played_media.split (",");
- bool found = false;
- foreach (Podcast podcast in controller.library.podcasts) {
-
- if (!found) {
- if (podcast.name == fields[1]) {
- found = true;
-
- // Attempt to find the matching episode, set it as the current episode, and display the information in the box
- foreach (Episode episode in podcast.episodes) {
- if (episode.title == fields[0]) {
- controller.current_episode = episode;
- toolbar.playback_box.set_info_title (controller.current_episode.title.replace ("%27", "'"), controller.current_episode.parent.name.replace ("%27", "'"));
- toolbar.playback_box.set_artwork_image_image (controller.current_episode.parent.coverart_uri);
- controller.track_changed (controller.current_episode.title, controller.current_episode.parent.name, controller.current_episode.parent.coverart_uri, (uint64) controller.player.duration);
-
- try {
-
- controller.player.set_episode (controller.current_episode);
- controller.player.set_position (controller.current_episode.last_played_position);
- artwork_popover.set_notes_text (episode.description);
-
- } catch (Error e) {
- warning (e.message);
- }
-
- if (controller.current_episode.last_played_position != 0) {
- toolbar.show_playback_box ();
- }
- else {
- toolbar.hide_playback_box ();
- }
- }
- }
- }
- }
- }
- }
- }
-
-
// Refill the controller.library based on what is stored in the database (if it's not newly launched, in
// which case it has already been filled)
if (!controller.newly_launched) {
@@ -773,16 +725,11 @@ namespace Vocal {
*/
private void play_episode_from_queue_immediately (Episode e) {
- controller.current_episode = e;
- artwork_popover.queue_box.hide ();
+ controller.set_episode (e);
+ artwork_popover.hide ();
controller.library.remove_episode_from_queue (e);
controller.play ();
-
- // Set the shownotes, the media information, and update the last played media in the settings
- controller.track_changed (controller.current_episode.title, controller.current_episode.parent.name, controller.current_episode.parent.coverart_uri, (uint64)controller.player.duration);
- artwork_popover.set_notes_text (controller.current_episode.description);
- controller.settings.last_played_media = "%s,%s".printf (controller.current_episode.title, controller.current_episode.parent.name);
}
/*
@@ -792,19 +739,13 @@ namespace Vocal {
// Get the episode
if (episode == null) {
- controller.current_episode = details.current_episode;
+ controller.set_episode (details.current_episode);
} else {
- controller.current_episode = episode;
+ controller.set_episode (episode);
}
controller.player.pause ();
controller.play ();
-
- // Set the shownotes, the media information, and update the last played media in the settings
- controller.track_changed (controller.current_episode.title, controller.current_episode.parent.name, controller.current_episode.parent.coverart_uri, (uint64) controller.player.duration);
- toolbar.playback_box.set_artwork_image_image (controller.current_episode.parent.coverart_uri);
- artwork_popover.set_notes_text (controller.current_episode.description);
- controller.settings.last_played_media = "%s,%s".printf (controller.current_episode.title, controller.current_episode.parent.name);
}
/*
@@ -964,13 +905,6 @@ namespace Vocal {
//If the user selects a file, get the name and parse it
if (decision == Gtk.ResponseType.ACCEPT || run_pending_import == true) {
- toolbar.show_playback_box ();
-
- // Hide the shownotes button
- toolbar.playback_box.hide_artwork_image ();
- toolbar.playback_box.hide_volume_button ();
- toolbar.hide_playlist_button ();
-
if (current_widget == welcome) {
switch_visible_page (import_message_box);
}
@@ -1012,10 +946,6 @@ namespace Vocal {
// Make the refresh and export items sensitive now
toolbar.export_item.sensitive = true;
- toolbar.playback_box.show_artwork_image ();
- toolbar.playback_box.show_volume_button ();
- toolbar.show_playlist_button ();
-
if (current_widget == import_message_box) {
switch_visible_page (all_scrolled);
}
@@ -1025,9 +955,9 @@ namespace Vocal {
controller.currently_importing = false;
if (controller.player.playing) {
- toolbar.playback_box.set_info_title (controller.current_episode.title.replace ("%27", "'"), controller.current_episode.parent.name.replace ("%27", "'"));
- toolbar.playback_box.set_artwork_image_image (controller.current_episode.parent.coverart_uri);
- video_controls.set_info_title (controller.current_episode.title.replace ("%27", "'"), controller.current_episode.parent.name.replace ("%27", "'"));
+ toolbar.playback_box.set_info_title (controller.get_episode ().title.replace ("%27", "'"), controller.get_episode ().parent.name.replace ("%27", "'"));
+ toolbar.playback_box.set_artwork_image_image (controller.get_episode ().parent.coverart_uri);
+ video_controls.set_info_title (controller.get_episode ().title.replace ("%27", "'"), controller.get_episode ().parent.name.replace ("%27", "'"));
}
loop.quit ();
@@ -1066,8 +996,13 @@ namespace Vocal {
*/
public void switch_visible_page (Gtk.Widget widget) {
- if (current_widget != widget)
- previous_widget = current_widget;
+ if (current_widget != widget) {
+ if (current_widget == welcome) {
+ previous_widget = all_scrolled;
+ } else {
+ previous_widget = current_widget;
+ }
+ }
if (widget == all_scrolled) {
notebook.set_visible_child (all_scrolled);
@@ -1141,7 +1076,7 @@ namespace Vocal {
info ("GStreamer registry updated, attempting to start playback using the new plugins...");
// Reset the controller.player
- controller.player.current_episode = null;
+ controller.set_episode (null);
controller.play ();
}
@@ -1237,7 +1172,7 @@ namespace Vocal {
details.on_single_delete(episode);
// Update gpodder.net
- controller.gpodder_client.update_episode (controller.current_episode, EpisodeAction.DELETE);
+ controller.gpodder_client.update_episode (controller.get_episode (), EpisodeAction.DELETE);
}
@@ -1639,7 +1574,7 @@ namespace Vocal {
toolbar.set_play_pause_image (playpause_image);
// If there is a video showing, return to the controller.library view
- if (controller.current_episode.parent.content_type == MediaType.VIDEO) {
+ if (controller.get_episode ().parent.content_type == MediaType.VIDEO) {
on_return_to_library ();
}
@@ -1648,18 +1583,13 @@ namespace Vocal {
controller.playback_status_changed ("Stopped");
- controller.current_episode = controller.library.get_next_episode_in_queue ();
-
- if (controller.current_episode != null) {
+ controller.set_episode (controller.library.get_next_episode_in_queue ());
+ if (controller.get_episode () != null) {
controller.play ();
-
- // Set the shownotes, the media information, and update the last played media in the settings
- controller.track_changed (controller.current_episode.title, controller.current_episode.parent.name, controller.current_episode.parent.coverart_uri, (uint64) controller.player.duration);
- artwork_popover.set_notes_text (controller.current_episode.description);
- controller.settings.last_played_media = "%s,%s".printf (controller.current_episode.title, controller.current_episode.parent.name);
} else {
controller.player.playing = false;
+ controller.settings.last_played_media = null;
}
// Regenerate the new episode list in case the ended episode was one of the new episodes
@@ -1753,9 +1683,6 @@ namespace Vocal {
// Show the store
if (index == 0) {
switch_visible_page (directory_scrolled);
-
- // Set the controller.library as the previous widget for return_to_library to work
- previous_widget = all_scrolled;
}
// Add a new feed
@@ -1810,7 +1737,7 @@ namespace Vocal {
}
// Update gpodder.net if necessary
- controller.gpodder_client.update_episode (controller.current_episode, EpisodeAction.PLAY);
+ controller.gpodder_client.update_episode (controller.get_episode (), EpisodeAction.PLAY);
// If an episode is currently playing and Vocal is set to keep playing in the background, hide the window
if (controller.player.playing && controller.settings.keep_playing_in_background) {
@@ -1818,7 +1745,7 @@ namespace Vocal {
return true;
} else if (downloads != null && downloads.downloads.size > 0) {
//If there are downloads verify that the user wishes to exit and cancel the downloads
- var downloads_active_dialog = new Gtk.MessageDialog (this, Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.YES_NO, _ ("Vocal is currently downloading episodes. Exiting will cause the downloads to be canceled. Are you sure you want to exit?"));
+ var downloads_active_dialog = new Gtk.MessageDialog (this, Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.YES_NO, _ ("Vocal is currently downloading episodes. Exiting will cause the downloads to be cancelled. Are you sure you want to exit?"));
downloads_active_dialog.response.connect ((response_id) => {
downloads_active_dialog.destroy ();
if (response_id == Gtk.ResponseType.YES) {
diff --git a/src/Objects/Episode.vala b/src/Objects/Episode.vala
index efa95a0..0771536 100644
--- a/src/Objects/Episode.vala
+++ b/src/Objects/Episode.vala
@@ -124,9 +124,11 @@ namespace Vocal {
// states that datetimes should be in RFC 822 format,
// but date strings with different formats can cause a crash.
string[] time_formats = {
- "%a, %d %b %Y %H:%M:%S %Z", // Sunday, 01 Jan 1970 00:00:00 GMT
- "%a, %b %d %Y %H:%M:%S %Z" // Sunday, Jan 01 1970 00:00:00 GMT
+ "%d %b %Y %H:%M:%S %Z", // 01 Jan 1970 00:00:00 GMT
+ "%b %d %Y %H:%M:%S %Z" // Jan 01 1970 00:00:00 GMT
};
+ // GLib.Time.strptime doesn't accept strings containing the weekday (just returns NULL instead)
+ date_released = date_released[5:date_released.length];
foreach (string format in time_formats) {
var last_parsed_char = tm.strptime (date_released, format);
if (last_parsed_char != null) {
diff --git a/src/Utils/FeedParser.vala b/src/Utils/FeedParser.vala
index c6eeeaa..513496a 100644
--- a/src/Utils/FeedParser.vala
+++ b/src/Utils/FeedParser.vala
@@ -132,6 +132,7 @@ namespace Vocal {
Episode episode = new Episode ();
string next_item_in_queue = null;
bool found_summary = false;
+ bool found_media = false;
while (next_item_in_queue != "item" && i < queue.size - 1) {
i++;
@@ -162,6 +163,11 @@ namespace Vocal {
i++;
string typestring = queue[i].slice (0, 5);
+
+ if (typestring == "audio" || typestring == "video") {
+ found_media = true;
+ }
+
if (podcast.content_type == MediaType.UNKNOWN) {
if (typestring == "audio") {
podcast.content_type = MediaType.AUDIO;
@@ -169,10 +175,6 @@ namespace Vocal {
else if (typestring == "video") {
podcast.content_type = MediaType.VIDEO;
}
- else {
- podcast.content_type = MediaType.UNKNOWN;
- }
-
}
type_found = true;
@@ -209,7 +211,9 @@ namespace Vocal {
// Add the new episode to the podcast
- podcast.add_episode (episode);
+ if (found_media) {
+ podcast.add_episode (episode);
+ }
}
@@ -349,6 +353,11 @@ namespace Vocal {
podcast = create_podcast_from_queue ();
}
+ if (podcast.content_type == MediaType.UNKNOWN) {
+ warning ("Feed doesn't contain any media files. Abort.");
+ return null;
+ }
+
if (podcast.name.length < 1) {
warning ("Something went wrong during podcast parsing. Abort.");
return null;
@@ -552,6 +561,7 @@ namespace Vocal {
Episode episode = new Episode ();
string next_item_in_queue = null;
bool found_summary = false;
+ bool found_media = false;
while (next_item_in_queue != "item" && i < queue.size - 1) {
@@ -582,6 +592,11 @@ namespace Vocal {
i++;
string typestring = queue[i].slice (0, 5);
+
+ if (typestring == "audio" || typestring == "video") {
+ found_media = true;
+ }
+
if (podcast.content_type == MediaType.UNKNOWN) {
if (typestring == "audio") {
podcast.content_type = MediaType.AUDIO;
@@ -589,10 +604,6 @@ namespace Vocal {
else if (typestring == "video") {
podcast.content_type = MediaType.VIDEO;
}
- else {
- podcast.content_type = MediaType.UNKNOWN;
- }
-
}
type_found = true;
@@ -628,17 +639,19 @@ namespace Vocal {
}
- episode.parent = podcast;
- episode.podcast_uri = podcast.feed_uri;
+ if (found_media) {
+ episode.parent = podcast;
+ episode.podcast_uri = podcast.feed_uri;
- if (previous_newest_episode != null) {
- if (episode.title == previous_newest_episode.title.replace ("%27", "'")) {
- previous_found = true;
+ if (previous_newest_episode != null) {
+ if (episode.title == previous_newest_episode.title.replace ("%27", "'")) {
+ previous_found = true;
+ } else {
+ new_episodes.add (episode);
+ }
} else {
new_episodes.add (episode);
}
- } else {
- new_episodes.add (episode);
}
}
@@ -687,6 +700,7 @@ namespace Vocal {
/* Creating a Episode with values from tag. */
Episode entry = new Episode ();
+ bool found_media = false;
for (Xml.Node* iterEntry = iter->children; iterEntry != null; iterEntry = iterEntry->next) {
switch (iterEntry->name) {
@@ -709,12 +723,14 @@ namespace Vocal {
entry.uri=propEntry->children->content;
entry.link = entry.uri;
} else if (attr_name == "type" && podcast != null) {
- podcast.content_type = MediaType.UNKNOWN;
-
if (propEntry->children->content.contains ("audio/")) {
podcast.content_type = MediaType.AUDIO;
+ found_media = true;
} else if (propEntry->children->content.contains ("video/")) {
podcast.content_type = MediaType.VIDEO;
+ found_media = true;
+ } else {
+ podcast.content_type = MediaType.UNKNOWN;
}
}
}
@@ -727,10 +743,12 @@ namespace Vocal {
}
}
- entry.parent=podcast;
- entry.podcast_uri = podcast.feed_uri;
+ if (found_media) {
+ entry.parent=podcast;
+ entry.podcast_uri = podcast.feed_uri;
- episodes.add (entry);
+ episodes.add (entry);
+ }
}
for (int i=episodes.size; i > 0 && !previous_found; i--) {
diff --git a/src/Utils/MPRIS.vala b/src/Utils/MPRIS.vala
index 8978433..2b10ce5 100644
--- a/src/Utils/MPRIS.vala
+++ b/src/Utils/MPRIS.vala
@@ -40,6 +40,8 @@ namespace Vocal {
private unowned DBusConnection conn;
private uint owner_id;
+ public signal void initialized ();
+
/*
* Default constructor that simply sets the controller.window
*/
@@ -109,6 +111,7 @@ namespace Vocal {
});
connection.register_object ("/org/mpris/MediaPlayer2", player);
+ initialized ();
}
@@ -146,7 +149,7 @@ namespace Vocal {
private const string INTERFACE_NAME = "org.mpris.MediaPlayer2.Player";
- const string TRACK_ID = "/com/github/needleandthread/vocal/Track/%d";
+ const string TRACK_ID = "/com/github/needleandthread/vocal/Track/%u";
public MprisPlayer (DBusConnection conn) {
this.conn = conn;
diff --git a/src/Utils/Player.vala b/src/Utils/Player.vala
index 9bf9659..9fd70b7 100644
--- a/src/Utils/Player.vala
+++ b/src/Utils/Player.vala
@@ -40,22 +40,21 @@ namespace Vocal {
private string tag_string;
public Episode current_episode;
+ private bool restore_position;
private Player (string[]? args) {
- bool new_launch = true;
-
current_episode = null;
// Check every half-second if the current media is playing, and if it is
// send a signal that there is a new position available
GLib.Timeout.add (500, () => {
-
- if (playing)
+ if (playing && duration > 0.0) {
+ if (restore_position) {
+ set_position (current_episode.last_played_position);
+ restore_position = false;
+ }
new_position_available ();
- if (new_launch && duration > 0.0) {
- new_position_available ();
- new_launch = false;
}
return true;
});
@@ -107,6 +106,10 @@ namespace Vocal {
// Set the URI
this.uri = episode.playback_uri;
info ("Setting playback URI: %s".printf (episode.playback_uri));
+
+ if (current_episode.last_played_position > 0) {
+ restore_position = true;
+ }
/*
// If it's a video podcast, get the width and height and configure that information
@@ -145,11 +148,13 @@ namespace Vocal {
/*
* Sets the currently playing media position, in seconds
*/
- public void set_position (int seconds) {
- double calculated_progress = (double)seconds / get_duration ();
- set_progress (calculated_progress);
- new_position_available ();
- }
+ public void set_position (int seconds) {
+ if (duration > 0.0) {
+ double calculated_progress = (double)seconds / duration;
+ set_progress (calculated_progress);
+ new_position_available ();
+ }
+ }
/*
diff --git a/src/Utils/Utils.vala b/src/Utils/Utils.vala
index 6ac202d..f45040c 100644
--- a/src/Utils/Utils.vala
+++ b/src/Utils/Utils.vala
@@ -95,6 +95,8 @@ public class Utils {
markup = original;
}
+ markup = markup.replace (" ", " ");
+ markup = markup.replace ("'", "'");
markup = markup.replace ("&", "&");
// Simplify (keep only href attribute) & preserve anchor tags.
diff --git a/src/Utils/gpodderClient.vala b/src/Utils/gpodderClient.vala
index 56cccf4..a6e7962 100644
--- a/src/Utils/gpodderClient.vala
+++ b/src/Utils/gpodderClient.vala
@@ -483,6 +483,10 @@ namespace Vocal {
}
public bool update_episode (Episode episode, EpisodeAction action) {
+
+ if (controller.settings.gpodder_username == "") {
+ return false;
+ }
var session = new Soup.Session ();
session.user_agent = "vocal";
diff --git a/src/VocalSettings.vala b/src/VocalSettings.vala
index 5578102..bfc9d6b 100644
--- a/src/VocalSettings.vala
+++ b/src/VocalSettings.vala
@@ -39,7 +39,7 @@ public class VocalSettings : Granite.Services.Settings {
public int rewind_seconds { get; set;}
public string library_location { get; set; }
- public string last_played_media { get; set; }
+ public string[] last_played_media { get; set; }
public string itunes_store_country { get; set; }
public string archive_access_key { get; set; }
public string archive_secret_key { get; set; }
diff --git a/src/Widgets/DirectoryView.vala b/src/Widgets/DirectoryView.vala
index 9f93ea3..8a45228 100644
--- a/src/Widgets/DirectoryView.vala
+++ b/src/Widgets/DirectoryView.vala
@@ -33,6 +33,8 @@ namespace Vocal {
private Gtk.Button first_run_continue_button;
private Gtk.Box loading_box;
+ private Gtk.Label itunes_title;
+ private Gtk.Label loading_label;
private Gtk.ScrolledWindow scrolled_window;
@@ -48,7 +50,7 @@ namespace Vocal {
banner_box.get_style_context ().add_class ("toolbar");
banner_box.get_style_context ().add_class ("library-toolbar");
- var itunes_title = new Gtk.Label (_ ("iTunes Top 100 Podcasts"));
+ itunes_title = new Gtk.Label (_ ("iTunes Top 100 Podcasts"));
itunes_title.margin_top = 15;
itunes_title.margin_bottom = 5;
itunes_title.justify = Gtk.Justification.CENTER;
@@ -101,7 +103,7 @@ namespace Vocal {
loading_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 5);
var spinner = new Gtk.Spinner ();
spinner.active = true;
- var loading_label = new Gtk.Label (_ ("Loading iTunes Store"));
+ loading_label = new Gtk.Label (_("Loading iTunes Store (%d / 100)".printf (0)));
loading_label.get_style_context ().add_class ("h2");
loading_box.add (loading_label);
loading_box.add (spinner);
@@ -131,6 +133,9 @@ namespace Vocal {
int i = 1;
if (entries == null) {
info ("iterating over entries");
+ itunes_title.set_text (_("Error when loading iTunes Top 100 Podcasts"));
+ loading_box.set_no_show_all (true);
+ loading_box.hide ();
return null;
}
@@ -148,6 +153,7 @@ namespace Vocal {
on_new_subscription (url);
});
flowbox.add (directory_art);
+ loading_label.set_text (_("Loading iTunes Store (%d / 100)".printf (i)));
i++;
}
diff --git a/src/Widgets/PodcastView.vala b/src/Widgets/PodcastView.vala
index cc90ae9..76330ed 100644
--- a/src/Widgets/PodcastView.vala
+++ b/src/Widgets/PodcastView.vala
@@ -619,7 +619,7 @@ namespace Vocal {
}
name_label.set_text (podcast.name.replace ("%27", "'"));
- description_label.set_text (podcast.description.replace ("""\n""", ""));
+ description_label.set_text (Utils.html_to_markup (podcast.description));
reset_episode_list ();
populate_episodes ();
@@ -663,7 +663,7 @@ namespace Vocal {
private void on_row_selected () {
GLib.List rows = listbox.get_selected_rows ();
- if (rows.length () < 1) {
+ if (rows.length () != 1) {
return;
}
@@ -721,7 +721,9 @@ namespace Vocal {
private void reset_episode_list () {
foreach (var item in listbox.get_children ()) {
- listbox.remove (item);
+ ListBoxRow row = (ListBoxRow) item;
+ row.selectable = false;
+ listbox.remove (row);
}
boxes.clear ();
diff --git a/src/Widgets/SearchResultsView.vala b/src/Widgets/SearchResultsView.vala
index c08650a..e788fec 100644
--- a/src/Widgets/SearchResultsView.vala
+++ b/src/Widgets/SearchResultsView.vala
@@ -143,9 +143,7 @@ namespace Vocal {
local_episodes_listbox.button_press_event.connect (on_episode_activated);
local_podcasts_listbox.button_press_event.connect (on_podcast_activated);
- local_episodes_listbox.expand = true;
- local_podcasts_listbox.expand = true;
- cloud_results_flowbox.expand = true;
+ content_box.expand = true;
local_episodes_widgets = new Gee.ArrayList ();
local_podcasts_widgets = new Gee.ArrayList ();
diff --git a/src/Widgets/Toolbar.vala b/src/Widgets/Toolbar.vala
index 59bc671..5ea084c 100644
--- a/src/Widgets/Toolbar.vala
+++ b/src/Widgets/Toolbar.vala
@@ -54,7 +54,6 @@ namespace Vocal {
public Gtk.Button search_button;
private Gtk.Button podcast_store_button;
- public Gtk.Button playlist_button;
public Gtk.Button new_episodes_button;
public Gtk.MenuItem export_item;
@@ -73,14 +72,6 @@ namespace Vocal {
// Set the playback box in the middle of the HeaderBar
playback_box.hexpand = true;
- playlist_button = new Gtk.Button.from_icon_name ("media-playlist-consecutive-symbolic");
- playlist_button.tooltip_text = _ ("Coming up next");
- playlist_button.clicked.connect (() => {
- playlist_selected ();
- });
- playlist_button.relief = Gtk.ReliefStyle.NONE;
- playlist_button.valign = Gtk.Align.CENTER;
-
if (on_elementary) {
new_episodes_button = new Gtk.Button.from_icon_name ("help-about-symbolic", Gtk.IconSize.LARGE_TOOLBAR);
new_episodes_button.relief = Gtk.ReliefStyle.NONE;
@@ -375,8 +366,6 @@ namespace Vocal {
right_button_box.pack_end (new_episodes_button);
right_button_box.halign = Gtk.Align.END;
- this.spacing = 0;
-
this.pack_start (left_button_box);
this.set_custom_title (playback_box);
this.pack_end (right_button_box);
@@ -398,7 +387,6 @@ namespace Vocal {
}
}
-
public void show_playback_box () {
if (playback_box != null) {
this.playback_box.no_show_all = false;
@@ -407,22 +395,6 @@ namespace Vocal {
}
}
-
-
- public void show_playlist_button () {
- if (playlist_button != null) {
- playlist_button.set_no_show_all (false);
- playlist_button.show ();
- }
- }
-
- public void hide_playlist_button () {
- if (playlist_button != null) {
- playlist_button.set_no_show_all (true);
- playlist_button.hide ();
- }
- }
-
public void hide_download_button () {
if (download != null) {
this.download.set_no_show_all (true);