[rhythmbox] podcast: rearrange podcast parsing code
- From: Jonathan Matthew <jmatthew src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rhythmbox] podcast: rearrange podcast parsing code
- Date: Fri, 16 Oct 2020 07:18:33 +0000 (UTC)
commit 614353cd92bdd5d5ed3a7735a5161d2c36793f56
Author: Jonathan Matthew <jonathan d14n org>
Date: Fri Sep 4 23:34:31 2020 +1000
podcast: rearrange podcast parsing code
Switch to totem_pl_parser_parse_async so we don't have to manage
threads, and move mime type checking and other error handling out
to the podcast manager code to simplify the parser interface.
podcast/rb-podcast-add-dialog.c | 40 ++--
podcast/rb-podcast-main-source.c | 2 +-
podcast/rb-podcast-manager.c | 384 ++++++++++++++++++---------------------
podcast/rb-podcast-manager.h | 7 -
podcast/rb-podcast-parse.c | 135 ++++++--------
podcast/rb-podcast-parse.h | 12 +-
podcast/test-podcast-parse.c | 56 +++---
7 files changed, 296 insertions(+), 340 deletions(-)
---
diff --git a/podcast/rb-podcast-add-dialog.c b/podcast/rb-podcast-add-dialog.c
index e7befa45f..794a2744f 100644
--- a/podcast/rb-podcast-add-dialog.c
+++ b/podcast/rb-podcast-add-dialog.c
@@ -286,11 +286,22 @@ typedef struct {
gboolean single;
GError *error;
int reset_count;
-} ParseThreadData;
+} ParseData;
-static gboolean
-parse_finished (ParseThreadData *data)
+static void
+parse_cb (RBPodcastChannel *channel, GError *error, gpointer user_data)
{
+ ParseData *data = user_data;
+
+ if (error != NULL) {
+ /* fake up a channel with just the url as the title, allowing the user
+ * to subscribe to the podcast anyway.
+ */
+ data->channel->url = g_strdup (data->url);
+ data->channel->title = g_strdup (data->url);
+ g_error_free (error);
+ }
+
if (data->reset_count != data->dialog->priv->reset_count) {
rb_debug ("dialog reset while parsing");
rb_podcast_parse_channel_free (data->channel);
@@ -298,7 +309,6 @@ parse_finished (ParseThreadData *data)
g_clear_error (&data->error);
g_free (data->url);
g_free (data);
- return FALSE;
}
if (data->error != NULL) {
@@ -374,30 +384,14 @@ parse_finished (ParseThreadData *data)
g_clear_error (&data->error);
g_free (data->url);
g_free (data);
- return FALSE;
-}
-
-static gpointer
-parse_thread (ParseThreadData *data)
-{
- if (rb_podcast_parse_load_feed (data->channel, data->url, FALSE, &data->error) == FALSE) {
- /* fake up a channel with just the url as the title, allowing the user
- * to subscribe to the podcast anyway.
- */
- data->channel->url = g_strdup (data->url);
- data->channel->title = g_strdup (data->url);
- }
-
- g_idle_add ((GSourceFunc) parse_finished, data);
- return NULL;
}
static void
parse_in_thread (RBPodcastAddDialog *dialog, const char *text, gboolean existing, gboolean single)
{
- ParseThreadData *data;
+ ParseData *data;
- data = g_new0 (ParseThreadData, 1);
+ data = g_new0 (ParseData, 1);
data->dialog = g_object_ref (dialog);
data->url = g_strdup (text);
data->channel = g_new0 (RBPodcastChannel, 1);
@@ -405,7 +399,7 @@ parse_in_thread (RBPodcastAddDialog *dialog, const char *text, gboolean existing
data->single = single;
data->reset_count = dialog->priv->reset_count;
- g_thread_new ("podcast parser", (GThreadFunc) parse_thread, data);
+ rb_podcast_parse_load_feed (data->channel, data->url, NULL, parse_cb, data);
}
static void
diff --git a/podcast/rb-podcast-main-source.c b/podcast/rb-podcast-main-source.c
index d59d85f74..45a54558c 100644
--- a/podcast/rb-podcast-main-source.c
+++ b/podcast/rb-podcast-main-source.c
@@ -380,7 +380,7 @@ impl_constructed (GObject *object)
source, 0);
g_signal_connect_object (podcast_mgr,
- "process_error",
+ "feed-parse-error",
G_CALLBACK (feed_error_cb),
source, 0);
diff --git a/podcast/rb-podcast-manager.c b/podcast/rb-podcast-manager.c
index 96485c35f..a0768923e 100644
--- a/podcast/rb-podcast-manager.c
+++ b/podcast/rb-podcast-manager.c
@@ -68,20 +68,11 @@ enum
{
START_DOWNLOAD,
FINISH_DOWNLOAD,
- PROCESS_ERROR,
+ FEED_PARSE_ERROR,
FEED_UPDATES_AVAILABLE,
LAST_SIGNAL
};
-/* passed from feed parsing threads back to main thread */
-typedef struct
-{
- GError *error;
- RBPodcastChannel *channel;
- RBPodcastManager *pd;
- gboolean automatic;
-} RBPodcastManagerParseResult;
-
typedef struct
{
RBPodcastManager *pd;
@@ -106,7 +97,8 @@ typedef struct
RBPodcastManager *pd;
char *url;
gboolean automatic;
- gboolean existing_feed;
+ RBPodcastChannel *channel;
+ GError *error;
} RBPodcastUpdate;
struct RBPodcastManagerPrivate
@@ -116,8 +108,8 @@ struct RBPodcastManagerPrivate
RBPodcastDownload *active_download;
guint source_sync;
int updating;
- gboolean shutdown;
RBExtDB *art_store;
+ GCancellable *update_cancel;
GArray *searches;
GSettings *settings;
@@ -151,12 +143,7 @@ static void rb_podcast_manager_save_metadata (RBPodcastManager *pd,
static void rb_podcast_manager_db_entry_added_cb (RBPodcastManager *pd,
RhythmDBEntry *entry);
static gboolean rb_podcast_manager_next_file (RBPodcastManager * pd);
-static void rb_podcast_manager_handle_feed_error (RBPodcastManager *mgr,
- const char *url,
- GError *error,
- gboolean emit);
-static gpointer rb_podcast_manager_thread_parse_feed (RBPodcastUpdate *info);
static void podcast_settings_changed_cb (GSettings *settings,
const char *key,
RBPodcastManager *mgr);
@@ -203,7 +190,7 @@ rb_podcast_manager_class_init (RBPodcastManagerClass *klass)
g_signal_new ("start_download",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBPodcastManagerClass, start_download),
+ 0,
NULL, NULL,
NULL,
G_TYPE_NONE,
@@ -214,7 +201,7 @@ rb_podcast_manager_class_init (RBPodcastManagerClass *klass)
g_signal_new ("finish_download",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBPodcastManagerClass, finish_download),
+ 0,
NULL, NULL,
NULL,
G_TYPE_NONE,
@@ -225,18 +212,18 @@ rb_podcast_manager_class_init (RBPodcastManagerClass *klass)
g_signal_new ("feed_updates_available",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBPodcastManagerClass, feed_updates_available),
+ 0,
NULL, NULL,
NULL,
G_TYPE_NONE,
1,
RHYTHMDB_TYPE_ENTRY);
- rb_podcast_manager_signals[PROCESS_ERROR] =
- g_signal_new ("process_error",
+ rb_podcast_manager_signals[FEED_PARSE_ERROR] =
+ g_signal_new ("feed-parse-error",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (RBPodcastManagerClass, process_error),
+ 0,
NULL, NULL,
NULL,
G_TYPE_NONE,
@@ -255,7 +242,6 @@ rb_podcast_manager_init (RBPodcastManager *pd)
pd->priv->source_sync = 0;
pd->priv->db = NULL;
-
}
static void
@@ -303,6 +289,8 @@ rb_podcast_manager_constructed (GObject *object)
PACKAGE "/" VERSION,
NULL);
+ pd->priv->update_cancel = g_cancellable_new ();
+
rb_podcast_manager_start_update_timer (pd);
}
@@ -624,8 +612,8 @@ void
rb_podcast_manager_update_feeds (RBPodcastManager *pd)
{
RhythmDBQueryResultList *list;
- RhythmDBEntry *entry;
- const char *uri;
+ RhythmDBEntry *entry;
+ const char *uri;
guint status;
GList *l;
@@ -672,181 +660,210 @@ rb_podcast_manager_update_feeds_cb (gpointer data)
return FALSE;
}
+static void
+podcast_update_free (RBPodcastUpdate *update)
+{
+ RBPodcastManager *pd = update->pd;
+
+ if (--pd->priv->updating == 0) {
+ g_object_notify (G_OBJECT (pd), "updating");
+ }
+ g_object_unref (pd);
-gboolean
-rb_podcast_manager_subscribe_feed (RBPodcastManager *pd, const char *url, gboolean automatic)
+ g_clear_error (&update->error);
+ rb_podcast_parse_channel_free (update->channel);
+ g_free (update->url);
+ g_free (update);
+}
+
+static void
+feed_parse_cb (RBPodcastChannel *channel, GError *error, gpointer user_data)
{
- RBPodcastUpdate *info;
+ RBPodcastUpdate *update = user_data;
+ RBPodcastManager *pd = update->pd;
RhythmDBEntry *entry;
- GFile *feed;
- char *feed_url;
- gboolean existing_feed;
+ GValue v = {0,};
+ gboolean existing = FALSE;
- if (g_str_has_prefix (url, "feed://") || g_str_has_prefix (url, "itpc://")) {
- char *tmp;
+ if (error == NULL) {
+ if (channel->is_opml) {
+ GList *l;
- tmp = g_strdup_printf ("http://%s", url + strlen ("feed://"));
- feed = g_file_new_for_uri (tmp);
- g_free (tmp);
- } else {
- feed = g_file_new_for_uri (url);
- }
+ rb_debug ("Loading OPML feeds from %s", channel->url);
- /* hmm. can we check if the GFile we got is something useful? */
-#if 0
- if (valid_url == NULL) {
- rb_error_dialog (NULL, _("Invalid URL"),
- _("The URL \"%s\" is not valid, please check it."), url);
- return FALSE;
- }
-#endif
+ for (l = channel->posts; l != NULL; l = l->next) {
+ RBPodcastItem *item = l->data;
+ /* assume the feeds don't already exist */
+ rb_podcast_manager_subscribe_feed (pd, item->url, FALSE);
+ }
+ } else {
+ rb_podcast_manager_add_parsed_feed (pd, channel);
+ }
+ } else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ rb_debug ("podcast update cancelled");
+ g_error_free (error);
+ } else {
+ /* set the error in the feed entry, if one exists */
+ entry = rhythmdb_entry_lookup_by_location (pd->priv->db, channel->url);
+ if (entry != NULL && rhythmdb_entry_get_entry_type (entry) ==
RHYTHMDB_ENTRY_TYPE_PODCAST_FEED) {
+ g_value_init (&v, G_TYPE_STRING);
+ g_value_set_string (&v, error->message);
+ rhythmdb_entry_set (pd->priv->db, entry, RHYTHMDB_PROP_PLAYBACK_ERROR, &v);
+ g_value_unset (&v);
+
+ g_value_init (&v, G_TYPE_ULONG);
+ g_value_set_ulong (&v, RHYTHMDB_PODCAST_FEED_STATUS_NORMAL);
+ rhythmdb_entry_set (pd->priv->db, entry, RHYTHMDB_PROP_STATUS, &v);
+ g_value_unset (&v);
- feed_url = g_file_get_uri (feed); /* not sure this buys us anything at all */
- entry = rhythmdb_entry_lookup_by_location (pd->priv->db, feed_url);
- if (entry) {
- GValue v = {0,};
- if (rhythmdb_entry_get_entry_type (entry) != RHYTHMDB_ENTRY_TYPE_PODCAST_FEED) {
- /* added as something else, probably iradio */
- rb_error_dialog (NULL, _("URL already added"),
- _("The URL \"%s\" has already been added as a radio station. "
- "If this is a podcast feed, please remove the radio station."), url);
- return FALSE;
+ rhythmdb_commit (pd->priv->db);
+ existing = TRUE;
}
- existing_feed = TRUE;
- g_value_init (&v, G_TYPE_ULONG);
- g_value_set_ulong (&v, RHYTHMDB_PODCAST_FEED_STATUS_UPDATING);
- rhythmdb_entry_set (pd->priv->db, entry, RHYTHMDB_PROP_STATUS, &v);
- rhythmdb_commit (pd->priv->db);
- g_value_unset (&v);
- } else {
- existing_feed = FALSE;
+ /* if this was a result of a direct user action, emit the error signal too */
+ if (update->automatic) {
+ gchar *error_msg;
+ error_msg = g_strdup_printf (_("There was a problem adding this podcast: %s. Please
verify the URL: %s"),
+ error->message, channel->url);
+ g_signal_emit (pd,
+ rb_podcast_manager_signals[FEED_PARSE_ERROR],
+ 0, channel->url, error_msg, existing);
+ g_free (error_msg);
+ }
+ g_error_free (error);
}
- info = g_new0 (RBPodcastUpdate, 1);
- info->pd = g_object_ref (pd);
- info->url = feed_url;
- info->automatic = automatic;
- info->existing_feed = existing_feed;
+ podcast_update_free (update);
+}
+
+static void
+start_feed_parse (RBPodcastManager *pd, RBPodcastUpdate *update)
+{
pd->priv->updating++;
if (pd->priv->updating == 1) {
g_object_notify (G_OBJECT (pd), "updating");
}
- g_thread_new ("podcast-parse",
- (GThreadFunc) rb_podcast_manager_thread_parse_feed,
- info);
-
- return TRUE;
+ rb_podcast_parse_load_feed (update->channel, update->url, pd->priv->update_cancel, feed_parse_cb,
update);
}
static void
-rb_podcast_manager_free_parse_result (RBPodcastManagerParseResult *result)
+confirm_bad_mime_type_response_cb (GtkDialog *dialog, int response, RBPodcastUpdate *update)
{
- rb_podcast_parse_channel_free (result->channel);
- g_object_unref (result->pd);
- g_clear_error (&result->error);
- g_free (result);
+ if (response == GTK_RESPONSE_YES) {
+ start_feed_parse (update->pd, update);
+ } else {
+ podcast_update_free (update);
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
}
-static gboolean
-rb_podcast_manager_parse_complete_cb (RBPodcastManagerParseResult *result)
+static void
+mime_type_check_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- if (result->pd->priv->shutdown) {
- return FALSE;
- }
-
- if (result->error) {
- rb_podcast_manager_handle_feed_error (result->pd,
- (char *)result->channel->url,
- result->error,
- (result->automatic == FALSE));
- } else if (result->channel->is_opml) {
- GList *l;
+ RBPodcastUpdate *update = user_data;
+ GFileInfo *file_info;
+ GtkWidget *dialog;
+ char *content_type;
+ GError *error = NULL;
- rb_debug ("Loading OPML feeds from %s", result->channel->url);
+ file_info = g_file_query_info_finish (G_FILE (source_object), res, &error);
+ if (file_info == NULL) {
+ g_object_unref (source_object);
+ feed_parse_cb (update->channel, error, update);
+ return;
+ }
- for (l = result->channel->posts; l != NULL; l = l->next) {
- RBPodcastItem *item = l->data;
- /* assume the feeds don't already exist */
- rb_podcast_manager_subscribe_feed (result->pd, item->url, FALSE);
- }
+ content_type = g_file_info_get_attribute_as_string (file_info,
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
+ if (content_type != NULL
+ && strstr (content_type, "html") == NULL
+ && strstr (content_type, "xml") == NULL
+ && strstr (content_type, "rss") == NULL
+ && strstr (content_type, "opml") == NULL) {
+ dialog = gtk_message_dialog_new (NULL, 0,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ _("The URL '%s' does not appear to be a podcast feed. "
+ "It may be the wrong URL, or the feed may be broken. "
+ "Would you like Rhythmbox to attempt to use it anyway?"),
+ update->url);
+ gtk_widget_show_all (dialog);
+ g_signal_connect (dialog, "response", G_CALLBACK (confirm_bad_mime_type_response_cb), update);
+ g_clear_error (&error);
+ } else if (content_type != NULL && strstr (content_type, "opml") != NULL) {
+ update->channel->is_opml = TRUE;
+ start_feed_parse (update->pd, update);
} else {
- rb_podcast_manager_add_parsed_feed (result->pd, result->channel);
- }
- if (--result->pd->priv->updating == 0) {
- g_object_notify (G_OBJECT (result->pd), "updating");
+ start_feed_parse (update->pd, update);
}
- return FALSE;
+ g_free (content_type);
+ g_object_unref (file_info);
+ g_object_unref (source_object);
}
-static void
-confirm_bad_mime_type_response_cb (GtkDialog *dialog, int response, RBPodcastUpdate *info)
+gboolean
+rb_podcast_manager_subscribe_feed (RBPodcastManager *pd, const char *url, gboolean automatic)
{
- if (response == GTK_RESPONSE_YES) {
- /* set the 'existing feed' flag to avoid the mime type check */
- info->existing_feed = TRUE;
- g_thread_new ("podcast-parse",
- (GThreadFunc) rb_podcast_manager_thread_parse_feed,
- info);
+ RBPodcastUpdate *update;
+ RhythmDBEntry *entry;
+ GFile *feed;
+ char *feed_url;
+
+ if (g_str_has_prefix (url, "feed://") || g_str_has_prefix (url, "itpc://")) {
+ char *tmp;
+
+ tmp = g_strdup_printf ("http://%s", url + strlen ("feed://"));
+ feed = g_file_new_for_uri (tmp);
+ g_free (tmp);
} else {
- g_free (info->url);
- g_free (info);
- if (--info->pd->priv->updating == 0) {
- g_object_notify (G_OBJECT (info->pd), "updating");
- }
+ feed = g_file_new_for_uri (url);
}
- gtk_widget_destroy (GTK_WIDGET (dialog));
-}
+ feed_url = g_file_get_uri (feed);
-static gboolean
-confirm_bad_mime_type (RBPodcastUpdate *info)
-{
- GtkWidget *dialog;
- dialog = gtk_message_dialog_new (NULL, 0,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_YES_NO,
- _("The URL '%s' does not appear to be a podcast feed. "
- "It may be the wrong URL, or the feed may be broken. "
- "Would you like Rhythmbox to attempt to use it anyway?"),
- info->url);
- gtk_widget_show_all (dialog);
- g_signal_connect (dialog, "response", G_CALLBACK (confirm_bad_mime_type_response_cb), info);
- return FALSE;
-}
+ update = g_new0 (RBPodcastUpdate, 1);
+ update->pd = g_object_ref (pd);
+ update->url = feed_url;
+ update->automatic = automatic;
+ update->channel = g_new0 (RBPodcastChannel, 1);
-static gpointer
-rb_podcast_manager_thread_parse_feed (RBPodcastUpdate *info)
-{
- RBPodcastChannel *feed = g_new0 (RBPodcastChannel, 1);
- RBPodcastManagerParseResult *result;
-
- result = g_new0 (RBPodcastManagerParseResult, 1);
- result->channel = feed;
- result->pd = info->pd; /* adopts our reference */
- result->automatic = info->automatic;
-
- g_clear_error (&result->error);
-
- rb_debug ("attempting to parse feed %s", info->url);
- if (rb_podcast_parse_load_feed (feed, info->url, info->existing_feed, &result->error) == FALSE) {
- if (g_error_matches (result->error,
- RB_PODCAST_PARSE_ERROR,
- RB_PODCAST_PARSE_ERROR_MIME_TYPE)) {
- g_idle_add ((GSourceFunc) confirm_bad_mime_type, info);
- return NULL;
+ entry = rhythmdb_entry_lookup_by_location (pd->priv->db, feed_url);
+ if (entry) {
+ GValue v = {0,};
+ if (rhythmdb_entry_get_entry_type (entry) != RHYTHMDB_ENTRY_TYPE_PODCAST_FEED) {
+ /* added as something else, probably iradio */
+ rb_error_dialog (NULL, _("URL already added"),
+ _("The URL \"%s\" has already been added as a radio station. "
+ "If this is a podcast feed, please remove the radio station."), url);
+ g_object_unref (feed);
+ podcast_update_free (update);
+ return FALSE;
}
+
+ g_value_init (&v, G_TYPE_ULONG);
+ g_value_set_ulong (&v, RHYTHMDB_PODCAST_FEED_STATUS_UPDATING);
+ rhythmdb_entry_set (pd->priv->db, entry, RHYTHMDB_PROP_STATUS, &v);
+ rhythmdb_commit (pd->priv->db);
+ g_value_unset (&v);
+
+ start_feed_parse (pd, update);
+ } else if (rb_uri_could_be_podcast (feed_url, NULL)) {
+ rb_debug ("not checking mime type for %s", feed_url);
+ start_feed_parse (pd, update);
+ } else {
+ g_file_query_info_async (feed,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ 0,
+ G_PRIORITY_DEFAULT,
+ pd->priv->update_cancel,
+ mime_type_check_cb,
+ update);
}
- g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
- (GSourceFunc) rb_podcast_manager_parse_complete_cb,
- result,
- (GDestroyNotify) rb_podcast_manager_free_parse_result);
- g_free (info->url);
- g_free (info);
- return NULL;
+ g_object_unref (feed);
+ return TRUE;
}
RhythmDBEntry *
@@ -1598,45 +1615,6 @@ rb_podcast_manager_add_parsed_feed (RBPodcastManager *pd, RBPodcastChannel *data
rhythmdb_commit (db);
}
-static void
-rb_podcast_manager_handle_feed_error (RBPodcastManager *mgr,
- const char *url,
- GError *error,
- gboolean emit)
-{
- RhythmDBEntry *entry;
- GValue v = {0,};
- gboolean existing = FALSE;
-
- /* set the error in the feed entry, if one exists */
- entry = rhythmdb_entry_lookup_by_location (mgr->priv->db, url);
- if (entry != NULL && rhythmdb_entry_get_entry_type (entry) == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED) {
- g_value_init (&v, G_TYPE_STRING);
- g_value_set_string (&v, error->message);
- rhythmdb_entry_set (mgr->priv->db, entry, RHYTHMDB_PROP_PLAYBACK_ERROR, &v);
- g_value_unset (&v);
-
- g_value_init (&v, G_TYPE_ULONG);
- g_value_set_ulong (&v, RHYTHMDB_PODCAST_FEED_STATUS_NORMAL);
- rhythmdb_entry_set (mgr->priv->db, entry, RHYTHMDB_PROP_STATUS, &v);
- g_value_unset (&v);
-
- rhythmdb_commit (mgr->priv->db);
- existing = TRUE;
- }
-
- /* if this was a result of a direct user action, emit the error signal too */
- if (emit) {
- gchar *error_msg;
- error_msg = g_strdup_printf (_("There was a problem adding this podcast: %s. Please verify
the URL: %s"),
- error->message, url);
- g_signal_emit (mgr,
- rb_podcast_manager_signals[PROCESS_ERROR],
- 0, url, error_msg, existing);
- g_free (error_msg);
- }
-}
-
void
rb_podcast_manager_shutdown (RBPodcastManager *pd)
{
@@ -1644,14 +1622,14 @@ rb_podcast_manager_shutdown (RBPodcastManager *pd)
g_assert (rb_is_main_thread ());
+ g_cancellable_cancel (pd->priv->update_cancel);
+
lst = g_list_reverse (g_list_copy (pd->priv->download_list));
for (l = lst; l != NULL; l = l->next) {
RBPodcastDownload *data = (RBPodcastDownload *) l->data;
cancel_download (data);
}
g_list_free (lst);
-
- pd->priv->shutdown = TRUE;
}
char *
diff --git a/podcast/rb-podcast-manager.h b/podcast/rb-podcast-manager.h
index 14c3ee718..cf7e669b6 100644
--- a/podcast/rb-podcast-manager.h
+++ b/podcast/rb-podcast-manager.h
@@ -55,13 +55,6 @@ typedef struct
typedef struct
{
GObjectClass parent_class;
-
- /* signals */
- void (*start_download) (RBPodcastManager* pd, RhythmDBEntry *entry);
- void (*finish_download) (RBPodcastManager* pd, RhythmDBEntry *entry);
- void (*feed_updates_available) (RBPodcastManager* pd, RhythmDBEntry *entry);
- void (*process_error) (RBPodcastManager* pd, const char *url, const char
*error, gboolean existing);
-
} RBPodcastManagerClass;
GType rb_podcast_manager_get_type (void);
diff --git a/podcast/rb-podcast-parse.c b/podcast/rb-podcast-parse.c
index 0c2879abc..937f6f732 100644
--- a/podcast/rb-podcast-parse.c
+++ b/podcast/rb-podcast-parse.c
@@ -40,6 +40,12 @@
#include "rb-podcast-parse.h"
#include "rb-file-helpers.h"
+typedef struct {
+ RBPodcastChannel *channel;
+ RBPodcastParseCallback callback;
+ gpointer user_data;
+} RBPodcastParseData;
+
GQuark
rb_podcast_parse_error_quark (void)
{
@@ -148,98 +154,65 @@ entry_parsed (TotemPlParser *parser,
channel->posts = g_list_prepend (channel->posts, item);
}
-gboolean
-rb_podcast_parse_load_feed (RBPodcastChannel *data,
- const char *file_name,
- gboolean existing_feed,
- GError **error)
+static void
+parse_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- GFile *file;
- GFileInfo *fileinfo;
- TotemPlParser *plparser;
-
- data->url = g_strdup (file_name);
-
- /* if the URL has a .rss, .xml or .atom extension (before the query string),
- * don't bother checking the MIME type.
- */
- if (rb_uri_could_be_podcast (file_name, &data->is_opml) || existing_feed) {
- rb_debug ("not checking mime type for %s (should be %s file)", file_name,
- data->is_opml ? "OPML" : "Podcast");
- } else {
- GError *ferror = NULL;
- char *content_type;
-
- rb_debug ("checking mime type for %s", file_name);
-
- file = g_file_new_for_uri (file_name);
- fileinfo = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, 0, NULL, &ferror);
- if (ferror != NULL) {
- g_set_error (error,
- RB_PODCAST_PARSE_ERROR,
- RB_PODCAST_PARSE_ERROR_FILE_INFO,
- _("Unable to check file type: %s"),
- ferror->message);
- g_object_unref (file);
- g_clear_error (&ferror);
- return FALSE;
- }
+ RBPodcastParseData *data = user_data;
+ RBPodcastChannel *channel = data->channel;
+ GError *error = NULL;
- content_type = g_file_info_get_attribute_as_string (fileinfo,
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
- g_object_unref (file);
- g_object_unref (fileinfo);
-
- if (content_type != NULL
- && strstr (content_type, "html") == NULL
- && strstr (content_type, "xml") == NULL
- && strstr (content_type, "rss") == NULL
- && strstr (content_type, "opml") == NULL) {
- g_set_error (error,
- RB_PODCAST_PARSE_ERROR,
- RB_PODCAST_PARSE_ERROR_MIME_TYPE,
- _("Unexpected file type: %s"),
- content_type);
- g_free (content_type);
- return FALSE;
- } else if (content_type != NULL
- && strstr (content_type, "opml") != NULL) {
- data->is_opml = TRUE;
- }
-
- g_free (content_type);
- }
+ totem_pl_parser_parse_finish (TOTEM_PL_PARSER (source_object), res, &error);
+ if (error) {
+ rb_debug ("parsing %s as a podcast failed: %s", channel->url, error->message);
+ g_clear_error (&error);
- plparser = totem_pl_parser_new ();
- g_object_set (plparser, "recurse", FALSE, "force", TRUE, NULL);
- g_signal_connect (G_OBJECT (plparser), "entry-parsed", G_CALLBACK (entry_parsed), data);
- g_signal_connect (G_OBJECT (plparser), "playlist-started", G_CALLBACK (playlist_started), data);
- g_signal_connect (G_OBJECT (plparser), "playlist-ended", G_CALLBACK (playlist_ended), data);
-
- if (totem_pl_parser_parse (plparser, file_name, FALSE) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
- rb_debug ("Parsing %s as a Podcast failed", file_name);
- g_set_error (error,
+ g_set_error (&error,
RB_PODCAST_PARSE_ERROR,
RB_PODCAST_PARSE_ERROR_XML_PARSE,
_("Unable to parse the feed contents"));
- g_object_unref (plparser);
- return FALSE;
- }
- g_object_unref (plparser);
-
- /* treat empty feeds, or feeds that don't contain any downloadable items, as
- * an error.
- */
- if (data->posts == NULL) {
- rb_debug ("Parsing %s as a podcast succeeded, but the feed contains no downloadable items",
file_name);
- g_set_error (error,
+ } else if (channel->posts == NULL) {
+ /*
+ * treat empty feeds, or feeds that don't contain any downloadable items, as
+ * an error.
+ */
+ rb_debug ("parsing %s as a podcast succeeded, but the feed contains no downloadable items",
channel->url);
+ g_set_error (&error,
RB_PODCAST_PARSE_ERROR,
RB_PODCAST_PARSE_ERROR_NO_ITEMS,
_("The feed does not contain any downloadable items"));
- return FALSE;
+ } else {
+ rb_debug ("parsing %s as a podcast succeeded", channel->url);
}
- rb_debug ("Parsing %s as a Podcast succeeded", file_name);
- return TRUE;
+ data->callback (channel, error, data->user_data);
+ g_object_unref (source_object);
+ g_free (data);
+}
+
+void
+rb_podcast_parse_load_feed (RBPodcastChannel *channel,
+ const char *feed_url,
+ GCancellable *cancellable,
+ RBPodcastParseCallback callback,
+ gpointer user_data)
+{
+ TotemPlParser *plparser;
+ RBPodcastParseData *data;
+
+ channel->url = g_strdup (feed_url);
+
+ data = g_new0 (RBPodcastParseData, 1);
+ data->channel = channel;
+ data->callback = callback;
+ data->user_data = user_data;
+
+ plparser = totem_pl_parser_new ();
+ g_object_set (plparser, "recurse", FALSE, "force", TRUE, NULL);
+ g_signal_connect (plparser, "entry-parsed", G_CALLBACK (entry_parsed), channel);
+ g_signal_connect (plparser, "playlist-started", G_CALLBACK (playlist_started), channel);
+ g_signal_connect (plparser, "playlist-ended", G_CALLBACK (playlist_ended), channel);
+
+ totem_pl_parser_parse_async (plparser, channel->url, FALSE, cancellable, parse_cb, data);
}
RBPodcastChannel *
diff --git a/podcast/rb-podcast-parse.h b/podcast/rb-podcast-parse.h
index abe85a5d8..7b6d8b3f1 100644
--- a/podcast/rb-podcast-parse.h
+++ b/podcast/rb-podcast-parse.h
@@ -29,6 +29,7 @@
#define RB_PODCAST_PARSE_H
#include <glib.h>
+#include <gio/gio.h>
typedef enum
{
@@ -75,10 +76,13 @@ GType rb_podcast_item_get_type (void);
#define RB_TYPE_PODCAST_CHANNEL (rb_podcast_channel_get_type ())
#define RB_TYPE_PODCAST_ITEM (rb_podcast_item_get_type ())
-gboolean rb_podcast_parse_load_feed (RBPodcastChannel *data,
- const char *url,
- gboolean existing_feed,
- GError **error);
+typedef void (*RBPodcastParseCallback) (RBPodcastChannel *data, GError *error, gpointer user_data);
+
+void rb_podcast_parse_load_feed (RBPodcastChannel *data,
+ const char *url,
+ GCancellable *cancellable,
+ RBPodcastParseCallback callback,
+ gpointer user_data);
RBPodcastChannel *rb_podcast_parse_channel_copy (RBPodcastChannel *data);
RBPodcastItem *rb_podcast_parse_item_copy (RBPodcastItem *data);
diff --git a/podcast/test-podcast-parse.c b/podcast/test-podcast-parse.c
index 0ad8c37f8..07458c03d 100644
--- a/podcast/test-podcast-parse.c
+++ b/podcast/test-podcast-parse.c
@@ -66,39 +66,30 @@ rb_debug_realf (const char *func,
file, line, func, buffer);
}
-int main (int argc, char **argv)
+static void
+parse_cb (RBPodcastChannel *channel, GError *error, gpointer user_data)
{
- RBPodcastChannel *data;
+ GMainLoop *ml = user_data;
GList *l;
GDate date = {0,};
char datebuf[1024];
- GError *error = NULL;
-
- setlocale (LC_ALL, "");
- bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-
- if (argv[2] != NULL && strcmp (argv[2], "--debug") == 0) {
- debug = TRUE;
- }
- data = g_new0 (RBPodcastChannel, 1);
- if (rb_podcast_parse_load_feed (data, argv[1], FALSE, &error) == FALSE) {
- g_warning ("Couldn't parse %s: %s", argv[1], error->message);
- g_clear_error (&error);
- return 1;
+ if (error) {
+ g_warning ("Couldn't parse %s: %s", channel->url, error->message);
+ g_main_loop_quit (ml);
+ return;
}
- g_date_set_time_t (&date, data->pub_date);
+ g_date_set_time_t (&date, channel->pub_date);
g_date_strftime (datebuf, 1024, "%F %T", &date);
- g_print ("Podcast title: %s\n", data->title);
- g_print ("Description: %s\n", data->description);
- g_print ("Author: %s\n", data->author);
+ g_print ("Podcast title: %s\n", channel->title);
+ g_print ("Description: %s\n", channel->description);
+ g_print ("Author: %s\n", channel->author);
g_print ("Date: %s\n", datebuf);
g_print ("\n");
- for (l = data->posts; l != NULL; l = l->next) {
+ for (l = channel->posts; l != NULL; l = l->next) {
RBPodcastItem *item = l->data;
g_date_set_time_t (&date, item->pub_date);
@@ -112,6 +103,29 @@ int main (int argc, char **argv)
g_print ("\n");
}
+ g_main_loop_quit (ml);
+}
+
+int
+main (int argc, char **argv)
+{
+ RBPodcastChannel *data;
+ GMainLoop *ml;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ if (argv[2] != NULL && strcmp (argv[2], "--debug") == 0) {
+ debug = TRUE;
+ }
+
+ ml = g_main_loop_new (NULL, FALSE);
+ data = g_new0 (RBPodcastChannel, 1);
+ rb_podcast_parse_load_feed (data, argv[1], NULL, parse_cb, ml);
+
+ g_main_loop_run (ml);
+
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]