[rhythmbox] podcast: use g_file_input_stream_query_info for downloads (bug #596615)



commit dfc275f6f276d2d566025c862d057f65e2397d32
Author: Robert Ancell <robert ancell canonical com>
Date:   Sat Apr 10 22:43:04 2010 +1000

    podcast: use g_file_input_stream_query_info for downloads (bug #596615)
    
    Where it works (depends on gvfs version), this means we only use a
    single HTTP request for podcast downloads, rather than one to get the
    filename and size and a second to download it.  Aside from being more
    efficient, this also helps in cases where the server doesn't deal with
    HEAD requests properly.

 podcast/rb-podcast-manager.c |  135 ++++++++++++++++++++++++++----------------
 1 files changed, 84 insertions(+), 51 deletions(-)
---
diff --git a/podcast/rb-podcast-manager.c b/podcast/rb-podcast-manager.c
index fd11fb3..f2d8daa 100644
--- a/podcast/rb-podcast-manager.c
+++ b/podcast/rb-podcast-manager.c
@@ -148,9 +148,14 @@ static void rb_podcast_manager_get_property 		(GObject *object,
 							 guint prop_id,
 		                                	 GValue *value,
                 		                	 GParamSpec *pspec);
+static void read_file_cb				(GFile *source,
+							 GAsyncResult *result,
+							 RBPodcastManagerInfo *data);
 static void download_file_info_cb			(GFile *source,
 							 GAsyncResult *result,
 							 RBPodcastManagerInfo *data);
+static void download_podcast				(GFileInfo *src_info,
+							 RBPodcastManagerInfo *data);
 static void rb_podcast_manager_abort_download		(RBPodcastManagerInfo *data);
 static gboolean rb_podcast_manager_sync_head_cb 	(gpointer data);
 static gboolean rb_podcast_manager_head_query_cb 	(GtkTreeModel *query_model,
@@ -617,7 +622,12 @@ download_error (RBPodcastManagerInfo *data, GError *error)
 	}
 
 	rhythmdb_commit (data->pd->priv->db);
-	g_idle_add ((GSourceFunc)end_job, data);
+
+	if (rb_is_main_thread() == FALSE) {
+		g_idle_add ((GSourceFunc)end_job, data);
+	} else {
+		rb_podcast_manager_abort_download (data);
+	}
 }
 
 static gboolean
@@ -626,7 +636,6 @@ rb_podcast_manager_next_file (RBPodcastManager * pd)
 	const char *location;
 	RBPodcastManagerInfo *data;
 	char *query_string;
-	const char *attrs;
 	GList *d;
 
 	g_assert (rb_is_main_thread ());
@@ -670,69 +679,101 @@ rb_podcast_manager_next_file (RBPodcastManager * pd)
 
 	data->source = g_file_new_for_uri (location);
 
-	attrs = G_FILE_ATTRIBUTE_STANDARD_SIZE ","
-		G_FILE_ATTRIBUTE_STANDARD_COPY_NAME ","
-		G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME;
-	g_file_query_info_async (data->source,
-				 attrs,
-				 G_FILE_QUERY_INFO_NONE,
-				 0,
-				 data->cancel,
-				 (GAsyncReadyCallback) download_file_info_cb,
-				 data);
+	g_file_read_async (data->source,
+	                   0,
+	                   data->cancel,
+	                   (GAsyncReadyCallback) read_file_cb,
+	                   data);
 
 	GDK_THREADS_LEAVE ();
 	return FALSE;
 }
 
 static void
