1 /*************************************************************************/
2 /* Copyright (C) 2011-2014 matias <mati86dl@gmail.com> */
3 /* */
4 /* This program is free software: you can redistribute it and/or modify */
5 /* it under the terms of the GNU General Public License as published by */
6 /* the Free Software Foundation, either version 3 of the License, or */
7 /* (at your option) any later version. */
8 /* */
9 /* This program is distributed in the hope that it will be useful, */
10 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
11 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
12 /* GNU General Public License for more details. */
13 /* */
14 /* You should have received a copy of the GNU General Public License */
15 /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
16 /*************************************************************************/
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21
22 #if defined(GETTEXT_PACKAGE)
23 #include <glib/gi18n-lib.h>
24 #else
25 #include <glib/gi18n.h>
26 #endif
27
28 #include <glib.h>
29 #include <glib-object.h>
30 #include <gmodule.h>
31 #include <gtk/gtk.h>
32
33 #include <glyr/glyr.h>
34 #include <glyr/cache.h>
35
36 #include <glib/gstdio.h>
37
38 #include <libpeas/peas.h>
39 #include <libpeas-gtk/peas-gtk.h>
40
41 #include "plugins/pragha-plugin-macros.h"
42
43 #include "pragha-song-info-plugin.h"
44 #include "pragha-song-info-dialog.h"
45 #include "pragha-song-info-pane.h"
46 #include "pragha-song-info-thread-albumart.h"
47 #include "pragha-song-info-thread-dialog.h"
48 #include "pragha-song-info-thread-pane.h"
49
50 #include "src/pragha.h"
51 #include "src/pragha-hig.h"
52 #include "src/pragha-playback.h"
53 #include "src/pragha-sidebar.h"
54 #include "src/pragha-simple-async.h"
55 #include "src/pragha-simple-widgets.h"
56 #include "src/pragha-preferences-dialog.h"
57 #include "src/pragha-utils.h"
58
59 struct _PraghaSongInfoPluginPrivate {
60 PraghaApplication *pragha;
61 GtkWidget *setting_widget;
62
63 PraghaSonginfoPane *pane;
64
65 GlyrDatabase *cache_db;
66
67 gboolean download_album_art;
68 GtkWidget *download_album_art_w;
69
70 GtkActionGroup *action_group_playlist;
71 guint merge_id_playlist;
72
73 GCancellable *pane_search;
74 };
75
76 PRAGHA_PLUGIN_REGISTER_PRIVATE_CODE (PRAGHA_TYPE_SONG_INFO_PLUGIN,
77 PraghaSongInfoPlugin,
78 pragha_song_info_plugin)
79
80 /*
81 * Popups
82 */
83
84 static void get_lyric_current_playlist_action (GtkAction *action, PraghaSongInfoPlugin *plugin);
85 static void get_artist_info_current_playlist_action (GtkAction *action, PraghaSongInfoPlugin *plugin);
86
87 static const GtkActionEntry playlist_actions [] = {
88 {"Search lyric", NULL, N_("Search _lyric"),
89 "", "Search lyric", G_CALLBACK(get_lyric_current_playlist_action)},
90 {"Search artist info", NULL, N_("Search _artist info"),
91 "", "Search artist info", G_CALLBACK(get_artist_info_current_playlist_action)},
92 };
93
94 static const gchar *playlist_xml = "<ui> \
95 <popup name=\"SelectionPopup\"> \
96 <menu action=\"ToolsMenu\"> \
97 <placeholder name=\"pragha-glyr-placeholder\"> \
98 <menuitem action=\"Search lyric\"/> \
99 <menuitem action=\"Search artist info\"/> \
100 <separator/> \
101 </placeholder> \
102 </menu> \
103 </popup> \
104 </ui>";
105
106 /*
107 * Action on playlist that show a dialog
108 */
109
110 static void
get_artist_info_current_playlist_action(GtkAction * action,PraghaSongInfoPlugin * plugin)111 get_artist_info_current_playlist_action (GtkAction *action, PraghaSongInfoPlugin *plugin)
112 {
113 PraghaPlaylist *playlist;
114 PraghaMusicobject *mobj;
115 const gchar *artist = NULL;
116
117 PraghaApplication *pragha = NULL;
118
119 pragha = plugin->priv->pragha;
120 playlist = pragha_application_get_playlist (pragha);
121
122 mobj = pragha_playlist_get_selected_musicobject (playlist);
123
124 artist = pragha_musicobject_get_artist (mobj);
125
126 CDEBUG(DBG_INFO, "Get Artist info Action of current playlist selection");
127
128 if (string_is_empty(artist))
129 return;
130
131 pragha_songinfo_plugin_get_info_to_dialog (plugin, GLYR_GET_ARTISTBIO, artist, NULL);
132 }
133
134 static void
get_lyric_current_playlist_action(GtkAction * action,PraghaSongInfoPlugin * plugin)135 get_lyric_current_playlist_action (GtkAction *action, PraghaSongInfoPlugin *plugin)
136 {
137 PraghaPlaylist *playlist;
138 PraghaMusicobject *mobj;
139 const gchar *artist = NULL;
140 const gchar *title = NULL;
141
142 PraghaApplication *pragha = NULL;
143 pragha = plugin->priv->pragha;
144
145 playlist = pragha_application_get_playlist (pragha);
146 mobj = pragha_playlist_get_selected_musicobject (playlist);
147
148 artist = pragha_musicobject_get_artist (mobj);
149 title = pragha_musicobject_get_title (mobj);
150
151 CDEBUG(DBG_INFO, "Get lyrics Action of current playlist selection.");
152
153 if (string_is_empty(artist) || string_is_empty(title))
154 return;
155
156 pragha_songinfo_plugin_get_info_to_dialog (plugin, GLYR_GET_LYRICS, artist, title);
157 }
158
159 /*
160 * Handlers depending on backend status
161 */
162
163 static void
related_get_album_art_handler(PraghaSongInfoPlugin * plugin)164 related_get_album_art_handler (PraghaSongInfoPlugin *plugin)
165 {
166 PraghaBackend *backend;
167 PraghaArtCache *art_cache;
168 PraghaMusicobject *mobj;
169 const gchar *artist = NULL;
170 const gchar *album = NULL;
171 gchar *album_art_path;
172
173 CDEBUG(DBG_INFO, "Get album art handler");
174
175 backend = pragha_application_get_backend (plugin->priv->pragha);
176 if (pragha_backend_get_state (backend) == ST_STOPPED)
177 return;
178
179 mobj = pragha_backend_get_musicobject (backend);
180 artist = pragha_musicobject_get_artist (mobj);
181 album = pragha_musicobject_get_album (mobj);
182
183 if (string_is_empty(artist) || string_is_empty(album))
184 return;
185
186 art_cache = pragha_application_get_art_cache (plugin->priv->pragha);
187 album_art_path = pragha_art_cache_get_uri (art_cache, artist, album);
188
189 if (album_art_path)
190 goto exists;
191
192 pragha_songinfo_plugin_get_album_art (plugin, artist, album);
193
194 exists:
195 g_free(album_art_path);
196 }
197
198 static void
cancel_pane_search(PraghaSongInfoPlugin * plugin)199 cancel_pane_search (PraghaSongInfoPlugin *plugin)
200 {
201 PraghaSongInfoPluginPrivate *priv = plugin->priv;
202
203 if (priv->pane_search) {
204 g_cancellable_cancel (priv->pane_search);
205 g_object_unref (priv->pane_search);
206 priv->pane_search = NULL;
207 }
208 }
209
210 static void
related_get_song_info_pane_handler(PraghaSongInfoPlugin * plugin)211 related_get_song_info_pane_handler (PraghaSongInfoPlugin *plugin)
212 {
213 PraghaSongInfoPluginPrivate *priv = plugin->priv;
214 PraghaBackend *backend;
215 PraghaMusicobject *mobj;
216 const gchar *artist = NULL;
217 const gchar *title = NULL;
218 const gchar *filename = NULL;
219
220 CDEBUG (DBG_INFO, "Get song info handler");
221
222 backend = pragha_application_get_backend (plugin->priv->pragha);
223 if (pragha_backend_get_state (backend) == ST_STOPPED) {
224 pragha_songinfo_pane_clear_text (plugin->priv->pane);
225 return;
226 }
227
228 mobj = pragha_backend_get_musicobject (backend);
229 artist = pragha_musicobject_get_artist (mobj);
230 title = pragha_musicobject_get_title (mobj);
231 filename = pragha_musicobject_get_file (mobj);
232
233 if (string_is_empty(artist) || string_is_empty(title))
234 return;
235
236 cancel_pane_search (plugin);
237 priv->pane_search = pragha_songinfo_plugin_get_info_to_pane (plugin, pragha_songinfo_pane_get_default_view(plugin->priv->pane), artist, title, filename);
238 }
239
240 static void
pragha_song_info_get_info(gpointer data)241 pragha_song_info_get_info (gpointer data)
242 {
243 PraghaSongInfoPlugin *plugin = data;
244 PraghaSongInfoPluginPrivate *priv = plugin->priv;
245
246 if (priv->download_album_art)
247 related_get_album_art_handler (plugin);
248
249 if (gtk_widget_is_visible(GTK_WIDGET(priv->pane)))
250 related_get_song_info_pane_handler (plugin);
251 }
252
253 static void
backend_changed_state_cb(PraghaBackend * backend,GParamSpec * pspec,gpointer user_data)254 backend_changed_state_cb (PraghaBackend *backend, GParamSpec *pspec, gpointer user_data)
255 {
256 PraghaMusicSource file_source = FILE_NONE;
257 PraghaBackendState state = 0;
258
259 PraghaSongInfoPlugin *plugin = user_data;
260
261 cancel_pane_search (plugin);
262
263 state = pragha_backend_get_state (backend);
264
265 CDEBUG(DBG_INFO, "Configuring thread to get the cover art");
266
267 if (state == ST_STOPPED)
268 pragha_songinfo_pane_clear_text (plugin->priv->pane);
269
270 if (state != ST_PLAYING)
271 return;
272
273 file_source = pragha_musicobject_get_source (pragha_backend_get_musicobject (backend));
274
275 if (file_source == FILE_NONE) {
276 pragha_songinfo_pane_clear_text (plugin->priv->pane);
277 return;
278 }
279
280 pragha_song_info_get_info (plugin);
281 }
282
283 /*
284 * Update handlers
285 */
286
287 static void
pragha_songinfo_pane_type_changed(PraghaSonginfoPane * pane,PraghaSongInfoPlugin * plugin)288 pragha_songinfo_pane_type_changed (PraghaSonginfoPane *pane, PraghaSongInfoPlugin *plugin)
289 {
290 related_get_song_info_pane_handler (plugin);
291 }
292
293 static void
pragha_songinfo_pane_visibility_changed(PraghaPreferences * preferences,GParamSpec * pspec,PraghaSongInfoPlugin * plugin)294 pragha_songinfo_pane_visibility_changed (PraghaPreferences *preferences, GParamSpec *pspec, PraghaSongInfoPlugin *plugin)
295 {
296 if (pragha_preferences_get_secondary_lateral_panel (preferences))
297 related_get_song_info_pane_handler (plugin);
298 }
299
300 /*
301 * Public api
302 */
303
304 GlyrDatabase *
pragha_songinfo_plugin_get_cache(PraghaSongInfoPlugin * plugin)305 pragha_songinfo_plugin_get_cache (PraghaSongInfoPlugin *plugin)
306 {
307 PraghaSongInfoPluginPrivate *priv = plugin->priv;
308
309 return priv->cache_db;
310 }
311
312 PraghaSonginfoPane *
pragha_songinfo_plugin_get_pane(PraghaSongInfoPlugin * plugin)313 pragha_songinfo_plugin_get_pane (PraghaSongInfoPlugin *plugin)
314 {
315 PraghaSongInfoPluginPrivate *priv = plugin->priv;
316
317 return priv->pane;
318 }
319
320 PraghaApplication *
pragha_songinfo_plugin_get_application(PraghaSongInfoPlugin * plugin)321 pragha_songinfo_plugin_get_application (PraghaSongInfoPlugin *plugin)
322 {
323 PraghaSongInfoPluginPrivate *priv = plugin->priv;
324
325 return priv->pragha;
326 }
327
328 /*
329 * Preferences plugin
330 */
331
332 static void
pragha_songinfo_preferences_dialog_response(GtkDialog * dialog,gint response_id,PraghaSongInfoPlugin * plugin)333 pragha_songinfo_preferences_dialog_response (GtkDialog *dialog,
334 gint response_id,
335 PraghaSongInfoPlugin *plugin)
336 {
337 PraghaPreferences *preferences;
338 gchar *plugin_group = NULL;
339
340 PraghaSongInfoPluginPrivate *priv = plugin->priv;
341
342 switch(response_id) {
343 case GTK_RESPONSE_CANCEL:
344 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(priv->download_album_art_w),
345 priv->download_album_art);
346 break;
347 case GTK_RESPONSE_OK:
348 priv->download_album_art =
349 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->download_album_art_w));
350
351 preferences = pragha_preferences_get ();
352 plugin_group = pragha_preferences_get_plugin_group_name(preferences, "song-info");
353 pragha_preferences_set_boolean (preferences,
354 plugin_group, "DownloadAlbumArt",
355 priv->download_album_art);
356 g_object_unref (preferences);
357 g_free (plugin_group);
358 break;
359 default:
360 break;
361 }
362 }
363
364 static void
pragha_songinfo_plugin_append_setting(PraghaSongInfoPlugin * plugin)365 pragha_songinfo_plugin_append_setting (PraghaSongInfoPlugin *plugin)
366 {
367 PreferencesDialog *dialog;
368 PraghaPreferences *preferences = NULL;
369 gchar *plugin_group = NULL;
370 GtkWidget *table, *download_album_art_w;
371 guint row = 0;
372
373 PraghaSongInfoPluginPrivate *priv = plugin->priv;
374
375 table = pragha_hig_workarea_table_new ();
376
377 pragha_hig_workarea_table_add_section_title(table, &row, _("Song Information"));
378
379 download_album_art_w = gtk_check_button_new_with_label (_("Download the album art while playing their songs."));
380 pragha_hig_workarea_table_add_wide_control (table, &row, download_album_art_w);
381
382 preferences = pragha_preferences_get ();
383 plugin_group = pragha_preferences_get_plugin_group_name(preferences, "song-info");
384
385 priv->download_album_art =
386 pragha_preferences_get_boolean (preferences, plugin_group, "DownloadAlbumArt");
387 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(download_album_art_w),
388 priv->download_album_art);
389
390 priv->setting_widget = table;
391 priv->download_album_art_w = download_album_art_w;
392
393 dialog = pragha_application_get_preferences_dialog (priv->pragha);
394 pragha_preferences_append_services_setting (dialog, table, FALSE);
395
396 pragha_preferences_dialog_connect_handler (dialog,
397 G_CALLBACK(pragha_songinfo_preferences_dialog_response),
398 plugin);
399
400 g_object_unref (G_OBJECT (preferences));
401 g_free (plugin_group);
402 }
403
404 static void
pragha_songinfo_plugin_remove_setting(PraghaSongInfoPlugin * plugin)405 pragha_songinfo_plugin_remove_setting (PraghaSongInfoPlugin *plugin)
406 {
407 PreferencesDialog *dialog;
408 PraghaSongInfoPluginPrivate *priv = plugin->priv;
409
410 dialog = pragha_application_get_preferences_dialog (priv->pragha);
411
412 pragha_preferences_dialog_disconnect_handler (dialog,
413 G_CALLBACK(pragha_songinfo_preferences_dialog_response),
414 plugin);
415
416 pragha_preferences_remove_services_setting (dialog, priv->setting_widget);
417 }
418
419 /*
420 * Plugin
421 */
422 static void
pragha_plugin_activate(PeasActivatable * activatable)423 pragha_plugin_activate (PeasActivatable *activatable)
424 {
425 PraghaPreferences *preferences;
426 PraghaPlaylist *playlist;
427 PraghaSidebar *sidebar;
428 gchar *cache_folder = NULL;
429
430 PraghaSongInfoPlugin *plugin = PRAGHA_SONG_INFO_PLUGIN (activatable);
431 PraghaSongInfoPluginPrivate *priv = plugin->priv;
432
433 CDEBUG(DBG_PLUGIN, "Song-info plugin %s", G_STRFUNC);
434
435 priv->pragha = g_object_get_data (G_OBJECT (plugin), "object");
436
437 glyr_init ();
438
439 cache_folder = g_build_path (G_DIR_SEPARATOR_S, g_get_user_cache_dir (), "pragha", NULL);
440
441 g_mkdir_with_parents (cache_folder, S_IRWXU);
442 priv->cache_db = glyr_db_init (cache_folder);
443 g_free (cache_folder);
444
445 /* Attach Playlist popup menu*/
446 priv->action_group_playlist = gtk_action_group_new ("PraghaGlyrPlaylistActions");
447 gtk_action_group_set_translation_domain (priv->action_group_playlist, GETTEXT_PACKAGE);
448 gtk_action_group_add_actions (priv->action_group_playlist,
449 playlist_actions,
450 G_N_ELEMENTS (playlist_actions),
451 plugin);
452
453 playlist = pragha_application_get_playlist (priv->pragha);
454 priv->merge_id_playlist = pragha_playlist_append_plugin_action (playlist,
455 priv->action_group_playlist,
456 playlist_xml);
457
458 /* Create the pane and attach it */
459 priv->pane = pragha_songinfo_pane_new ();
460 sidebar = pragha_application_get_second_sidebar (priv->pragha);
461 pragha_sidebar_attach_plugin (sidebar,
462 GTK_WIDGET (priv->pane),
463 pragha_songinfo_pane_get_pane_title (priv->pane),
464 pragha_songinfo_pane_get_popup_menu (priv->pane));
465
466 /* Connect signals */
467
468 g_signal_connect (pragha_application_get_backend (priv->pragha), "notify::state",
469 G_CALLBACK (backend_changed_state_cb), plugin);
470 backend_changed_state_cb (pragha_application_get_backend (priv->pragha), NULL, plugin);
471
472 preferences = pragha_application_get_preferences (priv->pragha);
473
474 g_signal_connect (G_OBJECT(preferences), "notify::secondary-lateral-panel",
475 G_CALLBACK(pragha_songinfo_pane_visibility_changed), plugin);
476
477 g_signal_connect (G_OBJECT(priv->pane), "type-changed",
478 G_CALLBACK(pragha_songinfo_pane_type_changed), plugin);
479
480 /* Default values */
481
482 pragha_songinfo_plugin_append_setting (plugin);
483 }
484
485 static void
pragha_plugin_deactivate(PeasActivatable * activatable)486 pragha_plugin_deactivate (PeasActivatable *activatable)
487 {
488 PraghaApplication *pragha = NULL;
489 PraghaPreferences *preferences;
490 PraghaPlaylist *playlist;
491 PraghaSidebar *sidebar;
492 gchar *plugin_group = NULL;
493
494 PraghaSongInfoPlugin *plugin = PRAGHA_SONG_INFO_PLUGIN (activatable);
495 PraghaSongInfoPluginPrivate *priv = plugin->priv;
496
497 pragha = plugin->priv->pragha;
498
499 CDEBUG(DBG_PLUGIN, "SongInfo plugin %s", G_STRFUNC);
500
501 g_signal_handlers_disconnect_by_func (pragha_application_get_backend (pragha),
502 backend_changed_state_cb, plugin);
503
504 playlist = pragha_application_get_playlist (pragha);
505 pragha_playlist_remove_plugin_action (playlist,
506 priv->action_group_playlist,
507 priv->merge_id_playlist);
508
509 priv->merge_id_playlist = 0;
510
511 preferences = pragha_application_get_preferences (pragha);
512
513 g_signal_handlers_disconnect_by_func (G_OBJECT(preferences),
514 pragha_songinfo_pane_visibility_changed,
515 plugin);
516
517 g_signal_handlers_disconnect_by_func (G_OBJECT(preferences),
518 pragha_songinfo_pane_type_changed,
519 plugin);
520
521 plugin_group = pragha_preferences_get_plugin_group_name (preferences, "song-info");
522 if (!pragha_plugins_is_shutdown(pragha_application_get_plugins_engine(priv->pragha))) {
523 pragha_preferences_remove_group (preferences, plugin_group);
524 }
525 g_free (plugin_group);
526
527 sidebar = pragha_application_get_second_sidebar (priv->pragha);
528 pragha_sidebar_remove_plugin (sidebar, GTK_WIDGET(priv->pane));
529
530 pragha_songinfo_plugin_remove_setting (plugin);
531
532 glyr_db_destroy (priv->cache_db);
533
534 glyr_cleanup ();
535
536 priv->pragha = NULL;
537 }
538