49#include <json-glib/json-glib.h>
57#define piwigo_EXTRA_VERBOSE FALSE
59#define MAX_ALBUM_NAME_SIZE 100
133 GString *
string = (GString *)data;
134 g_string_append_len(
string, ptr,
size * nmemb);
135#if piwigo_EXTRA_VERBOSE == TRUE
136 g_printf(
"server reply: %s\n", string->str);
146 return g_list_append(args, arg);
167 curl_easy_cleanup((*ctx)->curl_ctx);
168 if((*ctx)->cookie_file) g_unlink((*ctx)->cookie_file);
169 g_object_unref((*ctx)->json_parser);
200 g_hash_table_iter_init (&iter, table);
202 while (g_hash_table_iter_next (&iter, &
key, &
value))
206 gchar *data = (gchar *)
value;
207 JsonParser *parser = json_parser_new();
208 json_parser_load_from_data(parser, data, strlen(data), NULL);
209 JsonNode *root = json_parser_get_root(parser);
213 JsonObject *obj = json_node_get_object(root);
216 account->
server = g_strdup(json_object_get_string_member(obj,
"server"));
217 account->
username = g_strdup(json_object_get_string_member(obj,
"username"));
218 account->
password = g_strdup(json_object_get_string_member(obj,
"password"));
226 g_object_unref(parser);
230 g_hash_table_destroy(table);
237 for(
const GList *a = ui->
accounts; a; a = g_list_next(a))
240 if(account->
server && !strcmp(server, account->
server))
return account;
249 JsonBuilder *builder = json_builder_new();
250 json_builder_begin_object(builder);
251 json_builder_set_member_name(builder,
"server");
252 json_builder_add_string_value(builder, gtk_entry_get_text(ui->
server_entry));
253 json_builder_set_member_name(builder,
"username");
254 json_builder_add_string_value(builder, gtk_entry_get_text(ui->
user_entry));
255 json_builder_set_member_name(builder,
"password");
256 json_builder_add_string_value(builder, gtk_entry_get_text(ui->
pwd_entry));
258 json_builder_end_object(builder);
260 JsonNode *node = json_builder_get_root(builder);
261 JsonGenerator *generator = json_generator_new();
262 json_generator_set_root(generator, node);
263#if JSON_CHECK_VERSION(0, 14, 0)
264 json_generator_set_pretty(generator,
FALSE);
266 gchar *data = json_generator_to_data(generator, NULL);
268 json_node_free(node);
269 g_object_unref(generator);
270 g_object_unref(builder);
273 g_hash_table_insert(table, g_strdup(gtk_entry_get_text(ui->
server_entry)), data);
275 g_hash_table_destroy(table);
282 gchar mup[512] = { 0 };
283 snprintf(mup,
sizeof(mup),
"<span foreground=\"%s\" ><small>%s</small></span>", color, message);
285 gtk_widget_set_tooltip_markup(GTK_WIDGET(ui->
status_label), mup);
290 curl_mime *form = NULL;
292 GString *url = g_string_new(ctx->
url);
295 GString *response = g_string_new(
"");
299 curl_easy_setopt(ctx->
curl_ctx, CURLOPT_URL, url->str);
300 curl_easy_setopt(ctx->
curl_ctx, CURLOPT_POST, 1);
302 curl_easy_setopt(ctx->
curl_ctx, CURLOPT_WRITEDATA, response);
309 g_strlcat(cookie_fmt,
"/cookies.%.4lf.txt",
sizeof(cookie_fmt));
324 curl_mimepart *field = NULL;
326 form = curl_mime_init(ctx->
curl_ctx);
328 for(
const GList *a = args; a; a = g_list_next(a))
331 field = curl_mime_addpart(form);
332 curl_mime_name(field, ca->
name);
333 curl_mime_data(field, ca->
value, CURL_ZERO_TERMINATED);
336 field = curl_mime_addpart(form);
337 curl_mime_name(field,
"image");
338 curl_mime_filedata(field, filename);
340 curl_easy_setopt(ctx->
curl_ctx, CURLOPT_MIMEPOST, form);
344 GString *gargs = g_string_new(
"");
346 for(
const GList *a = args; a; a = g_list_next(a))
349 if(a!=args) g_string_append(gargs,
"&");
350 g_string_append(gargs, ca->
name);
351 g_string_append(gargs,
"=");
352 g_string_append(gargs, ca->
value);
355 curl_easy_setopt(ctx->
curl_ctx, CURLOPT_COPYPOSTFIELDS, gargs->str);
356 g_string_free(gargs,
TRUE);
359 const int res = curl_easy_perform(ctx->
curl_ctx);
361#if piwigo_EXTRA_VERBOSE == TRUE
362 g_printf(
"curl_easy_perform status %d\n", res);
365 if(filename) curl_mime_free(form);
367 g_string_free(url,
TRUE);
373 GError *
error = NULL;
374 gboolean ret = json_parser_load_from_data(ctx->
json_parser, response->str, response->len, &
error);
376 JsonNode *root = json_parser_get_root(ctx->
json_parser);
378 if(json_node_get_node_type(root) != JSON_NODE_OBJECT)
goto cleanup;
379 ctx->
response = json_node_get_object(root);
380 const char *status = json_object_get_string_member(ctx->
response,
"stat");
387 g_string_free(response,
TRUE);
398 if(!strcmp(ctx->
server,
"piwigo.com"))
399 ctx->
url = g_strdup_printf(
"https://%s.piwigo.com/ws.php?format=json", ctx->
username);
401 ctx->
url = g_strdup_printf(
"%s/ws.php?format=json", ctx->
server);
403 ctx->
url = g_strdup_printf(
"https://%s/ws.php?format=json", ctx->
server);
420 JsonObject *result = json_node_get_object(json_object_get_member(ctx->
response,
"result"));
421 const gchar *pwg_token = json_object_get_string_member(result,
"pwg_token");
433 if(res == CURLE_COULDNT_CONNECT || res == CURLE_SSL_CONNECT_ERROR)
435#if piwigo_EXTRA_VERBOSE == TRUE
436 g_printf(
"curl post error (%d), try authentication again\n", res);
455#if piwigo_EXTRA_VERBOSE == TRUE
456 g_printf(
"authenticated again, retry\n");
459#if piwigo_EXTRA_VERBOSE == TRUE
460 g_printf(
"second post exit with status %d\n", res);
465#if piwigo_EXTRA_VERBOSE == TRUE
466 g_printf(
"failed second authentication\n");
497 const gchar *errormessage = json_object_get_string_member(ui->
api->
response,
"message");
498 fprintf(stderr,
"[imageio_storage_piwigo] could not authenticate: `%s'!\n", errormessage);
554 if(strcmp(
value, _(
"create new album")) == 0)
557 gtk_widget_show_all(GTK_WIDGET(ui->
create_box));
565 gchar *
v = g_strstrip(g_strdup(
value));
566 gchar *
p =
v + strlen(
v) - 1;
569 while(
p !=
v && *
p !=
'(')
p--;
573 if(
p >=
v) *
p =
'\0';
603 gchar *
p = to_select;
606 if(*
p ==
' ' && *(
p+1) ==
'(')
616 to_select = g_strdup(select_album);
640 JsonObject *result = json_node_get_object(json_object_get_member(ui->
api->
response,
"result"));
641 JsonArray *albums = json_object_get_array_member(result,
"categories");
643 if(json_array_get_length(albums)>0 && index==0) index = 1;
644 if(index > json_array_get_length(albums) - 1) index = json_array_get_length(albums) - 1;
646 for(
int i = 0;
i < json_array_get_length(albums);
i++)
649 JsonObject *album = json_array_get_object_element(albums,
i);
653 g_strlcpy(new_album->
name, json_object_get_string_member(album,
"name"),
sizeof(new_album->
name));
654 new_album->
id = json_object_get_int_member(album,
"id");
655 new_album->
size = json_object_get_int_member(album,
"nb_images");
656 const int isroot = json_object_get_null_member(album,
"id_uppercat");
662 const char *hierarchy = json_object_get_string_member(album,
"uppercats");
663 char const *
p = hierarchy;
664 while(*
p++)
if(*
p ==
',') indent++;
667 g_snprintf(data,
sizeof(data),
"%*c%s (%" PRId64
")", indent * 3,
' ', new_album->
name, new_album->
size);
669 if(to_select && !strcmp(new_album->
name, to_select)) index =
i + 1;
671 g_strlcpy(new_album->
label, data,
sizeof(new_album->
label));
697 if(
p->parent_album_id != 0)
700 snprintf(pid,
sizeof(pid),
"%"PRId64,
p->parent_album_id);
710 if(!
p->api->response ||
p->api->error_occured)
716 JsonObject *result = json_node_get_object(json_object_get_member(
p->api->response,
"result"));
718 p->album_id = json_object_get_int_member(result,
"id");
733 snprintf(cat,
sizeof(cat),
"%"PRId64,
p->album_id);
734 snprintf(privacy,
sizeof(privacy),
"%d",
p->privacy);
741 if(caption && strlen(caption)>0)
744 if(author && strlen(author)>0)
750 if(
p->tags && strlen(
p->tags)>0)
758 return !
p->api->error_occured;
786 return _(
"Piwigo website");
812 int account_index = -1, index=0;
813 for(
const GList *a = ui->
accounts; a; a = g_list_next(a))
817 if(!strcmp(account->
server, server)) account_index = index;
828 gtk_widget_set_tooltip_text(GTK_WIDGET(ui->
server_entry),
829 _(
"the server name\ndefault protocol is https\nspecify http:// if non secure server"));
833 gtk_entry_set_width_chars(GTK_ENTRY(ui->
server_entry), 0);
836 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox),
TRUE,
TRUE, 0);
846 gtk_entry_set_width_chars(GTK_ENTRY(ui->
user_entry), 0);
849 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox),
TRUE,
TRUE, 0);
853 ui->
pwd_entry = GTK_ENTRY(gtk_entry_new());
859 gtk_entry_set_width_chars(GTK_ENTRY(ui->
pwd_entry), 0);
862 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox),
TRUE,
TRUE, 0);
865 button = gtk_button_new_with_label(_(
"login"));
866 gtk_widget_set_tooltip_text(button, _(
"piwigo login"));
872 gtk_label_set_ellipsize(ui->
status_label, PANGO_ELLIPSIZE_END);
873 gtk_widget_set_halign(GTK_WIDGET(ui->
status_label), GTK_ALIGN_START);
900 gtk_widget_set_tooltip_text(button, _(
"refresh album list"));
902 gtk_box_pack_start(GTK_BOX(hbox), button,
FALSE,
FALSE, 0);
913 label = gtk_label_new(_(
"title"));
914 g_object_set(G_OBJECT(label),
"xalign", 0.0, (gchar *)0);
915 gtk_box_pack_start(GTK_BOX(hbox), label,
FALSE,
FALSE, 0);
949 if(!
g->api->error_occured)
974 const gboolean high_quality,
const gboolean export_masks,
982 const char *ext = format->extension(fdata);
989 g_strlcat(fname,
"/darktable.XXXXXX.",
sizeof(fname));
990 g_strlcat(fname, ext,
sizeof(fname));
992 char *caption = NULL;
996 gint fd = g_mkstemp(fname);
999 dt_control_log(
"failed to create temporary image for piwigo export");
1000 fprintf(stderr,
"failed to create tempfile: %s\n", fname);
1012 caption = g_strdup(title->data);
1018 caption = g_path_get_basename(img->
filename);
1019 gchar *dot = g_strrstr(caption,
".");
1020 if(dot) dot[0] =
'\0';
1035 author = g_strdup(auth->data);
1041 icc_intent, self, sdata, num, total, metadata) != 0)
1043 fprintf(stderr,
"[imageio_storage_piwigo] could not export to file: `%s'!\n", fname);
1050 gboolean status =
TRUE;
1064 if(!status)
dt_control_log(_(
"cannot create a new piwigo album!"));
1072 fprintf(stderr,
"[imageio_storage_piwigo] could not upload to piwigo!\n");
1076 else if(
p->new_album)
1101 dt_control_log(ngettext(
"%d/%d exported to piwigo webalbum",
"%d/%d exported to piwigo webalbum", num),
1109 return sizeof(int64_t);
1120 for(
const GList *a = albums; a; a = g_list_next(a))
1146 p->api->authenticated =
FALSE;
1183 p->new_album =
TRUE;
1193 fprintf(stderr,
"Something went wrong.. album index %d = NULL\n", index - 2);
1201 fprintf(stderr,
"[imageio_storage_piwigo] cannot find album `%s'!\n",
p->album);
1223 if(
size != self->params_size(self))
return 1;
1231 if(strcmp(format->mime(NULL),
"image/jpeg") == 0)
1233 else if(strcmp(format->mime(NULL),
"image/png") == 0)
const char ** description(struct dt_iop_module_t *self)
static void error(char *msg)
void cleanup(dt_imageio_module_format_t *self)
void dt_bauhaus_combobox_clear(GtkWidget *widget)
int dt_bauhaus_combobox_get(GtkWidget *widget)
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
void dt_bauhaus_combobox_add_aligned(GtkWidget *widget, const char *text, dt_bauhaus_combobox_alignment_t align)
@ DT_BAUHAUS_COMBOBOX_ALIGN_LEFT
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
dt_colorspaces_color_profile_type_t
gchar * dt_conf_get_string(const char *name)
void dt_conf_set_string(const char *name, const char *val)
void dt_control_log(const char *msg,...)
#define DT_MODULE(MODVER)
static void dt_free_gpointer(gpointer ptr)
static const dt_aligned_pixel_simd_t value
static double dt_get_wtime(void)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
void dtgtk_cairo_paint_refresh(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
void dt_loc_get_tmp_dir(char *tmpdir, size_t bufsize)
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnects accels when a text or search entry gets the focus, and reconnects them when it looses it....
#define DT_GUI_BOX_SPACING
static GtkWidget * dt_ui_label_new(const gchar *str)
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
int dt_imageio_export(const int32_t imgid, const char *filename, dt_imageio_module_format_t *format, dt_imageio_module_data_t *format_params, const gboolean high_quality, const gboolean copy_metadata, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_imageio_module_storage_t *storage, dt_imageio_module_data_t *storage_params, int num, int total, dt_export_metadata_t *metadata)
void * get_params(dt_imageio_module_storage_t *self)
static _piwigo_api_context_t * _piwigo_ctx_init(void)
int supported(dt_imageio_module_storage_t *storage, dt_imageio_module_format_t *format)
static uint64_t _piwigo_album_id(const gchar *name, GList *albums)
void finalize_store(struct dt_imageio_module_storage_t *self, dt_imageio_module_data_t *data)
static void _piwigo_login_clicked(GtkButton *button, gpointer data)
static void _piwigo_authenticate(dt_storage_piwigo_gui_data_t *ui)
static gboolean _finalize_store(gpointer user_data)
static void _piwigo_api_authenticate(_piwigo_api_context_t *ctx)
static int _piwigo_api_post_internal(_piwigo_api_context_t *ctx, GList *args, char *filename, gboolean isauth)
static void _piwigo_load_account(dt_storage_piwigo_gui_data_t *ui)
static _piwigo_account_t * _piwigo_get_account(dt_storage_piwigo_gui_data_t *ui, const gchar *server)
static gboolean _piwigo_api_create_new_album(dt_storage_piwigo_params_t *p)
static void _piwigo_entry_changed(GtkEntry *entry, gpointer data)
void gui_cleanup(dt_imageio_module_storage_t *self)
void free_params(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *params)
static void _piwigo_free_account(void *data)
#define MAX_ALBUM_NAME_SIZE
static void _piwigo_set_status(dt_storage_piwigo_gui_data_t *ui, gchar *message, gchar *color)
static size_t curl_write_data_cb(void *ptr, size_t size, size_t nmemb, void *data)
size_t params_size(dt_imageio_module_storage_t *self)
void gui_init(dt_imageio_module_storage_t *self)
static GList * _piwigo_query_add_arguments(GList *args, const char *name, const char *value)
void init(dt_imageio_module_storage_t *self)
void gui_reset(dt_imageio_module_storage_t *self)
static gboolean _piwigo_api_upload_photo(dt_storage_piwigo_params_t *p, gchar *fname, gchar *author, gchar *caption, gchar *description)
static void _piwigo_api_post(_piwigo_api_context_t *ctx, GList *args, char *filename, gboolean isauth)
int set_params(dt_imageio_module_storage_t *self, const void *params, const int size)
static void _piwigo_account_changed(GtkComboBox *cb, gpointer data)
int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid, dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const int num, const int total, const gboolean high_quality, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_export_metadata_t *metadata)
static void _piwigo_ctx_destroy(_piwigo_api_context_t **ctx)
static void _piwigo_refresh_albums(dt_storage_piwigo_gui_data_t *ui, const gchar *select_album)
static void _piwigo_refresh_clicked(GtkButton *button, gpointer data)
#define piwigo_EXTRA_VERBOSE
static void _piwigo_album_changed(GtkComboBox *cb, gpointer data)
static void _piwigo_set_account(dt_storage_piwigo_gui_data_t *ui)
static void _piwigo_server_entry_changed(GtkEntry *entry, gpointer data)
GHashTable * dt_pwstorage_get(const gchar *slot)
gboolean dt_pwstorage_set(const gchar *slot, GHashTable *table)
struct _GtkWidget GtkWidget
unsigned __int64 uint64_t
CURL * curl_ctx
curl context
dt_pthread_mutex_t plugin_threadsafe
struct dt_bauhaus_t * bauhaus
struct dt_image_cache_t * image_cache
char filename[DT_MAX_FILENAME_LEN]
GModule *GtkWidget * widget
GtkWidget * parent_album_list
GtkWidget * permission_list
GtkEntry * new_album_entry
_piwigo_api_context_t * api
_piwigo_api_context_t * api
gchar * dt_util_glist_to_str(const gchar *separator, GList *items)