-download_file_info_cb (GFile *source,
-		       GAsyncResult *result,
-		       RBPodcastManagerInfo *data)
+read_file_cb (GFile *source,
+              GAsyncResult *result,
+              RBPodcastManagerInfo *data)
 {
 	GError *error = NULL;
 	GFileInfo *src_info;
-	char *local_file_name = NULL;
-	char *feed_folder;
-	char *esc_local_file_name;
-	char *local_file_uri;
-	char *sane_local_file_uri;
-	char *conf_dir_uri;
 
 	g_assert (rb_is_main_thread ());
 
-	rb_debug ("got file info results for %s",
+	rb_debug ("started read for %s",
 		  get_remote_location (data->entry));
 
-	src_info = g_file_query_info_finish (source, result, &error);
+	data->in_stream = g_file_read_finish (data->source,
+	                                      result,
+	                                      &error);
+	if (error != NULL) {
+		download_error (data, error);
+		g_error_free (error);
+		return;
+	}
+
+	src_info = g_file_input_stream_query_info (data->in_stream,
+	                                           G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+	                                           G_FILE_ATTRIBUTE_STANDARD_COPY_NAME ","
+	                                           G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME,
+	                                           NULL,
+	                                           &error);
 
-	/* ignore G_IO_ERROR_FAILED here, as it probably just means that the server is lame.
-	 * actual problems (not found, permission denied, etc.) have specific errors codes,
-	 * so they'll still be reported.
+	/* If no stream information then probably using an old version of gvfs, fall back
+	 * to getting the stream information from the GFile.
 	 */
-	if (error != NULL && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED) == FALSE) {
-		GValue val = {0,};
+	if (error != NULL) {
+		rb_debug ("file info query from input failed, trying query on file: %s", error->message);
+		g_error_free (error);
 
-		rb_debug ("file info query failed: %s", error->message);
+		g_file_query_info_async (data->source,
+		                         G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+		                         G_FILE_ATTRIBUTE_STANDARD_COPY_NAME ","
+		                         G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME,
+		                         G_FILE_QUERY_INFO_NONE,
+		                         0,
+		                         data->cancel,
+		                         (GAsyncReadyCallback) download_file_info_cb,
+		                         data);
+		return;
+	}
 
-		g_value_init (&val, G_TYPE_ULONG);
-		g_value_set_ulong (&val, RHYTHMDB_PODCAST_STATUS_ERROR);
-		rhythmdb_entry_set (data->pd->priv->db, data->entry, RHYTHMDB_PROP_STATUS, &val);
-		g_value_unset (&val);
+	rb_debug ("got file info results for %s",
+		  get_remote_location (data->entry));
 
-		g_value_init (&val, G_TYPE_STRING);
-		g_value_set_string (&val, error->message);
-		rhythmdb_entry_set (data->pd->priv->db, data->entry, RHYTHMDB_PROP_PLAYBACK_ERROR, &val);
-		g_value_unset (&val);
+	download_podcast (src_info, data);
+}
 
-		rhythmdb_commit (data->pd->priv->db);
+static void
+download_file_info_cb (GFile *source,
+                       GAsyncResult *result,
+                       RBPodcastManagerInfo *data)
+{
+	GError *error = NULL;
+	GFileInfo *src_info;
 
+	src_info = g_file_query_info_finish (source, result, &error);
+
+	if (error != NULL) {
+		download_error (data, error);
 		g_error_free (error);
-		rb_podcast_manager_abort_download (data);
-		return;
 	} else {
-		g_clear_error (&error);
+		rb_debug ("got file info results for %s",
+			  get_remote_location (data->entry));
+
+		download_podcast (src_info, data);
 	}
+}
+
+static void
+download_podcast (GFileInfo *src_info, RBPodcastManagerInfo *data)
+{
+	GError *error = NULL;
+	char *local_file_name = NULL;
+	char *feed_folder;
+	char *esc_local_file_name;
+	char *local_file_uri;
+	char *sane_local_file_uri;
+	char *conf_dir_uri;
 
 	if (src_info != NULL) {
 		data->download_size = g_file_info_get_attribute_uint64 (src_info, G_FILE_ATTRIBUTE_STANDARD_SIZE);
@@ -750,7 +791,7 @@ download_file_info_cb (GFile *source,
 
 	if (local_file_name == NULL) {
 		/* fall back to the basename from the original URI */
-		local_file_name = g_file_get_basename (source);
+		local_file_name = g_file_get_basename (data->source);
 		rb_debug ("didn't get a filename from the file info request; using basename %s", local_file_name);
 	}
 
@@ -800,7 +841,6 @@ download_file_info_cb (GFile *source,
 		return;
 	}
 
-
 	data->destination = g_file_new_for_uri (sane_local_file_uri);
 	if (g_file_query_exists (data->destination, NULL)) {
 		GFileInfo *dest_info;
@@ -1415,14 +1455,6 @@ podcast_download_thread (RBPodcastManagerInfo *data)
 	gssize n_read;
 	gssize n_written;
 	guint64 downloaded;
-	
-	/* open remote file */
-	data->in_stream = g_file_read (data->source, data->cancel, &error);
-	if (error != NULL) {
-		download_error (data, error);
-		g_error_free (error);
-		return NULL;
-	}
 
 	/* if we have an offset to download from, try the seek
 	 * before anything else.  if we can't seek, we'll have to
@@ -1545,6 +1577,7 @@ podcast_download_thread (RBPodcastManagerInfo *data)
 
 	if (error != NULL) {
 		download_error (data, error);
+		g_error_free (error);
 	} else {
 		download_progress (data, downloaded, data->download_size, TRUE);
 	}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]