1 /*************************************************************************/
2 /* Copyright (C) 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 <libsoup/soup.h>
34 
35 #include <libpeas/peas.h>
36 
37 #include "src/pragha.h"
38 #include "src/pragha-menubar.h"
39 #include "src/pragha-playlist.h"
40 #include "src/pragha-playlists-mgmt.h"
41 #include "src/pragha-musicobject-mgmt.h"
42 #include "src/pragha-hig.h"
43 #include "src/pragha-utils.h"
44 #include "src/pragha-window.h"
45 #include "src/xml_helper.h"
46 
47 #include "plugins/pragha-plugin-macros.h"
48 
49 #define PRAGHA_TYPE_TUNEIN_PLUGIN         (pragha_tunein_plugin_get_type ())
50 #define PRAGHA_TUNEIN_PLUGIN(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), PRAGHA_TYPE_TUNEIN_PLUGIN, PraghaTuneinPlugin))
51 #define PRAGHA_TUNEIN_PLUGIN_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), PRAGHA_TYPE_TUNEIN_PLUGIN, PraghaTuneinPlugin))
52 #define PRAGHA_IS_TUNEIN_PLUGIN(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), PRAGHA_TYPE_TUNEIN_PLUGIN))
53 #define PRAGHA_IS_TUNEIN_PLUGIN_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), PRAGHA_TYPE_TUNEIN_PLUGIN))
54 #define PRAGHA_TUNEIN_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PRAGHA_TYPE_TUNEIN_PLUGIN, PraghaTuneinPluginClass))
55 
56 struct _PraghaTuneinPluginPrivate {
57 	PraghaApplication *pragha;
58 
59 	GtkActionGroup    *action_group_main_menu;
60 	guint              merge_id_main_menu;
61 };
62 typedef struct _PraghaTuneinPluginPrivate PraghaTuneinPluginPrivate;
63 
64 PRAGHA_PLUGIN_REGISTER (PRAGHA_TYPE_TUNEIN_PLUGIN,
65                         PraghaTuneinPlugin,
66                         pragha_tunein_plugin)
67 
68 /*
69  * Prototypes
70  */
71 static void pragha_tunein_get_radio_dialog        (PraghaTuneinPlugin *plugin);
72 
73 /*
74  * Popups
75  */
76 
77 static void
pragha_tunein_plugin_get_radio_action(GtkAction * action,PraghaTuneinPlugin * plugin)78 pragha_tunein_plugin_get_radio_action (GtkAction *action, PraghaTuneinPlugin *plugin)
79 {
80 	pragha_tunein_get_radio_dialog (plugin);
81 }
82 
83 static void
pragha_gmenu_tunein_plugin_get_radio_action(GSimpleAction * action,GVariant * parameter,gpointer user_data)84 pragha_gmenu_tunein_plugin_get_radio_action (GSimpleAction *action,
85                                              GVariant      *parameter,
86                                              gpointer       user_data)
87 {
88 	pragha_tunein_get_radio_dialog (PRAGHA_TUNEIN_PLUGIN(user_data));
89 }
90 
91 static const GtkActionEntry main_menu_actions [] = {
92 	{"Search tunein", NULL, N_("Search radio on TuneIn"),
93 	 "", "Search tunein", G_CALLBACK(pragha_tunein_plugin_get_radio_action)}
94 };
95 
96 static const gchar *main_menu_xml = "<ui>						\
97 	<menubar name=\"Menubar\">									\
98 		<menu action=\"ToolsMenu\">								\
99 			<placeholder name=\"pragha-plugins-placeholder\">	\
100 				<menuitem action=\"Search tunein\"/>			\
101 				<separator/>									\
102 			</placeholder>										\
103 		</menu>													\
104 	</menubar>													\
105 </ui>";
106 
107 /*
108  * TuneIn Handlers
109  */
110 static const gchar *
tunein_helper_get_atribute(XMLNode * xml,const gchar * atribute)111 tunein_helper_get_atribute (XMLNode *xml, const gchar *atribute)
112 {
113 	XMLNode *xi;
114 
115 	xi = xmlnode_get (xml,CCA {"outline", NULL}, atribute, NULL);
116 
117 	if (xi)
118 		return xi->content;
119 
120 	return NULL;
121 }
122 
123 static void
pragha_tunein_plugin_get_radio_done(SoupSession * session,SoupMessage * msg,gpointer user_data)124 pragha_tunein_plugin_get_radio_done (SoupSession *session,
125                                      SoupMessage *msg,
126                                      gpointer     user_data)
127 {
128 	GtkWidget *window;
129 	PraghaPlaylist *playlist;
130 	PraghaDatabase *cdbase;
131 	PraghaMusicobject *mobj = NULL;
132 	XMLNode *xml = NULL, *xi;
133 	const gchar *type = NULL, *name = NULL, *url = NULL;
134 	gchar *uri_parsed, *name_fixed = NULL;
135 
136 	PraghaTuneinPlugin *plugin = user_data;
137 	PraghaTuneinPluginPrivate *priv = plugin->priv;
138 
139 	window = pragha_application_get_window (priv->pragha);
140 	remove_watch_cursor (window);
141 
142 	if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
143 		return;
144 
145 	xml = tinycxml_parse ((gchar *)msg->response_body->data);
146 	xi = xmlnode_get (xml, CCA{"opml", "body", "outline", NULL }, NULL, NULL);
147 
148 	type = tunein_helper_get_atribute (xi, "type");
149 	if (g_ascii_strcasecmp(type, "audio") != 0) {
150 		xmlnode_free(xml);
151 		return;
152 	}
153 
154 	name = tunein_helper_get_atribute (xi, "text");
155 	url = tunein_helper_get_atribute (xi, "URL");
156 
157 	if (string_is_empty(name) || string_is_empty(url)) {
158 		xmlnode_free(xml);
159 		return;
160 	}
161 
162 	name_fixed = unescape_HTML (name);
163 	uri_parsed = pragha_pl_get_first_playlist_item (url);
164 
165 	mobj = new_musicobject_from_location (uri_parsed, name_fixed);
166 
167 	playlist = pragha_application_get_playlist (priv->pragha);
168 	pragha_playlist_append_single_song (playlist, mobj);
169 	new_radio (playlist, uri_parsed, name_fixed);
170 
171 	cdbase = pragha_application_get_database (priv->pragha);
172 	pragha_database_change_playlists_done (cdbase);
173 
174 	xmlnode_free(xml);
175 
176 	g_free (name_fixed);
177 	g_free (uri_parsed);
178 }
179 
180 static void
pragha_tunein_plugin_get_radio(PraghaTuneinPlugin * plugin,const gchar * field)181 pragha_tunein_plugin_get_radio (PraghaTuneinPlugin *plugin, const gchar *field)
182 {
183 	GtkWidget *window;
184 	SoupSession *session;
185 	SoupMessage *msg;
186 	gchar *escaped_field = NULL, *query = NULL;
187 
188 	PraghaTuneinPluginPrivate *priv = plugin->priv;
189 
190 	window = pragha_application_get_window (priv->pragha);
191 	set_watch_cursor (window);
192 
193 	escaped_field = g_uri_escape_string (field, NULL, TRUE);
194 	query = g_strdup_printf ("%s%s", "http://opml.radiotime.com/Search.aspx?query=", escaped_field);
195 
196 	session = soup_session_sync_new ();
197 
198 	msg = soup_message_new ("GET", query);
199 	soup_session_queue_message (session, msg,
200 	                            pragha_tunein_plugin_get_radio_done, plugin);
201 
202 	g_free (escaped_field);
203 	g_free (query);
204 }
205 
206 /*
207  * TuneIn dialog
208  */
209 static void
pragha_tunein_get_radio_dialog(PraghaTuneinPlugin * plugin)210 pragha_tunein_get_radio_dialog (PraghaTuneinPlugin *plugin)
211 {
212 	GtkWidget *dialog, *parent;
213 	GtkWidget *table, *entry;
214 	gint result;
215 	guint row = 0;
216 
217 	PraghaTuneinPluginPrivate *priv = plugin->priv;
218 
219 	parent = pragha_application_get_window (priv->pragha);
220 	dialog = gtk_dialog_new_with_buttons (_("Search in TuneIn"),
221 	                                      GTK_WINDOW(parent),
222 	                                      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
223 	                                      _("_Cancel"), GTK_RESPONSE_CANCEL,
224 	                                      _("_Ok"), GTK_RESPONSE_ACCEPT,
225 	                                      NULL);
226 
227 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
228 
229 	table = pragha_hig_workarea_table_new ();
230 
231 	pragha_hig_workarea_table_add_section_title (table, &row, _("Search in TuneIn"));
232 
233 	entry = gtk_entry_new ();
234 	gtk_entry_set_max_length (GTK_ENTRY(entry), 255);
235 	gtk_entry_set_activates_default (GTK_ENTRY(entry), TRUE);
236 
237 	pragha_hig_workarea_table_add_wide_control (table, &row, entry);
238 
239 	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), table);
240 
241 	gtk_widget_show_all(dialog);
242 
243 	result = gtk_dialog_run(GTK_DIALOG(dialog));
244 	switch(result) {
245 	case GTK_RESPONSE_ACCEPT:
246 		pragha_tunein_plugin_get_radio(plugin, gtk_entry_get_text(GTK_ENTRY(entry)));
247 		break;
248 	case GTK_RESPONSE_CANCEL:
249 		break;
250 	default:
251 		break;
252 	}
253 	gtk_widget_destroy (dialog);
254 }
255 
256 /*
257  * TuneIn plugin
258  */
259 static void
pragha_plugin_activate(PeasActivatable * activatable)260 pragha_plugin_activate (PeasActivatable *activatable)
261 {
262 	GMenuItem *item;
263 	GSimpleAction *action;
264 
265 	PraghaTuneinPlugin *plugin = PRAGHA_TUNEIN_PLUGIN (activatable);
266 
267 	PraghaTuneinPluginPrivate *priv = plugin->priv;
268 	priv->pragha = g_object_get_data (G_OBJECT (plugin), "object");
269 
270 	CDEBUG(DBG_PLUGIN, "TuneIn plugin %s", G_STRFUNC);
271 
272 	/* Attach main menu */
273 
274 	priv->action_group_main_menu = gtk_action_group_new ("PraghaTuneinPlugin");
275 	gtk_action_group_set_translation_domain (priv->action_group_main_menu, GETTEXT_PACKAGE);
276 	gtk_action_group_add_actions (priv->action_group_main_menu,
277 	                              main_menu_actions,
278 	                              G_N_ELEMENTS (main_menu_actions),
279 	                              plugin);
280 
281 	priv->merge_id_main_menu = pragha_menubar_append_plugin_action (priv->pragha,
282 	                                                                priv->action_group_main_menu,
283 	                                                                main_menu_xml);
284 
285 	/* Gear Menu */
286 
287 	action = g_simple_action_new ("search-tunein", NULL);
288 	g_signal_connect (G_OBJECT (action), "activate",
289 	                  G_CALLBACK (pragha_gmenu_tunein_plugin_get_radio_action), plugin);
290 
291 	item = g_menu_item_new (_("Search radio on TuneIn"), "win.search-tunein");
292 
293 	pragha_menubar_append_action (priv->pragha, "pragha-plugins-placeholder", action, item);
294 }
295 
296 static void
pragha_plugin_deactivate(PeasActivatable * activatable)297 pragha_plugin_deactivate (PeasActivatable *activatable)
298 {
299 	PraghaTuneinPlugin *plugin = PRAGHA_TUNEIN_PLUGIN (activatable);
300 	PraghaTuneinPluginPrivate *priv = plugin->priv;
301 
302 	CDEBUG(DBG_PLUGIN, "TuneIn plugin %s", G_STRFUNC);
303 
304 	pragha_menubar_remove_plugin_action (priv->pragha,
305 	                                     priv->action_group_main_menu,
306 	                                     priv->merge_id_main_menu);
307 	priv->merge_id_main_menu = 0;
308 
309 	pragha_menubar_remove_action (priv->pragha, "pragha-plugins-placeholder", "search-tunein");
310 }
311