[shotwell/wip/phako/google-photos] Wip: upload
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [shotwell/wip/phako/google-photos] Wip: upload
- Date: Mon, 21 Jan 2019 22:28:40 +0000 (UTC)
commit 81ba8e6dbcc5e3674fc1c7bc7d2d0331dfabf070
Author: Jens Georg <mail jensge org>
Date: Mon Jan 21 23:20:32 2019 +0100
Wip: upload
data/gsettings/org.yorba.shotwell.gschema.xml | 6 +-
plugins/common/Resources.vala | 7 +-
plugins/shotwell-publishing/PhotosPublisher.vala | 64 +++++++++++++++++--
.../shotwell-publishing/PhotosPublishingPane.vala | 33 +++++++++-
plugins/shotwell-publishing/PhotosService.vala | 4 +-
plugins/shotwell-publishing/PhotosUploader.vala | 74 ++++++++++++++++++++++
plugins/shotwell-publishing/meson.build | 3 +-
7 files changed, 174 insertions(+), 17 deletions(-)
---
diff --git a/data/gsettings/org.yorba.shotwell.gschema.xml b/data/gsettings/org.yorba.shotwell.gschema.xml
index 65955fa0..2c0893e0 100644
--- a/data/gsettings/org.yorba.shotwell.gschema.xml
+++ b/data/gsettings/org.yorba.shotwell.gschema.xml
@@ -413,7 +413,7 @@
<child name="flickr" schema="org.yorba.shotwell.sharing.flickr" />
<child name="gallery3" schema="org.yorba.shotwell.sharing.publishing-gallery3" />
<child name="picasa" schema="org.yorba.shotwell.sharing.picasa" />
- <child name="org-gnome-shotwell-publishing-photos"
schema="org.yorba.shotwell.sharing.org-gnome-shotwell-publishing-photos" />
+ <child name="org-gnome-shotwell-publishing-google-photos"
schema="org.yorba.shotwell.sharing.org-gnome-shotwell-publishing-google-photos" />
<child name="youtube" schema="org.yorba.shotwell.sharing.youtube" />
</schema>
@@ -513,7 +513,7 @@
</key>
</schema>
-<schema id="org.yorba.shotwell.sharing.org-gnome-shotwell-publishing-photos"
path="/org/yorba/shotwell/sharing/org-gnome-shotwell-publishing-photos/">
+<schema id="org.yorba.shotwell.sharing.org-gnome-shotwell-publishing-google-photos"
path="/org/yorba/shotwell/sharing/org-gnome-shotwell-publishing-google-photos/">
<key name="refresh-token" type="s">
<default>""</default>
<summary>refresh token</summary>
@@ -754,7 +754,7 @@
<description>True if the Picasa Web Albums publishing plugin is enabled, false
otherwise</description>
</key>
- <key name="org-gnome-shotwell-publishing-photos" type="b">
+ <key name="org-gnome-shotwell-publishing-google-photos" type="b">
<default>true</default>
<summary>enable Google Photos publishing plugin</summary>
<description>True if the Google Photos publishing plugin is enabled, false otherwise</description>
diff --git a/plugins/common/Resources.vala b/plugins/common/Resources.vala
index 29c7294e..ecbf2f87 100644
--- a/plugins/common/Resources.vala
+++ b/plugins/common/Resources.vala
@@ -42,7 +42,7 @@ public Gdk.Pixbuf[]? load_icon_set(GLib.File? icon_file) {
try {
icon = new Gdk.Pixbuf.from_file(icon_file.get_path());
} catch (Error err) {
- warning("couldn't load icon set from %s.", icon_file.get_path());
+ warning("couldn't load icon set from %s: %s", icon_file.get_path(), err.message);
}
if (icon != null) {
@@ -57,9 +57,10 @@ public Gdk.Pixbuf[]? load_icon_set(GLib.File? icon_file) {
public Gdk.Pixbuf[]? load_from_resource (string resource_path) {
Gdk.Pixbuf? icon = null;
try {
- icon = new Gdk.Pixbuf.from_resource (resource_path);
+ debug ("Loading icon from %s", resource_path);
+ icon = new Gdk.Pixbuf.from_resource_at_scale (resource_path, 24, 24, true);
} catch (Error error) {
- warning ("Couldn't load icon set from %s", resource_path);
+ warning ("Couldn't load icon set from %s: %s", resource_path, error.message);
}
if (icon != null) {
diff --git a/plugins/shotwell-publishing/PhotosPublisher.vala
b/plugins/shotwell-publishing/PhotosPublisher.vala
index a3366b8c..11111f67 100644
--- a/plugins/shotwell-publishing/PhotosPublisher.vala
+++ b/plugins/shotwell-publishing/PhotosPublisher.vala
@@ -15,6 +15,7 @@ internal class PublishingParameters {
public const int ORIGINAL_SIZE = -1;
private string? target_album_name;
+ private string? target_album_id;
private bool album_public;
private bool strip_metadata;
private int major_axis_size_pixels;
@@ -26,6 +27,7 @@ internal class PublishingParameters {
public PublishingParameters() {
this.user_name = "[unknown]";
this.target_album_name = null;
+ this.target_album_id = null;
this.major_axis_size_selection_id = 0;
this.major_axis_size_pixels = ORIGINAL_SIZE;
this.album_public = false;
@@ -41,6 +43,10 @@ internal class PublishingParameters {
public void set_target_album_name(string target_album_name) {
this.target_album_name = target_album_name;
}
+
+ public void set_target_album_entry_id(string target_album_id) {
+ this.target_album_id = target_album_id;
+ }
public string get_user_name() {
return user_name;
@@ -58,14 +64,14 @@ internal class PublishingParameters {
this.albums = albums;
}
- /*
+
public void set_major_axis_size_pixels(int pixels) {
this.major_axis_size_pixels = pixels;
}
-
+
public int get_major_axis_size_pixels() {
return major_axis_size_pixels;
- } */
+ }
public void set_major_axis_size_selection_id(int selection_id) {
this.major_axis_size_selection_id = selection_id;
@@ -139,6 +145,7 @@ public class Publisher : Publishing.RESTSupport.GooglePublisher {
private Spit.Publishing.Authenticator authenticator;
private bool running = false;
private PublishingParameters publishing_parameters;
+ private Spit.Publishing.ProgressCallback progress_reporter;
public Publisher(Spit.Publishing.Service service,
Spit.Publishing.PluginHost host) {
@@ -227,13 +234,34 @@ public class Publisher : Publishing.RESTSupport.GooglePublisher {
debug("ACTION: showing publishing options pane.");
var opts_pane = new PublishingOptionsPane(this.publishing_parameters,
this.authenticator.can_logout());
-// opts_pane.publish.connect(on_publishing_options_publish);
-// opts_pane.logout.connect(on_publishing_options_logout);
+ opts_pane.publish.connect(on_publishing_options_publish);
+ opts_pane.logout.connect(on_publishing_options_logout);
get_host().install_dialog_pane(opts_pane);
get_host().set_service_locked(false);
}
+ private void on_publishing_options_logout() {
+ if (!is_running())
+ return;
+
+ debug("EVENT: user clicked 'Logout' in the publishing options pane.");
+
+ do_logout();
+ }
+
+ private void on_publishing_options_publish() {
+ if (!is_running())
+ return;
+
+ debug("EVENT: user clicked 'Publish' in the publishing options pane.");
+
+ save_parameters_to_configuration_system(publishing_parameters);
+
+ do_upload();
+ }
+
+
protected override void do_logout() {
debug("ACTION: logging out user.");
get_session().deauthenticate();
@@ -244,6 +272,32 @@ public class Publisher : Publishing.RESTSupport.GooglePublisher {
}
}
+ private void do_upload() {
+ debug("ACTION: uploading media items to remote server.");
+
+ get_host().set_service_locked(true);
+
+ progress_reporter = get_host().serialize_publishables(
+ publishing_parameters.get_major_axis_size_pixels(),
+ publishing_parameters.get_strip_metadata());
+
+ // Serialization is a long and potentially cancellable operation, so before we use
+ // the publishables, make sure that the publishing interaction is still running. If it
+ // isn't the publishing environment may be partially torn down so do a short-circuit
+ // return
+ if (!is_running())
+ return;
+
+ Spit.Publishing.Publishable[] publishables = get_host().get_publishables();
+ Uploader uploader = new Uploader(get_session(), publishables, publishing_parameters);
+
+ uploader.upload_complete.connect(on_upload_complete);
+ uploader.upload_error.connect(on_upload_error);
+
+ uploader.upload(on_upload_status_updated);
+ }
+
+
public override bool is_running() {
return running;
}
diff --git a/plugins/shotwell-publishing/PhotosPublishingPane.vala
b/plugins/shotwell-publishing/PhotosPublishingPane.vala
index 45ca3f1f..d26fdfc5 100644
--- a/plugins/shotwell-publishing/PhotosPublishingPane.vala
+++ b/plugins/shotwell-publishing/PhotosPublishingPane.vala
@@ -17,6 +17,8 @@ internal class PublishingOptionsPane : Gtk.Box, Spit.Publishing.DialogPane {
[GtkChild]
private Gtk.Button logout_button;
[GtkChild]
+ private Gtk.Button publish_button;
+ [GtkChild]
private Gtk.ComboBoxText existing_albums_combo;
[GtkChild]
private Gtk.ComboBoxText size_combo;
@@ -24,6 +26,8 @@ internal class PublishingOptionsPane : Gtk.Box, Spit.Publishing.DialogPane {
private Gtk.Label publish_to_label;
[GtkChild]
private Gtk.Label login_identity_label;
+ [GtkChild]
+ private Gtk.CheckButton strip_metadata_check;
public signal void publish();
public signal void logout();
@@ -41,6 +45,7 @@ internal class PublishingOptionsPane : Gtk.Box, Spit.Publishing.DialogPane {
// populate any widgets whose contents are programmatically-generated.
login_identity_label.set_label(_("You are logged into Google Photos as %s.").printf(
parameters.get_user_name()));
+ strip_metadata_check.set_active(parameters.get_strip_metadata());
if((parameters.get_media_type() & Spit.Publishing.Publisher.MediaType.PHOTO) == 0) {
publish_to_label.set_label(_("Videos will appear in:"));
@@ -56,6 +61,9 @@ internal class PublishingOptionsPane : Gtk.Box, Spit.Publishing.DialogPane {
size_combo.set_sensitive(true);
size_combo.set_active(parameters.get_major_axis_size_selection_id());
}
+
+ publish_button.clicked.connect (on_publish_clicked);
+ logout_button.clicked.connect (on_logout_clicked);
}
// DialogPane interface
@@ -68,9 +76,6 @@ internal class PublishingOptionsPane : Gtk.Box, Spit.Publishing.DialogPane {
}
public void on_pane_installed() {
- if (90 < 0) {
- print("%d", size_descriptions[0].major_axis_pixels);
- }
int default_album_id = -1;
string last_album = parameters.get_target_album_name();
@@ -92,5 +97,27 @@ internal class PublishingOptionsPane : Gtk.Box, Spit.Publishing.DialogPane {
public void on_pane_uninstalled() {
}
+
+ private void on_publish_clicked() {
+ // size_combo won't have been set to anything useful if this is the first time we've
+ // published to Picasa, and/or we've only published video before, so it may be negative,
+ // indicating nothing was selected. Clamp it to a valid value...
+ int size_combo_last_active = (size_combo.get_active() >= 0) ? size_combo.get_active() : 0;
+
+ parameters.set_major_axis_size_selection_id(size_combo_last_active);
+ parameters.set_major_axis_size_pixels(
+ size_descriptions[size_combo_last_active].major_axis_pixels);
+ parameters.set_strip_metadata(strip_metadata_check.get_active());
+
+ Album[] albums = parameters.get_albums();
+
+ parameters.set_target_album_name(albums[existing_albums_combo.get_active()].name);
+ parameters.set_target_album_entry_id(albums[existing_albums_combo.get_active()].id);
+ publish();
+ }
+
+ private void on_logout_clicked() {
+ logout();
+ }
}
}
diff --git a/plugins/shotwell-publishing/PhotosService.vala b/plugins/shotwell-publishing/PhotosService.vala
index 35bb2432..0ffb4d4d 100644
--- a/plugins/shotwell-publishing/PhotosService.vala
+++ b/plugins/shotwell-publishing/PhotosService.vala
@@ -1,7 +1,7 @@
namespace Publishing.GooglePhotos {
public class Service : Object, Spit.Pluggable, Spit.Publishing.Service {
- private const string ICON_FILENAME = "gnome-photos.svg";
+ private const string ICON_FILENAME = "google-photos.svg";
private static Gdk.Pixbuf[] icon_pixbuf_set = null;
@@ -17,7 +17,7 @@ public class Service : Object, Spit.Pluggable, Spit.Publishing.Service {
}
public unowned string get_id() {
- return "org.gnome.shotwell.publishing.photos";
+ return "org.gnome.shotwell.publishing.google-photos";
}
public unowned string get_pluggable_name() {
diff --git a/plugins/shotwell-publishing/PhotosUploader.vala b/plugins/shotwell-publishing/PhotosUploader.vala
new file mode 100644
index 00000000..dd52a1a7
--- /dev/null
+++ b/plugins/shotwell-publishing/PhotosUploader.vala
@@ -0,0 +1,74 @@
+namespace Publishing.GooglePhotos {
+
+internal class UploadTransaction :
+ Publishing.RESTSupport.GooglePublisher.AuthenticatedTransaction {
+ private PublishingParameters parameters;
+ private Publishing.RESTSupport.GoogleSession session;
+ private Spit.Publishing.Publishable publishable;
+ private MappedFile mapped_file;
+
+ public UploadTransaction(Publishing.RESTSupport.GoogleSession session,
+ PublishingParameters parameters, Spit.Publishing.Publishable publishable) {
+ base(session, "https://photoslibrary.googleapis.com/v1/uploads",
+ Publishing.RESTSupport.HttpMethod.POST);
+ assert(session.is_authenticated());
+ this.session = session;
+ this.parameters = parameters;
+ this.publishable = publishable;
+ }
+
+ public override void execute() throws Spit.Publishing.PublishingError {
+ var basename = publishable.get_param_string(Spit.Publishing.Publishable.PARAM_STRING_BASENAME);
+
+ // attempt to map the binary image data from disk into memory
+ try {
+ mapped_file = new MappedFile(publishable.get_serialized_file().get_path(), false);
+ } catch (FileError e) {
+ string msg = "Picasa: couldn't read data from %s: %s".printf(
+ publishable.get_serialized_file().get_path(), e.message);
+ warning("%s", msg);
+
+ throw new Spit.Publishing.PublishingError.LOCAL_FILE_ERROR(msg);
+ }
+ unowned uint8[] photo_data = (uint8[]) mapped_file.get_contents();
+ photo_data.length = (int) mapped_file.get_length();
+
+ // bind the binary image data read from disk into a Soup.Buffer object so that we
+ // can attach it to the multipart request, then actaully append the buffer
+ // to the multipart request. Then, set the MIME type for this part.
+ Soup.Buffer bindable_data = new Soup.Buffer(Soup.MemoryUse.TEMPORARY, photo_data);
+
+ // create a message that can be sent over the wire whose payload is the multipart container
+ // that we've been building up
+ var outbound_message = new Soup.Message ("POST", get_endpoint_url());
+ outbound_message.request_headers.append("Authorization", "Bearer " +
+ session.get_access_token());
+ outbound_message.request_headers.append("X-Goog-Upload-File-Name", basename);
+ outbound_message.request_headers.append("X-Goog-Upload-Protocol", "raw");
+ outbound_message.request_headers.set_content_type("application/octet-stream", null);
+ outbound_message.request_body.append_buffer (bindable_data);
+ set_message(outbound_message);
+
+ // send the message and get its response
+ set_is_executed(true);
+ send();
+ }
+}
+
+internal class Uploader : Publishing.RESTSupport.BatchUploader {
+ private PublishingParameters parameters;
+
+ public Uploader(Publishing.RESTSupport.GoogleSession session,
+ Spit.Publishing.Publishable[] publishables, PublishingParameters parameters) {
+ base(session, publishables);
+
+ this.parameters = parameters;
+ }
+
+ protected override Publishing.RESTSupport.Transaction create_transaction(
+ Spit.Publishing.Publishable publishable) {
+ return new UploadTransaction((Publishing.RESTSupport.GoogleSession) get_session(),
+ parameters, get_current_publishable());
+ }
+}
+}
diff --git a/plugins/shotwell-publishing/meson.build b/plugins/shotwell-publishing/meson.build
index cfee47cc..fd27a99e 100644
--- a/plugins/shotwell-publishing/meson.build
+++ b/plugins/shotwell-publishing/meson.build
@@ -8,7 +8,8 @@ shotwell_publishing_sources = [
'PiwigoPublishing.vala',
'PhotosPublisher.vala',
'PhotosService.vala',
- 'PhotosPublishingPane.vala'
+ 'PhotosPublishingPane.vala',
+ 'PhotosUploader.vala'
]
shotwell_publishing_resources = gnome.compile_resources('publishing-resource',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]