[libgdata] youtube: Switch to a stream-based upload API
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgdata] youtube: Switch to a stream-based upload API
- Date: Fri, 10 Dec 2010 17:54:27 +0000 (UTC)
commit 5a6637eb4ba66265a7f698d8bbae4a3f5b6a30a5
Author: Philip Withnall <philip tecnocode co uk>
Date: Fri Dec 10 17:13:33 2010 +0000
youtube: Switch to a stream-based upload API
For similar reasons as the Documents service's switch to a stream-based
upload and download API, it makes sense to switch the YouTube service to a
stream-based upload API. This gives us more flexibility as to the source of
uploaded data.
The test suite has been updated appropriately.
The following API has been changed:
â?¢ gdata_youtube_service_upload_video()
The following API has been removed:
â?¢ gdata_youtube_service_upload_video_async()
â?¢ gdata_youtube_service_upload_video_finish()
The following API has been added:
â?¢ gdata_youtube_service_finish_video_upload()
docs/reference/gdata-sections.txt | 3 +-
gdata/gdata.symbols | 5 +-
gdata/services/youtube/gdata-youtube-service.c | 248 ++++--------------------
gdata/services/youtube/gdata-youtube-service.h | 9 +-
gdata/tests/youtube.c | 100 +++++++++-
5 files changed, 136 insertions(+), 229 deletions(-)
---
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 071218a..3b4ed92 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -188,8 +188,7 @@ gdata_youtube_service_query_related_async
gdata_youtube_service_query_standard_feed
gdata_youtube_service_query_standard_feed_async
gdata_youtube_service_upload_video
-gdata_youtube_service_upload_video_async
-gdata_youtube_service_upload_video_finish
+gdata_youtube_service_finish_video_upload
gdata_youtube_service_get_categories
gdata_youtube_service_get_categories_async
gdata_youtube_service_get_categories_finish
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index 7d65b16..5c12768 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -109,7 +109,6 @@ gdata_youtube_service_query_videos
gdata_youtube_service_query_videos_async
gdata_youtube_service_query_related
gdata_youtube_service_query_related_async
-gdata_youtube_service_upload_video
gdata_youtube_service_get_developer_key
gdata_youtube_video_get_type
gdata_youtube_video_new
@@ -842,8 +841,6 @@ gdata_contacts_service_query_groups
gdata_contacts_service_query_groups_async
gdata_contacts_service_insert_group
gdata_contacts_service_insert_group_async
-gdata_youtube_service_upload_video_async
-gdata_youtube_service_upload_video_finish
gdata_picasaweb_service_insert_album_async
gdata_picasaweb_service_query_files_async
gdata_documents_service_finish_upload
@@ -855,3 +852,5 @@ gdata_documents_service_remove_entry_from_folder_async
gdata_documents_service_remove_entry_from_folder_finish
gdata_picasaweb_service_upload_file
gdata_picasaweb_service_finish_file_upload
+gdata_youtube_service_upload_video
+gdata_youtube_service_finish_video_upload
diff --git a/gdata/services/youtube/gdata-youtube-service.c b/gdata/services/youtube/gdata-youtube-service.c
index ec59191..bd75b23 100644
--- a/gdata/services/youtube/gdata-youtube-service.c
+++ b/gdata/services/youtube/gdata-youtube-service.c
@@ -596,76 +596,36 @@ gdata_youtube_service_query_related_async (GDataYouTubeService *self, GDataYouTu
GDATA_TYPE_YOUTUBE_VIDEO, cancellable, progress_callback, progress_user_data, callback, user_data);
}
-static GOutputStream *
-get_file_output_stream (GDataYouTubeService *self, GDataYouTubeVideo *video_entry, GFile *video_data, GError **error)
-{
- GFileInfo *file_info = NULL;
- const gchar *slug = NULL, *content_type = NULL;
- GOutputStream *output_stream;
-
- file_info = g_file_query_info (video_data, "standard::display-name,standard::content-type", G_FILE_QUERY_INFO_NONE, NULL, error);
- if (file_info == NULL)
- return NULL;
-
- slug = g_file_info_get_display_name (file_info);
- content_type = g_file_info_get_content_type (file_info);
-
- /* Streaming upload support using GDataUploadStream; automatically handles the XML and multipart stuff for us */
- output_stream = gdata_upload_stream_new (GDATA_SERVICE (self), SOUP_METHOD_POST,
- "http://uploads.gdata.youtube.com/feeds/api/users/default/uploads",
- GDATA_ENTRY (video_entry), slug, content_type);
- g_object_unref (file_info);
-
- return output_stream;
-}
-
-static GDataYouTubeVideo *
-parse_spliced_stream (GOutputStream *output_stream, GError **error)
-{
- const gchar *response_body;
- gssize response_length;
- GDataYouTubeVideo *new_entry;
-
- /* Get the response from the server */
- response_body = gdata_upload_stream_get_response (GDATA_UPLOAD_STREAM (output_stream), &response_length);
- g_assert (response_body != NULL && response_length > 0);
-
- /* Parse the response to produce a GDataPicasaWebFile */
- new_entry = GDATA_YOUTUBE_VIDEO (gdata_parsable_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO, response_body, (gint) response_length, error));
-
- return new_entry;
-}
-
/**
* gdata_youtube_service_upload_video:
* @self: a #GDataYouTubeService
* @video: a #GDataYouTubeVideo to insert
- * @video_file: the video file to upload
- * @cancellable: optional #GCancellable object, or %NULL
+ * @slug: the filename to give to the uploaded file
+ * @content_type: the content type of the uploaded data
* @error: a #GError, or %NULL
*
- * Uploads a video to YouTube, using the properties from @video and the video file pointed to by @video_file.
+ * Uploads a video to YouTube, using the properties from @video and the file data written to the resulting #GDataUploadStream.
*
* If @video has already been inserted, a %GDATA_SERVICE_ERROR_ENTRY_ALREADY_INSERTED error will be returned. If no user is authenticated
* with the service, %GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED will be returned.
*
- * If there is a problem reading @video_file, an error from g_file_load_contents() or g_file_query_info() will be returned. Other errors from
- * #GDataServiceError can be returned for other exceptional conditions, as determined by the server.
+ * The stream returned by this function should be written to using the standard #GOutputStream methods, asychronously or synchronously. Once the stream
+ * is closed (using g_output_stream_close()), gdata_youtube_service_finish_video_upload() should be called on it to parse and return the updated
+ * #GDataYouTubeVideo for the uploaded video. This must be done, as @video isn't updated in-place.
+ *
+ * Any upload errors will be thrown by the stream methods, and may come from the #GDataServiceError domain.
+ *
+ * Return value: (transfer full): a #GDataUploadStream to write the video data to, or %NULL; unref with g_object_unref()
*
- * Return value: (transfer full): the inserted #GDataYouTubeVideo with updated properties from @video; unref with g_object_unref()
+ * Since: 0.8.0
**/
-GDataYouTubeVideo *
-gdata_youtube_service_upload_video (GDataYouTubeService *self, GDataYouTubeVideo *video, GFile *video_file, GCancellable *cancellable, GError **error)
+GDataUploadStream *
+gdata_youtube_service_upload_video (GDataYouTubeService *self, GDataYouTubeVideo *video, const gchar *slug, const gchar *content_type, GError **error)
{
- GDataYouTubeVideo *new_entry;
- GOutputStream *output_stream;
- GInputStream *input_stream;
- GError *child_error = NULL;
-
g_return_val_if_fail (GDATA_IS_YOUTUBE_SERVICE (self), NULL);
g_return_val_if_fail (GDATA_IS_YOUTUBE_VIDEO (video), NULL);
- g_return_val_if_fail (G_IS_FILE (video_file), NULL);
- g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (slug != NULL && *slug != '\0', NULL);
+ g_return_val_if_fail (content_type != NULL && *content_type != '\0', NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (gdata_entry_is_inserted (GDATA_ENTRY (video)) == TRUE) {
@@ -680,181 +640,45 @@ gdata_youtube_service_upload_video (GDataYouTubeService *self, GDataYouTubeVideo
return NULL;
}
- output_stream = get_file_output_stream (self, video, video_file, error);
- if (output_stream == NULL)
- return NULL;
-
- /* Open the video file for reading */
- input_stream = G_INPUT_STREAM (g_file_read (video_file, cancellable, error));
- if (input_stream == NULL) {
- g_object_unref (output_stream);
- return NULL;
- }
-
- /* Splice the streams to upload the file and metadata */
- g_output_stream_splice (output_stream, input_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
- cancellable, &child_error);
-
- g_object_unref (input_stream);
- if (child_error != NULL) {
- g_object_unref (output_stream);
- g_propagate_error (error, child_error);
- return NULL;
- }
-
- new_entry = parse_spliced_stream (output_stream, error);
- g_object_unref (output_stream);
-
- return new_entry;
+ /* Streaming upload support using GDataUploadStream; automatically handles the XML and multipart stuff for us */
+ return GDATA_UPLOAD_STREAM (gdata_upload_stream_new (GDATA_SERVICE (self), SOUP_METHOD_POST,
+ "http://uploads.gdata.youtube.com/feeds/api/users/default/uploads",
+ GDATA_ENTRY (video), slug, content_type));
}
/**
- * gdata_youtube_service_upload_video_finish:
+ * gdata_youtube_service_finish_video_upload:
* @self: a #GDataYouTubeService
- * @result: a #GSimpleAsyncResult
+ * @upload_stream: the #GDataUploadStream from the operation
* @error: a #GError, or %NULL
*
- * This should be called to obtain the result of a call to gdata_youtube_service_upload_video_async() and to check for errors.
+ * Finish off a video upload operation started by gdata_youtube_service_upload_video(), parsing the result and returning the new #GDataYouTubeVideo.
*
- * If there is a problem reading the subect file's data, an error from g_output_stream_splice() or g_file_query_info() will be returned. Other errors
- * from #GDataServiceError can be returned for other exceptional conditions, as determined by the server.
+ * If an error occurred during the upload operation, it will have been returned during the operation (e.g. by g_output_stream_splice() or one
+ * of the other stream methods). In such a case, %NULL will be returned but @error will remain unset. @error is only set in the case that the server
+ * indicates that the operation was successful, but an error is encountered in parsing the result sent by the server.
*
- * If the video to upload has already been inserted, a %GDATA_SERVICE_ERROR_ENTRY_ALREADY_INSERTED error will be set. If no user is authenticated with
- * the service when trying to upload it, %GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED will be set.
- *
- * Return value: (transfer full): the inserted #GDataYouTubeVideo; unref with g_object_unref()
+ * Return value: (transfer full): the new #GDataYouTubeVideo, or %NULL; unref with g_object_unref()
*
* Since: 0.8.0
*/
GDataYouTubeVideo *
-gdata_youtube_service_upload_video_finish (GDataYouTubeService *self, GAsyncResult *result, GError **error)
+gdata_youtube_service_finish_video_upload (GDataYouTubeService *self, GDataUploadStream *upload_stream, GError **error)
{
+ const gchar *response_body;
+ gssize response_length;
+
g_return_val_if_fail (GDATA_IS_YOUTUBE_SERVICE (self), NULL);
- g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+ g_return_val_if_fail (GDATA_IS_UPLOAD_STREAM (upload_stream), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+ /* Get the response from the server */
+ response_body = gdata_upload_stream_get_response (upload_stream, &response_length);
+ if (response_body == NULL || response_length == 0)
return NULL;
- g_assert (gdata_youtube_service_upload_video_async == g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result)));
-
- return GDATA_YOUTUBE_VIDEO (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)));
-}
-
-typedef struct {
- GDataYouTubeService *service;
- GAsyncReadyCallback callback;
- gpointer user_data;
-} UploadVideoAsyncData;
-
-static void
-upload_video_async_data_free (UploadVideoAsyncData *data)
-{
- g_object_unref (data->service);
- g_slice_free (UploadVideoAsyncData, data);
-}
-
-static void
-upload_video_async_cb (GOutputStream *output_stream, GAsyncResult *result, UploadVideoAsyncData *data)
-{
- GError *error = NULL;
- GDataYouTubeVideo *video = NULL;
- GSimpleAsyncResult *async_result;
-
- g_output_stream_splice_finish (output_stream, result, &error);
-
- /* If we're error free, parse the file from the stream */
- if (error == NULL)
- video = parse_spliced_stream (output_stream, &error);
-
- if (error == NULL && video != NULL) {
- async_result = g_simple_async_result_new (G_OBJECT (data->service), (GAsyncReadyCallback) data->callback,
- data->user_data, gdata_youtube_service_upload_video_async);
- } else {
- async_result = g_simple_async_result_new_from_error (G_OBJECT (data->service), (GAsyncReadyCallback) data->callback,
- data->user_data, error);
- }
-
- g_simple_async_result_set_op_res_gpointer (async_result, video, NULL);
-
- g_simple_async_result_complete (async_result);
-
- upload_video_async_data_free (data);
-}
-
-/**
- * gdata_youtube_service_upload_video_async:
- * @self: a #GDataYouTubeService
- * @video_entry: a #GDataYouTubeVideo to insert
- * @video_data: the actual file to upload
- * @cancellable: optional #GCancellable object, or %NULL
- * @callback: a #GAsyncReadyCallback to call when the upload is finished
- * @user_data: (closure): data to pass to the @callback function
- *
- * Uploads a video to YouTube asynchronously, using the @video_data from disk and the metadata from @video_entry. A user must be authenticated to use
- * this function. Note that uploaded videos aren't publicly visible on YouTube immediately; they need to go through a moderation queue first.
- *
- * @callback should call gdata_youtube_service_upload_video_finish() to obtain a #GDataYouTubeVideo representing the uploaded video and check for
- * possible errors.
- *
- * Since: 0.8.0
- **/
-void
-gdata_youtube_service_upload_video_async (GDataYouTubeService *self, GDataYouTubeVideo *video_entry, GFile *video_data, GCancellable *cancellable,
- GAsyncReadyCallback callback, gpointer user_data)
-{
- GOutputStream *output_stream;
- GInputStream *input_stream;
- UploadVideoAsyncData *data;
- GSimpleAsyncResult *result;
- GError *error = NULL;
-
- g_return_if_fail (GDATA_IS_YOUTUBE_SERVICE (self));
- g_return_if_fail (GDATA_IS_YOUTUBE_VIDEO (video_entry));
- g_return_if_fail (G_IS_FILE (video_data));
- g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
-
- if (gdata_entry_is_inserted (GDATA_ENTRY (video_entry)) == TRUE) {
- g_set_error_literal (&error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_ENTRY_ALREADY_INSERTED,
- _("The entry has already been inserted."));
- goto error;
- }
-
- if (gdata_service_is_authenticated (GDATA_SERVICE (self)) == FALSE) {
- g_set_error_literal (&error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
- _("You must be authenticated to upload a video."));
- goto error;
- }
-
- /* Prepare and retrieve a #GDataOutputStream for the file and its data */
- output_stream = get_file_output_stream (self, video_entry, video_data, &error);
- if (output_stream == NULL)
- goto error;
-
- /* Pipe the input file to the upload stream */
- input_stream = G_INPUT_STREAM (g_file_read (video_data, cancellable, &error));
- if (input_stream == NULL) {
- g_object_unref (output_stream);
- goto error;
- }
-
- data = g_slice_new (UploadVideoAsyncData);
- data->service = g_object_ref (self);
- data->callback = callback;
- data->user_data = user_data;
-
- /* Actually transfer the data */
- g_output_stream_splice_async (output_stream, input_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
- 0, cancellable, (GAsyncReadyCallback) upload_video_async_cb, data);
-
- g_object_unref (input_stream);
- g_object_unref (output_stream);
-
- return;
-
-error:
- result = g_simple_async_result_new_from_error (G_OBJECT (self), callback, user_data, error);
- g_simple_async_result_complete (result);
+ /* Parse the response to produce a GDataYouTubeVideo */
+ return GDATA_YOUTUBE_VIDEO (gdata_parsable_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO, response_body, (gint) response_length, error));
}
/**
diff --git a/gdata/services/youtube/gdata-youtube-service.h b/gdata/services/youtube/gdata-youtube-service.h
index 5a7ba58..5268640 100644
--- a/gdata/services/youtube/gdata-youtube-service.h
+++ b/gdata/services/youtube/gdata-youtube-service.h
@@ -25,6 +25,7 @@
#include <libsoup/soup.h>
#include <gdata/gdata-service.h>
+#include <gdata/gdata-upload-stream.h>
#include <gdata/services/youtube/gdata-youtube-video.h>
#include <gdata/app/gdata-app-categories.h>
@@ -131,11 +132,9 @@ void gdata_youtube_service_query_related_async (GDataYouTubeService *self, GData
GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
GAsyncReadyCallback callback, gpointer user_data);
-GDataYouTubeVideo *gdata_youtube_service_upload_video (GDataYouTubeService *self, GDataYouTubeVideo *video, GFile *video_file,
- GCancellable *cancellable, GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-void gdata_youtube_service_upload_video_async (GDataYouTubeService *self, GDataYouTubeVideo *video_entry, GFile *video_data,
- GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-GDataYouTubeVideo *gdata_youtube_service_upload_video_finish (GDataYouTubeService *self, GAsyncResult *result,
+GDataUploadStream *gdata_youtube_service_upload_video (GDataYouTubeService *self, GDataYouTubeVideo *video, const gchar *slug,
+ const gchar *content_type, GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+GDataYouTubeVideo *gdata_youtube_service_finish_video_upload (GDataYouTubeService *self, GDataUploadStream *upload_stream,
GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
const gchar *gdata_youtube_service_get_developer_key (GDataYouTubeService *self) G_GNUC_PURE;
diff --git a/gdata/tests/youtube.c b/gdata/tests/youtube.c
index daa5bc5..43c2ec0 100644
--- a/gdata/tests/youtube.c
+++ b/gdata/tests/youtube.c
@@ -259,16 +259,24 @@ test_query_related_async (gconstpointer service)
}
typedef struct {
+ GDataYouTubeService *service;
GDataYouTubeVideo *video;
GDataYouTubeVideo *updated_video;
GFile *video_file;
+ gchar *slug;
+ gchar *content_type;
+ GFileInputStream *file_stream;
} UploadData;
static void
setup_upload (UploadData *data, gconstpointer service)
{
GDataMediaCategory *category;
+ GFileInfo *file_info;
const gchar * const tags[] = { "toast", "wedding", NULL };
+ GError *error = NULL;
+
+ data->service = g_object_ref ((gpointer) service);
/* Create the metadata for the video being uploaded */
data->video = gdata_youtube_video_new (NULL);
@@ -283,6 +291,22 @@ setup_upload (UploadData *data, gconstpointer service)
/* Get a file to upload */
/* TODO: fix the path */
data->video_file = g_file_new_for_path (TEST_FILE_DIR "sample.ogg");
+
+ /* Get the file's info */
+ file_info = g_file_query_info (data->video_file, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ G_FILE_QUERY_INFO_NONE, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (G_IS_FILE_INFO (file_info));
+
+ data->slug = g_strdup (g_file_info_get_display_name (file_info));
+ data->content_type = g_strdup (g_file_info_get_content_type (file_info));
+
+ g_object_unref (file_info);
+
+ /* Get an input stream for the file */
+ data->file_stream = g_file_read (data->video_file, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (G_IS_FILE_INPUT_STREAM (data->file_stream));
}
static void
@@ -296,19 +320,49 @@ teardown_upload (UploadData *data, gconstpointer service)
g_object_unref (data->video);
g_object_unref (data->video_file);
+ g_free (data->slug);
+ g_free (data->content_type);
+ g_object_unref (data->file_stream);
+ g_object_unref (data->service);
}
static void
test_upload_simple (UploadData *data, gconstpointer service)
{
+ GDataUploadStream *upload_stream;
+ const gchar * const *tags, * const *tags2;
+ gssize transfer_size;
GError *error = NULL;
+ /* Prepare the upload stream */
+ upload_stream = gdata_youtube_service_upload_video (GDATA_YOUTUBE_SERVICE (service), data->video, data->slug, data->content_type, &error);
+ g_assert_no_error (error);
+ g_assert (GDATA_IS_UPLOAD_STREAM (upload_stream));
+
/* Upload the video */
- data->updated_video = gdata_youtube_service_upload_video (GDATA_YOUTUBE_SERVICE (service), data->video, data->video_file, NULL, &error);
+ transfer_size = g_output_stream_splice (G_OUTPUT_STREAM (upload_stream), G_INPUT_STREAM (data->file_stream),
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (transfer_size, >, 0);
+
+ /* Finish off the upload */
+ data->updated_video = gdata_youtube_service_finish_video_upload (GDATA_YOUTUBE_SERVICE (service), upload_stream, &error);
g_assert_no_error (error);
g_assert (GDATA_IS_YOUTUBE_VIDEO (data->updated_video));
- /* TODO: check entries and feed properties */
+ /* Check the video's properties */
+ g_assert (gdata_entry_is_inserted (GDATA_ENTRY (data->updated_video)));
+ g_assert_cmpstr (gdata_entry_get_title (GDATA_ENTRY (data->updated_video)), ==, gdata_entry_get_title (GDATA_ENTRY (data->video)));
+ g_assert_cmpstr (gdata_youtube_video_get_description (data->updated_video), ==, gdata_youtube_video_get_description (data->video));
+ g_assert_cmpstr (gdata_media_category_get_category (gdata_youtube_video_get_category (data->updated_video)), ==,
+ gdata_media_category_get_category (gdata_youtube_video_get_category (data->video)));
+
+ tags = gdata_youtube_video_get_keywords (data->video);
+ tags2 = gdata_youtube_video_get_keywords (data->updated_video);
+ g_assert_cmpuint (g_strv_length ((gchar**) tags2), ==, g_strv_length ((gchar**) tags));
+ g_assert_cmpstr (tags2[0], ==, tags[0]);
+ g_assert_cmpstr (tags2[1], ==, tags[1]);
+ g_assert_cmpstr (tags2[2], ==, tags[2]);
}
typedef struct {
@@ -331,15 +385,35 @@ teardown_upload_async (UploadAsyncData *data, gconstpointer service)
}
static void
-test_upload_async_cb (GDataService *service, GAsyncResult *async_result, UploadAsyncData *data)
+test_upload_async_cb (GOutputStream *stream, GAsyncResult *result, UploadAsyncData *data)
{
+ const gchar * const *tags, * const *tags2;
+ gssize transfer_size;
GError *error = NULL;
- data->data.updated_video = gdata_youtube_service_upload_video_finish (GDATA_YOUTUBE_SERVICE (service), async_result, &error);
+ /* Finish off the transfer */
+ transfer_size = g_output_stream_splice_finish (stream, result, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (transfer_size, >, 0);
+
+ /* Finish off the upload */
+ data->data.updated_video = gdata_youtube_service_finish_video_upload (data->data.service, GDATA_UPLOAD_STREAM (stream), &error);
g_assert_no_error (error);
g_assert (GDATA_IS_YOUTUBE_VIDEO (data->data.updated_video));
+ /* Check the video's properties */
+ g_assert (gdata_entry_is_inserted (GDATA_ENTRY (data->data.updated_video)));
g_assert_cmpstr (gdata_entry_get_title (GDATA_ENTRY (data->data.updated_video)), ==, gdata_entry_get_title (GDATA_ENTRY (data->data.video)));
+ g_assert_cmpstr (gdata_youtube_video_get_description (data->data.updated_video), ==, gdata_youtube_video_get_description (data->data.video));
+ g_assert_cmpstr (gdata_media_category_get_category (gdata_youtube_video_get_category (data->data.updated_video)), ==,
+ gdata_media_category_get_category (gdata_youtube_video_get_category (data->data.video)));
+
+ tags = gdata_youtube_video_get_keywords (data->data.video);
+ tags2 = gdata_youtube_video_get_keywords (data->data.updated_video);
+ g_assert_cmpuint (g_strv_length ((gchar**) tags2), ==, g_strv_length ((gchar**) tags));
+ g_assert_cmpstr (tags2[0], ==, tags[0]);
+ g_assert_cmpstr (tags2[1], ==, tags[1]);
+ g_assert_cmpstr (tags2[2], ==, tags[2]);
g_main_loop_quit (data->main_loop);
}
@@ -347,10 +421,22 @@ test_upload_async_cb (GDataService *service, GAsyncResult *async_result, UploadA
static void
test_upload_async (UploadAsyncData *data, gconstpointer service)
{
- /* Upload the video */
- gdata_youtube_service_upload_video_async (GDATA_YOUTUBE_SERVICE (service), data->data.video, data->data.video_file, NULL,
- (GAsyncReadyCallback) test_upload_async_cb, data);
+ GDataUploadStream *upload_stream;
+ GError *error = NULL;
+
+ /* Prepare the upload stream */
+ upload_stream = gdata_youtube_service_upload_video (GDATA_YOUTUBE_SERVICE (service), data->data.video, data->data.slug,
+ data->data.content_type, &error);
+ g_assert_no_error (error);
+ g_assert (GDATA_IS_UPLOAD_STREAM (upload_stream));
+
+ /* Upload the video asynchronously */
+ g_output_stream_splice_async (G_OUTPUT_STREAM (upload_stream), G_INPUT_STREAM (data->data.file_stream),
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback) test_upload_async_cb, data);
g_main_loop_run (data->main_loop);
+
+ g_object_unref (upload_stream);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]