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