1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * Goo
5 *
6 * Copyright (C) 2004 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23 #include <config.h>
24 #include <string.h>
25 #include <gtk/gtk.h>
26 #if HAVE_LIBCOVERART
27 #include <coverart/caa_c.h>
28 #endif
29 #include "dlg-cover-chooser.h"
30 #include "gio-utils.h"
31 #include "glib-utils.h"
32 #include "gtk-utils.h"
33 #include "goo-window.h"
34
35
36 #define BUFFER_SIZE 4096
37 #define COVER_BACKUP_FILENAME "original_cover.png"
38 #define MAX_IMAGES 20
39 #define GET_WIDGET(x) _gtk_builder_get_widget (data->builder, (x))
40 #define _GTK_RESPONSE_RESET 10
41
42
43 enum {
44 URL_COLUMN,
45 IMAGE_COLUMN,
46 N_COLUMNS
47 };
48
49
50 typedef struct {
51 GooWindow *window;
52 char *artist;
53 char *album;
54 GtkBuilder *builder;
55 GtkWidget *dialog;
56 GtkWidget *icon_view;
57 GdkPixbuf *cover_backup;
58 GList *file_list;
59 int total_files;
60 GList *current_file;
61 int loaded_files;
62 GCancellable *cancellable;
63 gboolean searching;
64 gboolean destroy;
65 } DialogData;
66
67
68 static GList *
make_file_list_from_search_result(void * buffer,gsize count,int max_files)69 make_file_list_from_search_result (void *buffer,
70 gsize count,
71 int max_files)
72 {
73 GList *list = NULL;
74 int n_files = 0;
75 gboolean done = FALSE;
76 GInputStream *stream;
77 gssize n;
78 char buf[BUFFER_SIZE];
79 int buf_offset = 0;
80 GString *partial_url;
81
82 stream = g_memory_input_stream_new_from_data (buffer, count, NULL);
83 partial_url = NULL;
84 while ((n = g_input_stream_read (stream,
85 buf + buf_offset,
86 BUFFER_SIZE - buf_offset - 1,
87 NULL,
88 NULL)) > 0)
89 {
90 const char *prefix = "/images?q=tbn:";
91 int prefix_len = strlen (prefix);
92 char *url_start;
93 gboolean copy_tail = TRUE;
94
95 buf[buf_offset+n] = 0;
96
97 if (partial_url == NULL)
98 url_start = strstr (buf, prefix);
99 else
100 url_start = buf;
101
102 while (url_start != NULL) {
103 char *url_end;
104
105 url_end = strstr (url_start, "\"");
106
107 if (url_end == NULL) {
108 if (partial_url == NULL)
109 partial_url = g_string_new (url_start);
110 else
111 g_string_append (partial_url, url_start);
112 url_start = NULL;
113 copy_tail = FALSE;
114 }
115 else {
116 char *url_tail = g_strndup (url_start, url_end - url_start);
117 char *url;
118 char *complete_url;
119
120 if (partial_url != NULL) {
121 g_string_append (partial_url, url_tail);
122 g_free (url_tail);
123 url = partial_url->str;
124 g_string_free (partial_url, FALSE);
125 partial_url = NULL;
126 }
127 else
128 url = url_tail;
129
130 complete_url = g_strconcat ("http://images.google.com", url, NULL);
131 g_free (url);
132
133 list = g_list_prepend (list, complete_url);
134 n_files++;
135 if (n_files >= max_files) {
136 done = TRUE;
137 break;
138 }
139
140 url_start = strstr (url_end + 1, prefix);
141 }
142 }
143
144 if (done)
145 break;
146
147 if (copy_tail) {
148 prefix_len = MIN (prefix_len, buf_offset + n);
149 strncpy (buf,
150 buf + buf_offset + n - prefix_len,
151 prefix_len);
152 buf_offset = prefix_len;
153 }
154 else
155 buf_offset = 0;
156 }
157
158 if (partial_url != NULL)
159 g_string_free (partial_url, TRUE);
160
161 g_object_unref (stream);
162
163 return g_list_reverse (list);
164 }
165
166
167 static char *
get_query(const char * album,const char * artist)168 get_query (const char *album,
169 const char *artist)
170 {
171 char *s, *e, *q;
172
173 s = g_strdup_printf ("%s %s", album, artist);
174 e = g_uri_escape_string (s, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE);
175 q = g_strconcat ("http://images.google.com/images?q=", e, NULL);
176
177 g_free (e);
178 g_free (s);
179
180 return q;
181 }
182
183
184 /* -- dlg_cover_chooser -- */
185
186
187 static void
destroy_cb(GtkWidget * widget,DialogData * data)188 destroy_cb (GtkWidget *widget,
189 DialogData *data)
190 {
191 if (data->searching) {
192 data->destroy = TRUE;
193 g_cancellable_cancel (data->cancellable);
194 return;
195 }
196
197 g_signal_handlers_disconnect_by_data (data->icon_view, data);
198
199 g_object_unref (data->cancellable);
200 _g_string_list_free (data->file_list);
201 _g_object_unref (data->cover_backup);
202 g_object_unref (data->builder);
203 g_free (data->album);
204 g_free (data->artist);
205 g_free (data);
206 }
207
208
209 static void
search_completed(DialogData * data)210 search_completed (DialogData *data)
211 {
212 char *text;
213
214 data->searching = FALSE;
215 gtk_widget_set_sensitive (GET_WIDGET ("cancel_search_button"), FALSE);
216 text = g_strdup_printf ("%u", data->total_files);
217 gtk_label_set_text (GTK_LABEL (GET_WIDGET ("progress_label")), text);
218
219 g_free (text);
220
221 if (data->destroy)
222 destroy_cb (NULL, data);
223 }
224
225
226 static void load_current_file (DialogData *data);
227
228
229 static void
search_image_data_ready_cb(void * buffer,gsize count,GError * error,gpointer user_data)230 search_image_data_ready_cb (void *buffer,
231 gsize count,
232 GError *error,
233 gpointer user_data)
234 {
235 DialogData *data = user_data;
236
237 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
238 search_completed (data);
239 return;
240 }
241
242 if (error == NULL) {
243 GInputStream *stream;
244 GdkPixbuf *image;
245
246 stream = g_memory_input_stream_new_from_data (buffer, count, NULL);
247 image = gdk_pixbuf_new_from_stream (stream, NULL, &error);
248 if (image != NULL) {
249 GtkTreeModel *model;
250 GtkTreeIter iter;
251 char *url;
252
253 model = gtk_icon_view_get_model (GTK_ICON_VIEW (data->icon_view));
254 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
255 url = (char *) data->current_file->data;
256 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
257 URL_COLUMN, url,
258 IMAGE_COLUMN, image,
259 -1);
260
261 g_object_unref (image);
262 }
263 }
264
265 data->loaded_files++;
266 data->current_file = data->current_file->next;
267 load_current_file (data);
268 }
269
270
271 static void
update_progress_label(DialogData * data)272 update_progress_label (DialogData *data)
273 {
274 char *text;
275
276 if (data->loaded_files < data->total_files)
277 text = g_strdup_printf (_("%u, loading image: %u"),
278 data->total_files,
279 data->loaded_files + 1);
280 else
281 text = g_strdup_printf ("%u", data->total_files);
282 gtk_label_set_text (GTK_LABEL (GET_WIDGET ("progress_label")), text);
283
284 g_free (text);
285 }
286
287
288 static void
load_current_file(DialogData * data)289 load_current_file (DialogData *data)
290 {
291 char *url;
292 GFile *source;
293
294 update_progress_label (data);
295
296 if (data->current_file == NULL) {
297 search_completed (data);
298 return;
299 }
300
301 url = data->current_file->data;
302
303 debug (DEBUG_INFO, "LOADING %s\n", url);
304
305 source = g_file_new_for_uri (url);
306 g_load_file_async (source,
307 G_PRIORITY_DEFAULT,
308 data->cancellable,
309 search_image_data_ready_cb,
310 data);
311
312 g_object_unref (source);
313 }
314
315
316 static void
start_loading_files(DialogData * data)317 start_loading_files (DialogData *data)
318 {
319 gtk_list_store_clear (GTK_LIST_STORE (gtk_icon_view_get_model (GTK_ICON_VIEW (data->icon_view))));
320 data->total_files = g_list_length (data->file_list);
321 data->current_file = data->file_list;
322 data->loaded_files = 0;
323 load_current_file (data);
324 }
325
326
327 static void
search_query_ready_cb(void * buffer,gsize count,GError * error,gpointer user_data)328 search_query_ready_cb (void *buffer,
329 gsize count,
330 GError *error,
331 gpointer user_data)
332 {
333 DialogData *data = user_data;
334
335 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
336 search_completed (data);
337 return;
338 }
339
340 if (error != NULL) {
341 _gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->dialog),
342 _("Could not search for a cover on Internet"),
343 &error);
344 search_completed (data);
345 return;
346 }
347
348 data->file_list = make_file_list_from_search_result (buffer, count, MAX_IMAGES);
349 start_loading_files (data);
350 }
351
352
353 static void
start_searching(DialogData * data)354 start_searching (DialogData *data)
355 {
356 char *query;
357 GFile *file;
358
359 data->searching = TRUE;
360 g_cancellable_reset (data->cancellable);
361 gtk_widget_set_sensitive (GET_WIDGET ("cancel_search_button"), TRUE);
362
363 query = get_query (data->album, data->artist);
364 file = g_file_new_for_uri (query);
365 g_load_file_async (file,
366 G_PRIORITY_DEFAULT,
367 data->cancellable,
368 search_query_ready_cb,
369 data);
370
371 g_object_unref (file);
372 g_free (query);
373 }
374
375
376 static void
ok_button_clicked(DialogData * data)377 ok_button_clicked (DialogData *data)
378 {
379 GList *list;
380
381 list = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (data->icon_view));
382 if (list != NULL) {
383 GtkTreePath *path;
384 GtkTreeModel *model;
385 GtkTreeIter iter;
386
387 path = list->data;
388 model = gtk_icon_view_get_model (GTK_ICON_VIEW (data->icon_view));
389 if (gtk_tree_model_get_iter (model, &iter, path)) {
390 GdkPixbuf *image;
391
392 gtk_tree_model_get (model, &iter, IMAGE_COLUMN, &image, -1);
393 goo_window_set_cover_image_from_pixbuf (data->window, image);
394
395 g_object_unref (image);
396 }
397
398 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
399 g_list_free (list);
400 }
401 }
402
403
404 static void
icon_view_selection_changed_cb(GtkIconView * icon_view,DialogData * data)405 icon_view_selection_changed_cb (GtkIconView *icon_view,
406 DialogData *data)
407 {
408 GList *list;
409
410 list = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (data->icon_view));
411 gtk_widget_set_sensitive (gtk_dialog_get_widget_for_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK), list != NULL);
412
413 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
414 g_list_free (list);
415 }
416
417
418 static void
icon_view_item_activated_cb(GtkIconView * icon_view,GtkTreePath * path,DialogData * data)419 icon_view_item_activated_cb (GtkIconView *icon_view,
420 GtkTreePath *path,
421 DialogData *data)
422 {
423 ok_button_clicked (data);
424 }
425
426
427 static void
cancel_search_button_clicked_cb(GtkWidget * widget,DialogData * data)428 cancel_search_button_clicked_cb (GtkWidget *widget,
429 DialogData *data)
430 {
431 g_cancellable_cancel (data->cancellable);
432 }
433
434
435 static void
backup_cover_image(DialogData * data)436 backup_cover_image (DialogData *data)
437 {
438 char *cover_filename;
439
440 cover_filename = goo_window_get_cover_filename (data->window);
441 gtk_widget_set_sensitive (gtk_dialog_get_widget_for_response (GTK_DIALOG (data->dialog), _GTK_RESPONSE_RESET), cover_filename != NULL);
442 if (cover_filename != NULL)
443 data->cover_backup = gdk_pixbuf_new_from_file (cover_filename, NULL);
444
445 g_free (cover_filename);
446 }
447
448
449 static void
dialog_response_cb(GtkWidget * dialog,int response_id,DialogData * data)450 dialog_response_cb (GtkWidget *dialog,
451 int response_id,
452 DialogData *data)
453 {
454 switch (response_id) {
455 case GTK_RESPONSE_OK:
456 ok_button_clicked (data);
457 gtk_widget_destroy (dialog);
458 break;
459
460 case _GTK_RESPONSE_RESET:
461 goo_window_set_cover_image_from_pixbuf (data->window, data->cover_backup);
462 break;
463
464 default:
465 gtk_widget_destroy (dialog);
466 break;
467 }
468 }
469
470
471 void
dlg_cover_chooser(GooWindow * window,const char * album,const char * artist)472 dlg_cover_chooser (GooWindow *window,
473 const char *album,
474 const char *artist)
475 {
476 DialogData *data;
477 GtkListStore *model;
478 GtkCellRenderer *renderer;
479
480 data = g_new0 (DialogData, 1);
481 data->window = window;
482 data->builder = _gtk_builder_new_from_resource ("cover-chooser.ui");
483 data->album = g_strdup (album);
484 data->artist = g_strdup (artist);
485 data->cancellable = g_cancellable_new ();
486
487 /* Get the widgets. */
488
489 data->dialog = g_object_new (GTK_TYPE_DIALOG,
490 "title", _("Choose a CD Cover"),
491 "transient-for", GTK_WINDOW (window),
492 "modal", TRUE,
493 "use-header-bar", _gtk_settings_get_dialogs_use_header (),
494 NULL);
495 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (data->dialog))),
496 GET_WIDGET ("cover_chooser_dialog"));
497 gtk_dialog_add_buttons (GTK_DIALOG (data->dialog),
498 _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
499 _GTK_LABEL_OK, GTK_RESPONSE_OK,
500 NULL);
501
502 {
503 GtkWidget *button;
504
505 button = gtk_button_new_from_icon_name ("edit-undo-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
506 gtk_widget_show (button);
507 gtk_dialog_add_action_widget (GTK_DIALOG (data->dialog), button, _GTK_RESPONSE_RESET);
508 }
509
510 gtk_style_context_add_class (gtk_widget_get_style_context (gtk_dialog_get_widget_for_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK)),
511 GTK_STYLE_CLASS_SUGGESTED_ACTION);
512
513 model = gtk_list_store_new (N_COLUMNS,
514 G_TYPE_STRING,
515 GDK_TYPE_PIXBUF);
516 data->icon_view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (model));
517 g_object_unref (model);
518
519 renderer = gtk_cell_renderer_pixbuf_new ();
520 g_object_set (renderer, "follow-state", TRUE, NULL);
521 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (data->icon_view),
522 renderer,
523 TRUE);
524 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (data->icon_view),
525 renderer,
526 "pixbuf", IMAGE_COLUMN,
527 NULL);
528
529 gtk_widget_show (data->icon_view);
530 gtk_container_add (GTK_CONTAINER (GET_WIDGET ("icon_view_scrolledwindow")), data->icon_view);
531
532 /* Set widgets data. */
533
534 backup_cover_image (data);
535
536 gtk_widget_set_sensitive (gtk_dialog_get_widget_for_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK), FALSE);
537
538 /* Set the signals handlers. */
539
540 g_signal_connect (G_OBJECT (data->dialog),
541 "destroy",
542 G_CALLBACK (destroy_cb),
543 data);
544 g_signal_connect (G_OBJECT (data->dialog),
545 "response",
546 G_CALLBACK (dialog_response_cb),
547 data);
548 g_signal_connect (G_OBJECT (data->icon_view),
549 "selection-changed",
550 G_CALLBACK (icon_view_selection_changed_cb),
551 data);
552 g_signal_connect (G_OBJECT (data->icon_view),
553 "item-activated",
554 G_CALLBACK (icon_view_item_activated_cb),
555 data);
556 g_signal_connect (GET_WIDGET ("cancel_search_button"),
557 "clicked",
558 G_CALLBACK (cancel_search_button_clicked_cb),
559 data);
560
561 /* run dialog. */
562
563 gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (window));
564 gtk_window_set_modal (GTK_WINDOW (data->dialog), FALSE);
565 gtk_widget_show (data->dialog);
566
567 start_searching (data);
568 }
569
570
571 /* -- auto fetch functions -- */
572
573
574 typedef struct {
575 GooWindow *window;
576 GCancellable *cancellable;
577 } FetchData;
578
579
580 static void
fetch_data_free(FetchData * data)581 fetch_data_free (FetchData *data)
582 {
583 _g_object_unref (data->cancellable);
584 g_free (data);
585 }
586
587
588 static void
image_data_ready_for_query_cb(void * buffer,gsize count,GError * error,gpointer user_data)589 image_data_ready_for_query_cb (void *buffer,
590 gsize count,
591 GError *error,
592 gpointer user_data)
593 {
594 FetchData *data = user_data;
595 gboolean success;
596
597 success = (error == NULL) && (count > 0);
598 if (success)
599 success = goo_window_set_cover_image_from_data (data->window, buffer, count);
600
601 if (! success)
602 fetch_cover_image_from_album_info (data->window,
603 goo_window_get_album (data->window),
604 FETCH_COVER_STAGE_AFTER_WEB_SEARCH,
605 data->cancellable);
606
607 fetch_data_free (data);
608 }
609
610
611 static void
query_ready_cb(void * buffer,gsize count,GError * error,gpointer user_data)612 query_ready_cb (void *buffer,
613 gsize count,
614 GError *error,
615 gpointer user_data)
616 {
617 FetchData *data = user_data;
618 GList *list;
619
620 if (error != NULL) {
621 fetch_data_free (data);
622 return;
623 }
624
625 list = make_file_list_from_search_result (buffer, count, 1);
626 if (list != NULL) {
627 GFile *file;
628
629 file = g_file_new_for_uri ((char *) list->data);
630 g_load_file_async (file,
631 G_PRIORITY_DEFAULT,
632 NULL,
633 image_data_ready_for_query_cb,
634 data);
635
636 g_object_unref (file);
637 }
638 else
639 fetch_data_free (data);
640
641 _g_string_list_free (list);
642 }
643
644
645 void
fetch_cover_image_from_name(GooWindow * window,const char * album,const char * artist,GCancellable * cancellable)646 fetch_cover_image_from_name (GooWindow *window,
647 const char *album,
648 const char *artist,
649 GCancellable *cancellable)
650 {
651 FetchData *data;
652 char *url;
653 GFile *file;
654
655 data = g_new0 (FetchData, 1);
656 data->window = window;
657 data->cancellable = _g_object_ref (cancellable);
658
659 url = get_query (album, artist);
660 file = g_file_new_for_uri (url);
661 g_load_file_async (file,
662 G_PRIORITY_DEFAULT,
663 data->cancellable,
664 query_ready_cb,
665 data);
666
667 g_object_unref (file);
668 g_free (url);
669 }
670
671
672 /* -- fetch_cover_image_from_asin -- */
673
674
675 static void
image_data_ready_for_asin_cb(void * buffer,gsize count,GError * error,gpointer user_data)676 image_data_ready_for_asin_cb (void *buffer,
677 gsize count,
678 GError *error,
679 gpointer user_data)
680 {
681 FetchData *data = user_data;
682 gboolean success;
683
684 success = (error == NULL) && (count > 0);
685 if (success)
686 success = goo_window_set_cover_image_from_data (data->window, buffer, count);
687
688 if (! success)
689 fetch_cover_image_from_album_info (data->window,
690 goo_window_get_album (data->window),
691 FETCH_COVER_STAGE_AFTER_ASIN,
692 data->cancellable);
693
694 fetch_data_free (data);
695 }
696
697
698 void
fetch_cover_image_from_asin(GooWindow * window,const char * asin,GCancellable * cancellable)699 fetch_cover_image_from_asin (GooWindow *window,
700 const char *asin,
701 GCancellable *cancellable)
702 {
703 FetchData *data;
704 char *url;
705 GFile *file;
706
707 data = g_new0 (FetchData, 1);
708 data->window = window;
709 data->cancellable = _g_object_ref (cancellable);
710
711 url = g_strdup_printf ("http://images.amazon.com/images/P/%s.01._SCLZZZZZZZ_.jpg", asin);
712 file = g_file_new_for_uri (url);
713 g_load_file_async (file,
714 G_PRIORITY_DEFAULT,
715 data->cancellable,
716 image_data_ready_for_asin_cb,
717 data);
718
719 g_object_unref (file);
720 g_free (url);
721 }
722
723
724 /* -- fetch_cover_image_from_album_info -- */
725
726
727 #if HAVE_LIBCOVERART
728
729
730 typedef struct {
731 GooWindow *window;
732 AlbumInfo *album;
733 guchar *buffer;
734 gsize size;
735 } GetCoverArtData;
736
737
738 static void
get_cover_art_data_free(GetCoverArtData * data)739 get_cover_art_data_free (GetCoverArtData *data)
740 {
741 g_object_unref (data->window);
742 album_info_unref (data->album);
743 g_free (data->buffer);
744 g_free (data);
745 }
746
747
748 static void
metadata_get_coverart_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)749 metadata_get_coverart_thread (GTask *task,
750 gpointer source_object,
751 gpointer task_data,
752 GCancellable *cancellable)
753 {
754 GetCoverArtData *data = task_data;
755 CaaCoverArt cover_art;
756 CaaImageData image_data;
757
758 cover_art = caa_coverart_new (PACKAGE_NAME "-" PACKAGE_VERSION);
759 image_data = caa_coverart_fetch_front (cover_art, data->album->id);
760 if (image_data != NULL) {
761 data->size = caa_imagedata_size (image_data);
762 data->buffer = g_new (guchar, data->size);
763 memcpy (data->buffer, caa_imagedata_data (image_data), data->size);
764 }
765
766 caa_coverart_delete (cover_art);
767 }
768
769
770 static void
metadata_get_coverart(GooWindow * window,AlbumInfo * album,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)771 metadata_get_coverart (GooWindow *window,
772 AlbumInfo *album,
773 GCancellable *cancellable,
774 GAsyncReadyCallback callback,
775 gpointer user_data)
776 {
777 GTask *task;
778 GetCoverArtData *data;
779
780 task = g_task_new (NULL, cancellable, callback, user_data);
781
782 data = g_new0 (GetCoverArtData, 1);
783 data->window = g_object_ref (window);
784 data->album = album_info_ref (album);
785 data->buffer = NULL;
786 data->size = 0;
787 g_task_set_task_data (task, data, (GDestroyNotify) get_cover_art_data_free);
788
789 g_task_run_in_thread (task, metadata_get_coverart_thread);
790
791 g_object_unref (task);
792 }
793
794
795 static gboolean
metadata_get_coverart_finish(GAsyncResult * result,guchar ** buffer,gsize * count)796 metadata_get_coverart_finish (GAsyncResult *result,
797 guchar **buffer,
798 gsize *count)
799 {
800 GetCoverArtData *data;
801
802 g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
803
804 data = g_task_get_task_data (G_TASK (result));
805 if (data->size == 0)
806 return FALSE;
807
808 *buffer = data->buffer;
809 *count = data->size;
810
811 return TRUE;
812 }
813
814
815 typedef struct {
816 GooWindow *window;
817 AlbumInfo *album;
818 GCancellable *cancellable;
819 } CoverArtData;
820
821
822 static void
cover_art_data_free(CoverArtData * data)823 cover_art_data_free (CoverArtData *data)
824 {
825 g_object_unref (data->window);
826 album_info_unref (data->album);
827 _g_object_unref (data->cancellable);
828 g_free (data);
829 }
830
831
832 static void
metadata_get_coverart_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)833 metadata_get_coverart_cb (GObject *source_object,
834 GAsyncResult *result,
835 gpointer user_data)
836 {
837 CoverArtData *data = user_data;
838 guchar *buffer;
839 gsize size;
840 gboolean success;
841
842 success = metadata_get_coverart_finish (result, &buffer, &size);
843 if (success)
844 success = goo_window_set_cover_image_from_data (data->window, buffer, size);
845
846 if (! success)
847 fetch_cover_image_from_album_info (data->window,
848 data->album,
849 FETCH_COVER_STAGE_AFTER_LIBCOVERART,
850 data->cancellable);
851
852 cover_art_data_free (data);
853 }
854
855
856 #endif
857
858
859 void
fetch_cover_image_from_album_info(GooWindow * window,AlbumInfo * album,FetchCoverStage after_stage,GCancellable * cancellable)860 fetch_cover_image_from_album_info (GooWindow *window,
861 AlbumInfo *album,
862 FetchCoverStage after_stage,
863 GCancellable *cancellable)
864 {
865 if ((cancellable != NULL) && g_cancellable_is_cancelled (cancellable))
866 return;
867
868 #if HAVE_LIBCOVERART
869
870 if ((FETCH_COVER_STAGE_AFTER_LIBCOVERART > after_stage)
871 && (album != NULL)
872 && (album->id != NULL))
873 {
874 CoverArtData *data;
875
876 data = g_new0 (CoverArtData, 1);
877 data->window = g_object_ref (window);
878 data->album = album_info_ref (album);
879 data->cancellable = _g_object_ref (cancellable);
880 metadata_get_coverart (data->window,
881 data->album,
882 data->cancellable,
883 metadata_get_coverart_cb,
884 data);
885
886 return;
887 }
888
889 #endif
890
891 if ((FETCH_COVER_STAGE_AFTER_ASIN > after_stage)
892 && (album != NULL)
893 && (album->asin != NULL))
894 {
895 fetch_cover_image_from_asin (window, album->asin, cancellable);
896 return;
897 }
898
899 if ((FETCH_COVER_STAGE_AFTER_WEB_SEARCH > after_stage)
900 && (album != NULL)
901 && (album->title != NULL)
902 && (album->artist != NULL))
903 {
904 fetch_cover_image_from_name (window, album->title, album->artist, cancellable);
905 }
906 }
907