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