1 /* gmpc-lastfmradio (GMPC plugin)
2 * Copyright (C) 2008-2009 Qball Cow <qball@sarine.nl>
3 * Project homepage: http://gmpcwiki.sarine.nl/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <gmpc/plugin.h>
22 #include <gmpc/config1.h>
23 #include <gmpc/gmpc-metaimage.h>
25 #include <gmpc/playlist3-messages.h>
26 #include "lfr_plugin.h"
30 /* The plugin structure */
33 /* This keeps a reference to the browser in the left row */
34 static GtkTreeRowReference
*lfr_ref
= NULL
;
35 /* The widget that holds the browser view */
36 static GtkWidget
*lfr_vbox
= NULL
;
39 static LastFM
*lfm
= NULL
;
41 * Destroy, init and saving
43 static void lfr_init(void)
46 gchar
*path
= gmpc_plugin_get_data_path(&plugin
);
47 gchar
*url
= g_build_path(G_DIR_SEPARATOR_S
,path
, "lfr", NULL
);
48 debug_printf(DEBUG_WARNING
,"Found url: %s\n", url
);
49 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default (),url
);
54 // gtk_icon_theme_append_search_path(gtk_icon_theme_get_default (),DATA_DIR);
56 g_assert(lfm
== NULL
);
59 static void lfr_destroy(void)
61 /* remove the extra reference */
62 if(lfr_vbox
) {g_object_unref(lfr_vbox
);lfr_vbox
= NULL
;}
63 if(lfm
) {g_object_unref(lfm
);lfm
= NULL
;}
66 static void lfr_save_myself(void)
68 /* Save the position in the left tree */
71 GtkTreePath
*path
= gtk_tree_row_reference_get_path(lfr_ref
);
74 gint
*indices
= gtk_tree_path_get_indices(path
);
75 debug_printf(DEBUG_INFO
,"Saving myself '%s' to position: %i\n",plugin
.name
, indices
[0]);
76 cfg_set_single_value_as_int(config
, CONFIG_NAME
,"position",indices
[0]);
77 gtk_tree_path_free(path
);
85 static GtkWidget
*connection_warning_box
= NULL
;
86 static GtkWidget
*rest_box
= NULL
;
87 static GtkWidget
*user_label
= NULL
;
88 static GtkWidget
*my_station_combo
= NULL
;
89 static GtkWidget
*progressbar
= NULL
;
90 static GtkWidget
*song_info_box
= NULL
;
92 static void lfr_browser_conn_changed(LastFM
*l
, gboolean connected
,gpointer data
)
95 gchar
*str
= g_markup_printf_escaped("<span size='xx-large'>%s's Last.FM Dashboard</span>",
96 last_fm_get_username(lfm
));
98 gtk_label_set_markup(GTK_LABEL(user_label
),str
);
100 gtk_widget_show_all(rest_box
);
101 gtk_widget_hide(connection_warning_box
);
103 gtk_widget_hide(rest_box
);
104 gtk_widget_show_all(connection_warning_box
);
107 void play_path(const gchar
*path
);
108 static void lfr_browser_play_stream(LastFM
*l
, const gchar
*stream
, gpointer data
)
112 static void lfr_browser_error_callback(LastFM
*l
,gboolean fatal
, const gchar
*errormsg
, gpointer data
)
114 playlist3_show_error_message(errormsg
, (fatal
)?ERROR_CRITICAL
:ERROR_WARNING
);
116 guint pb_timeout
= 0;
117 static gboolean
lfr_browser_pulse(GtkProgressBar
*pb
)
119 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(pb
));
122 static void lfr_browser_processing(LastFM
*l
, gboolean processing
, gpointer data
)
126 gtk_widget_set_sensitive(rest_box
, FALSE
);
127 gtk_widget_show(progressbar
);
128 if(pb_timeout
== 0) {
129 pb_timeout
= g_timeout_add(100, (GSourceFunc
)lfr_browser_pulse
, progressbar
);
132 gtk_widget_set_sensitive(rest_box
, TRUE
);
133 gtk_widget_hide(progressbar
);
135 g_source_remove(pb_timeout
);
139 extern GmpcConnection
*gmpcconn
;
141 static void lfr_browser_song_info(LastFM
*l
, mpd_Song
*song
, gpointer data
)
143 GtkWidget
*label
= NULL
;
144 GtkWidget
*hbox
= gtk_table_new(3, 3,FALSE
);
145 GtkWidget
*temp
= gtk_bin_get_child(GTK_BIN(song_info_box
));
147 if(cfg_get_single_value_as_int_with_default(config
, CONFIG_NAME
, "dirty-hack", FALSE
) == 0)
150 gtk_widget_destroy(temp
);
153 gtk_table_set_row_spacings(GTK_TABLE(hbox
), 6);
154 gtk_table_set_col_spacings(GTK_TABLE(hbox
), 6);
155 gtk_container_set_border_width(GTK_CONTAINER(hbox
), 6);
157 label
= gtk_label_new("");
158 gtk_misc_set_alignment(GTK_MISC(label
), 1.0,0.5);
159 gtk_label_set_markup(GTK_LABEL(label
),"<b>Track</b>");
160 gtk_table_attach(GTK_TABLE(hbox
), label
,1,2,0,1,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
161 label
= gtk_label_new(song
->title
);
162 gtk_misc_set_alignment(GTK_MISC(label
), 0.0,0.5);
163 gtk_table_attach(GTK_TABLE(hbox
), label
,2,3,0,1,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
165 label
= gtk_label_new("");
166 gtk_misc_set_alignment(GTK_MISC(label
), 1.0,0.5);
167 gtk_label_set_markup(GTK_LABEL(label
),"<b>Artist</b>");
168 gtk_table_attach(GTK_TABLE(hbox
), label
,1,2,1,2,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
169 label
= gtk_label_new(song
->artist
);
170 gtk_misc_set_alignment(GTK_MISC(label
), 0.0,0.5);
171 gtk_table_attach(GTK_TABLE(hbox
), label
,2,3,1,2,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
173 label
= gtk_label_new("");
174 gtk_misc_set_alignment(GTK_MISC(label
), 1.0,0.5);
175 gtk_label_set_markup(GTK_LABEL(label
),"<b>Album</b>");
176 gtk_table_attach(GTK_TABLE(hbox
), label
,1,2,2,3,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
177 label
= gtk_label_new(song
->album
);
178 gtk_misc_set_alignment(GTK_MISC(label
), 0.0,0.5);
179 gtk_table_attach(GTK_TABLE(hbox
), label
,2,3,2,3,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
181 label
= gmpc_metaimage_new_size(META_ALBUM_ART
,96);
182 gmpc_metaimage_update_cover_from_song(GMPC_METAIMAGE(label
), song
);
183 gtk_table_attach(GTK_TABLE(hbox
), label
,0,1,0,3,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
185 gtk_widget_show_all(hbox
);
186 gtk_container_add(GTK_CONTAINER(song_info_box
), hbox
);
189 else if(song
&& song
->artist
)
191 mpd_Song
*song2
= mpd_playlist_get_current_song(connection
);
194 if(song
->artist
) changed
+= (strcmp(song2
->artist
, song
->artist
) != 0);
196 g_free(song2
->artist
);
197 song2
->artist
= g_strdup(song
->artist
);
198 }else if(song
->artist
) {
200 song2
->artist
= g_strdup(song
->artist
);
203 if(song
->album
) changed
+= (strcmp(song2
->album
, song
->album
) != 0);
205 g_free(song2
->album
);
206 song2
->album
= g_strdup(song
->album
);
207 }else if (song
->album
)
210 song2
->album
= g_strdup(song
->album
);
213 if(song
->title
) changed
+= (strcmp(song2
->title
, song
->title
) != 0);
215 g_free(song2
->title
);
216 song2
->title
= g_strdup(song
->title
);
217 }else if (song
->title
)
220 song2
->title
= g_strdup(song
->title
);
224 gmpc_connection_status_changed(gmpcconn
,connection
, MPD_CST_SONGID
|MPD_CST_SONGPOS
);
226 gtk_widget_destroy(temp
);
229 gtk_table_set_row_spacings(GTK_TABLE(hbox
), 6);
230 gtk_table_set_col_spacings(GTK_TABLE(hbox
), 6);
231 gtk_container_set_border_width(GTK_CONTAINER(hbox
), 6);
233 label
= gtk_label_new("");
234 gtk_misc_set_alignment(GTK_MISC(label
), 1.0,0.5);
235 gtk_label_set_markup(GTK_LABEL(label
),"<b>Track</b>");
236 gtk_table_attach(GTK_TABLE(hbox
), label
,1,2,0,1,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
237 label
= gtk_label_new(song
->title
);
238 gtk_misc_set_alignment(GTK_MISC(label
), 0.0,0.5);
239 gtk_table_attach(GTK_TABLE(hbox
), label
,2,3,0,1,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
241 label
= gtk_label_new("");
242 gtk_misc_set_alignment(GTK_MISC(label
), 1.0,0.5);
243 gtk_label_set_markup(GTK_LABEL(label
),"<b>Artist</b>");
244 gtk_table_attach(GTK_TABLE(hbox
), label
,1,2,1,2,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
245 label
= gtk_label_new(song
->artist
);
246 gtk_misc_set_alignment(GTK_MISC(label
), 0.0,0.5);
247 gtk_table_attach(GTK_TABLE(hbox
), label
,2,3,1,2,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
249 label
= gtk_label_new("");
250 gtk_misc_set_alignment(GTK_MISC(label
), 1.0,0.5);
251 gtk_label_set_markup(GTK_LABEL(label
),"<b>Album</b>");
252 gtk_table_attach(GTK_TABLE(hbox
), label
,1,2,2,3,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
253 label
= gtk_label_new(song
->album
);
254 gtk_misc_set_alignment(GTK_MISC(label
), 0.0,0.5);
255 gtk_table_attach(GTK_TABLE(hbox
), label
,2,3,2,3,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
257 label
= gmpc_metaimage_new_size(META_ALBUM_ART
,96);
258 gmpc_metaimage_update_cover_from_song(GMPC_METAIMAGE(label
), song
);
259 gtk_table_attach(GTK_TABLE(hbox
), label
,0,1,0,3,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
261 gtk_widget_show_all(hbox
);
262 gtk_container_add(GTK_CONTAINER(song_info_box
), hbox
);
269 gtk_widget_destroy(temp
);
274 gulong lfm_update_timeout
= 0;
275 static int lfm_update(LastFM
*l
)
277 last_fm_get_current_song(lfm
);
280 static void lfr_browser_song_info_query(GtkWidget
*button
, gpointer data
)
282 mpd_Song
*song
= mpd_playlist_get_current_song(connection
);
283 if(song
&& song
->file
)
285 const gchar
*stream_url
= last_fm_get_stream_url(lfm
);
286 if(stream_url
&& strcmp(stream_url
, song
->file
) == 0)
288 last_fm_get_current_song(lfm
);
289 if(lfm_update_timeout
== 0) {
290 if(cfg_get_single_value_as_int_with_default(config
, CONFIG_NAME
, "dirty-hack", FALSE
))
291 lfm_update_timeout
= g_timeout_add_seconds(15, G_CALLBACK(lfm_update
), lfm
);
297 lfr_browser_song_info(lfm
, NULL
, NULL
);
298 if(lfm_update_timeout
)
300 g_source_remove(lfm_update_timeout
);
301 lfm_update_timeout
= 0;
304 static void lfr_mpd_status_changed(MpdObj
*mi
, ChangedStatusType what
, void *data
)
306 if(what
&MPD_CST_SONGPOS
|| what
&MPD_CST_SONGPOS
)
309 lfr_browser_song_info_query(NULL
, NULL
);
312 static void lfr_button_clicked(GtkWidget
*button
, GtkWidget
*entry
)
314 const gchar
*combotext
= gtk_combo_box_get_active_text(GTK_COMBO_BOX(my_station_combo
));
315 const gchar
*text
= gtk_entry_get_text(GTK_ENTRY(entry
));
316 if(strlen(text
) > 0 && combotext
)
318 if(strcmp(combotext
, "Artist") == 0) {
319 last_fm_play_artist_radio(lfm
, text
);
320 } else if(strcmp(combotext
, "Similar Artist") == 0) {
321 last_fm_play_similar_artist_radio(lfm
, text
);
322 } else if(strcmp(combotext
, "Tag") == 0) {
323 last_fm_play_tag_radio(lfm
, text
);
324 } else if(strcmp(combotext
, "User") == 0) {
325 last_fm_play_user_radio(lfm
, text
);
326 } else if(strcmp(combotext
, "Group") == 0) {
327 last_fm_play_group_radio(lfm
, text
);
328 } else if(strcmp(combotext
, "Neighbourhood") == 0) {
329 last_fm_play_neighbours_radio(lfm
, text
);
334 static void lfr_button_play_recommendations(GtkWidget
*button
, gpointer data
) {
335 last_fm_play_recommendations(lfm
);
337 static void lfr_button_play_my_radio_station(GtkWidget
*button
, gpointer data
) {
338 last_fm_play_user_radio(lfm
,NULL
);
340 static void lfr_button_play_my_neighbourhood(GtkWidget
*button
, gpointer data
) {
341 last_fm_play_neighbours_radio(lfm
, NULL
);
343 static void lfr_button_play_my_loved(GtkWidget
*button
, gpointer data
) {
344 last_fm_play_loved_radio (lfm
);
347 void preferences_show_pref_window(int plugin_id
);
348 static void lfr_open_preferences(GtkWidget
*but
, gpointer data
)
350 preferences_show_pref_window(plugin
.id
);
355 static void lfr_background_style_changed(GtkWidget
*vbox
, GtkStyle
*style
, GtkWidget
*vp
)
357 gtk_widget_modify_bg(vp
,GTK_STATE_NORMAL
, &(GTK_WIDGET(vbox
)->style
->base
[GTK_STATE_NORMAL
]));
359 static gboolean
lfr_heading_expose_event(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
)
362 int width
= widget
->allocation
.width
;
363 int height
= widget
->allocation
.height
;
365 gtk_paint_flat_box(widget
->style
,
375 gtk_paint_focus(widget
->style
, widget
->window
,
385 static void lfr_browser_init()
388 GtkWidget
*temp
, *temp2
;
389 GtkWidget
*event
= NULL
;
390 /* If the widget allready exists, don't try to create it. */
391 if(lfr_vbox
!= NULL
) return;
395 * VBOX <holds everything>
399 * + Event box (for bg colour)
404 lfr_vbox
= gtk_vbox_new(FALSE
, 0);
406 event
= gtk_event_box_new();
407 gtk_widget_set_app_paintable(event
, TRUE
);
408 g_signal_connect(G_OBJECT(event
), "expose-event", G_CALLBACK(lfr_heading_expose_event
), NULL
);
410 hbox
= gtk_hbox_new(FALSE
, 6);
411 gtk_container_set_border_width(GTK_CONTAINER(hbox
), 6);
413 temp
= gtk_image_new_from_icon_name("lastfm", GTK_ICON_SIZE_DND
);
414 gtk_box_pack_start(GTK_BOX(hbox
), temp
, FALSE
, TRUE
, 0);
416 temp
= gtk_label_new("");
417 gtk_label_set_markup(GTK_LABEL(temp
), "<span size='xx-large' weight='bold'>Last.FM Radio</span>");
418 gtk_misc_set_alignment(GTK_MISC(temp
), 0.0, 0.5);
419 gtk_box_pack_start(GTK_BOX(hbox
), temp
, FALSE
, TRUE
, 0);
420 gtk_container_add(GTK_CONTAINER(event
), hbox
);
421 gtk_box_pack_start(GTK_BOX(lfr_vbox
), event
, FALSE
, TRUE
, 0);
422 gtk_widget_show_all(event
);
425 /* Event box for colouring back */
426 temp
= gtk_scrolled_window_new(NULL
, NULL
);
427 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(temp
), GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
428 event
= gtk_event_box_new();
429 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(temp
), GTK_SHADOW_IN
);
430 gtk_widget_modify_bg(event
,GTK_STATE_NORMAL
, &(GTK_WIDGET(lfr_vbox
)->style
->base
[GTK_STATE_NORMAL
]));
431 g_signal_connect(G_OBJECT(lfr_vbox
), "style-set", G_CALLBACK(lfr_background_style_changed
), event
);
434 rest_box
= gtk_vbox_new(FALSE
, 6);
435 gtk_container_set_border_width(GTK_CONTAINER(rest_box
), 8);
436 gtk_container_add(GTK_CONTAINER(event
), rest_box
);
437 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(temp
), event
);
438 gtk_box_pack_start(GTK_BOX(lfr_vbox
), temp
, TRUE
, TRUE
, 0);
440 gtk_widget_show(event
);
441 gtk_widget_show(temp
);
448 user_label
= gtk_label_new("");
449 gtk_misc_set_alignment(GTK_MISC(user_label
), 0.0,0.5);
450 gtk_box_pack_start(GTK_BOX(rest_box
), user_label
, FALSE
,TRUE
,12);
453 temp
= gtk_label_new("");
454 gtk_label_set_markup(GTK_LABEL(temp
),"<span size='x-large'>My Stations</span>");
455 gtk_misc_set_alignment(GTK_MISC(temp
), 0.0,0.5);
456 gtk_box_pack_start(GTK_BOX(rest_box
), temp
, FALSE
,TRUE
,0);
459 /* My recommendations */
460 hbox
= gtk_hbox_new(FALSE
, 0);
461 temp
= gtk_image_new_from_icon_name("recommended_radio", GTK_ICON_SIZE_MENU
);
462 gtk_box_pack_start(GTK_BOX(hbox
), temp
, FALSE
,TRUE
,0);
463 temp
= gtk_label_new("My Recommendations");
464 temp2
= gtk_button_new();
465 gtk_container_add(GTK_CONTAINER(temp2
), temp
);
466 gtk_button_set_relief(GTK_BUTTON(temp2
), GTK_RELIEF_NONE
);
467 gtk_box_pack_start(GTK_BOX(hbox
), temp2
, FALSE
,TRUE
,0);
468 gtk_box_pack_start(GTK_BOX(rest_box
), hbox
, FALSE
,TRUE
,0);
469 g_signal_connect(G_OBJECT(temp2
), "clicked", G_CALLBACK(lfr_button_play_recommendations
), NULL
);
471 /* My Radio Station*/
472 hbox
= gtk_hbox_new(FALSE
, 0);
473 temp
= gtk_image_new_from_icon_name("personal_radio", GTK_ICON_SIZE_MENU
);
474 gtk_box_pack_start(GTK_BOX(hbox
), temp
, FALSE
,TRUE
,0);
475 temp
= gtk_label_new("My Radio Station");
476 temp2
= gtk_button_new();
477 gtk_container_add(GTK_CONTAINER(temp2
), temp
);
478 gtk_button_set_relief(GTK_BUTTON(temp2
), GTK_RELIEF_NONE
);
479 gtk_box_pack_start(GTK_BOX(hbox
), temp2
, FALSE
,TRUE
,0);
480 gtk_box_pack_start(GTK_BOX(rest_box
), hbox
, FALSE
,TRUE
,0);
481 g_signal_connect(G_OBJECT(temp2
), "clicked", G_CALLBACK(lfr_button_play_my_radio_station
), NULL
);
484 /* My Radio Station*/
485 hbox
= gtk_hbox_new(FALSE
, 0);
486 temp
= gtk_image_new_from_icon_name("my_neighbours", GTK_ICON_SIZE_MENU
);
487 gtk_box_pack_start(GTK_BOX(hbox
), temp
, FALSE
,TRUE
,0);
488 temp
= gtk_label_new("My Neighbourhood");
489 temp2
= gtk_button_new();
490 gtk_container_add(GTK_CONTAINER(temp2
), temp
);
491 gtk_button_set_relief(GTK_BUTTON(temp2
), GTK_RELIEF_NONE
);
492 gtk_box_pack_start(GTK_BOX(hbox
), temp2
, FALSE
,TRUE
,0);
493 gtk_box_pack_start(GTK_BOX(rest_box
), hbox
, FALSE
,TRUE
,0);
494 g_signal_connect(G_OBJECT(temp2
), "clicked", G_CALLBACK(lfr_button_play_my_neighbourhood
), NULL
);
496 /* My Radio Station*/
497 hbox
= gtk_hbox_new(FALSE
, 0);
498 temp
= gtk_image_new_from_icon_name("loved_radio", GTK_ICON_SIZE_MENU
);
499 gtk_box_pack_start(GTK_BOX(hbox
), temp
, FALSE
,TRUE
,0);
500 temp
= gtk_label_new("My Loved Songs");
501 temp2
= gtk_button_new();
502 gtk_container_add(GTK_CONTAINER(temp2
), temp
);
503 gtk_button_set_relief(GTK_BUTTON(temp2
), GTK_RELIEF_NONE
);
504 gtk_box_pack_start(GTK_BOX(hbox
), temp2
, FALSE
,TRUE
,0);
505 gtk_box_pack_start(GTK_BOX(rest_box
), hbox
, FALSE
,TRUE
,0);
506 g_signal_connect(G_OBJECT(temp2
), "clicked", G_CALLBACK(lfr_button_play_my_loved
), NULL
);
510 temp
= gtk_label_new("");
511 gtk_label_set_markup(GTK_LABEL(temp
),"<span size='x-large'>Create Radio Station</span>");
512 gtk_misc_set_alignment(GTK_MISC(temp
), 0.0,0.5);
513 gtk_box_pack_start(GTK_BOX(rest_box
), temp
, FALSE
,TRUE
,0);
517 progressbar
= gtk_progress_bar_new();
518 gtk_box_pack_start(GTK_BOX(lfr_vbox
), progressbar
, FALSE
,TRUE
,0);
520 /* Quick and dirty box */
521 hbox
= gtk_hbox_new(FALSE
, 6);
523 my_station_combo
= temp
= gtk_combo_box_new_text();
524 gtk_combo_box_append_text(GTK_COMBO_BOX(temp
), "Artist");
525 gtk_combo_box_append_text(GTK_COMBO_BOX(temp
), "Similar Artist");
526 gtk_combo_box_append_text(GTK_COMBO_BOX(temp
), "Tag");
527 gtk_combo_box_append_text(GTK_COMBO_BOX(temp
), "User");
528 gtk_combo_box_append_text(GTK_COMBO_BOX(temp
), "Group");
529 gtk_combo_box_append_text(GTK_COMBO_BOX(temp
), "Neighbourhood");
530 gtk_combo_box_set_active(GTK_COMBO_BOX(temp
), 1);
531 gtk_box_pack_start(GTK_BOX(hbox
), temp
, FALSE
,TRUE
,0);
533 temp
= gtk_entry_new();
534 gtk_box_pack_start(GTK_BOX(hbox
), temp
, TRUE
,TRUE
,0);
535 g_signal_connect(G_OBJECT(temp
), "activate", G_CALLBACK(lfr_button_clicked
), temp
);
536 temp2
= gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY
);
537 gtk_box_pack_start(GTK_BOX(hbox
), temp2
, FALSE
,TRUE
,0);
538 g_signal_connect(G_OBJECT(temp2
), "clicked", G_CALLBACK(lfr_button_clicked
), temp
);
540 gtk_box_pack_start(GTK_BOX(rest_box
), hbox
, FALSE
,TRUE
,0);
543 song_info_box
= gtk_frame_new(NULL
);
544 gtk_box_pack_start(GTK_BOX(rest_box
), song_info_box
, FALSE
,TRUE
,0);
546 hbox
= gtk_hbox_new(FALSE
, 0);
547 temp
= gtk_image_new_from_icon_name(GTK_STOCK_REFRESH
, GTK_ICON_SIZE_MENU
);
548 gtk_box_pack_start(GTK_BOX(hbox
), temp
, FALSE
,TRUE
,0);
549 temp2
= gtk_button_new_with_label("Query current song info");
550 gtk_button_set_relief(GTK_BUTTON(temp2
), GTK_RELIEF_NONE
);
551 gtk_box_pack_start(GTK_BOX(hbox
), temp2
, FALSE
,TRUE
,0);
552 gtk_box_pack_start(GTK_BOX(rest_box
), hbox
, FALSE
,TRUE
,0);
553 g_signal_connect(temp2
, "clicked", G_CALLBACK(lfr_browser_song_info_query
), NULL
);
555 /** Show this box when we are not connected */
556 hbox
= gtk_hbox_new(FALSE
, 6);
557 connection_warning_box
= gtk_frame_new(NULL
);
558 gtk_container_add(GTK_CONTAINER(connection_warning_box
), hbox
);
559 gtk_container_set_border_width(GTK_CONTAINER(hbox
), 8);
561 gtk_box_pack_end(GTK_BOX(lfr_vbox
), connection_warning_box
, FALSE
, TRUE
, 0);
562 temp
= gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING
, GTK_ICON_SIZE_DIALOG
);
563 gtk_box_pack_start(GTK_BOX(hbox
), temp
, FALSE
, TRUE
, 0);
564 temp
= gtk_label_new("You must enter a valid last.FM username and pasword");
565 gtk_misc_set_alignment(GTK_MISC(temp
), 0.0,0.5);
566 gtk_box_pack_start(GTK_BOX(hbox
), temp
, TRUE
, TRUE
, 0);
567 temp
= gtk_button_new_with_label("Open preferences");
568 gtk_box_pack_start(GTK_BOX(hbox
), temp
, FALSE
, TRUE
, 0);
569 g_signal_connect(G_OBJECT(temp
), "clicked", G_CALLBACK(lfr_open_preferences
), NULL
);
571 if(last_fm_is_connected(lfm
)) {
572 gtk_widget_show_all(rest_box
);
574 gtk_widget_show_all(connection_warning_box
);
577 gtk_widget_show(lfr_vbox
);
578 /* Add extra references so the widget is not destroyed when removed*/
579 g_object_ref(lfr_vbox
);
582 g_signal_connect(G_OBJECT(lfm
), "connection_changed", G_CALLBACK(lfr_browser_conn_changed
), NULL
);
583 g_signal_connect(G_OBJECT(lfm
), "play_stream", G_CALLBACK(lfr_browser_play_stream
), NULL
);
584 g_signal_connect(G_OBJECT(lfm
), "processing", G_CALLBACK(lfr_browser_processing
), NULL
);
586 g_signal_connect(G_OBJECT(lfm
), "song_info_available", G_CALLBACK(lfr_browser_song_info
), NULL
);
587 g_signal_connect(G_OBJECT(lfm
), "error_callback", G_CALLBACK(lfr_browser_error_callback
), NULL
);
589 last_fm_connect(lfm
);
593 * Browser integration functions
595 /* When the player needs to be added to the right pane */
596 static void lfr_browser_selected(GtkWidget
*container
)
602 gtk_container_add(GTK_CONTAINER(container
), lfr_vbox
);
603 gtk_widget_show(lfr_vbox
);
605 /* When the player needs to be removed from the right pane */
606 static void lfr_browser_unselected(GtkWidget
*container
)
608 gtk_container_remove(GTK_CONTAINER(container
), gtk_bin_get_child(GTK_BIN(container
)));
610 /* Add the plugin to the left pane */
611 static void lfr_browser_add(GtkWidget
*cat_tree
)
613 GtkTreePath
*path
= NULL
;
615 GtkListStore
*pl3_tree
= (GtkListStore
*)gtk_tree_view_get_model(GTK_TREE_VIEW(cat_tree
));
616 gint pos
= cfg_get_single_value_as_int_with_default(config
, CONFIG_NAME
,"position",20);
618 if(!cfg_get_single_value_as_int_with_default(config
, CONFIG_NAME
, "enable", TRUE
)) return;
620 debug_printf(DEBUG_INFO
,"Adding at position: %i", pos
);
621 playlist3_insert_browser(&iter
, pos
);
622 gtk_list_store_set(GTK_LIST_STORE(pl3_tree
), &iter
,
623 PL3_CAT_TYPE
, plugin
.id
,
624 PL3_CAT_TITLE
, "Last.FM Radio",
626 PL3_CAT_ICON_ID
, "lastfm",
629 * Clean up old row reference if it exists
633 gtk_tree_row_reference_free(lfr_ref
);
637 * create row reference
639 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(playlist3_get_category_tree_store()), &iter
);
642 lfr_ref
= gtk_tree_row_reference_new(GTK_TREE_MODEL(playlist3_get_category_tree_store()), path
);
643 gtk_tree_path_free(path
);
649 static int lfr_get_enabled()
651 return cfg_get_single_value_as_int_with_default(config
, CONFIG_NAME
, "enable", TRUE
);
653 void pl3_update_go_menu(void);
654 static void lfr_set_enabled(int enabled
)
656 cfg_set_single_value_as_int(config
, CONFIG_NAME
, "enable", enabled
);
659 /* Add the browser to the left pane, if there is none to begin with */
662 lfr_browser_add(GTK_WIDGET(playlist3_get_category_tree_view()));
667 /* Remove it from the left pane */
668 GtkTreePath
*path
= gtk_tree_row_reference_get_path(lfr_ref
);
671 /* for a save of myself */
673 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(playlist3_get_category_tree_store()), &iter
, path
)){
674 gtk_list_store_remove(playlist3_get_category_tree_store(), &iter
);
676 gtk_tree_path_free(path
);
677 gtk_tree_row_reference_free(lfr_ref
);
681 /* Make sure the go menu is in sync */
682 pl3_update_go_menu();
688 GtkWidget
*username_entry
;
689 GtkWidget
*password_entry
;
690 static void lfr_pref_set_info(GtkWidget
*button
, gpointer data
)
692 const gchar
*username
= gtk_entry_get_text(GTK_ENTRY(username_entry
));
693 const gchar
*password
= gtk_entry_get_text(GTK_ENTRY(password_entry
));
694 if(strlen(username
) > 0 && strlen(password
) > 0)
696 last_fm_set_login(lfm
, username
, password
);
697 last_fm_connect(lfm
);
700 static void lfr_pref_conn_changed(LastFM
*l
, gboolean connected
, GtkWidget
*label
)
702 gtk_label_set_text(GTK_LABEL(label
),connected
?"connected":"disconnected");
704 static void lfr_pref_construct(GtkWidget
*container
)
706 GtkWidget
*table
= gtk_table_new(3,2,FALSE
);
709 gtk_table_set_row_spacings(GTK_TABLE(table
),6);
710 gtk_table_set_col_spacings(GTK_TABLE(table
),6);
712 label
= gtk_label_new("Username");
713 gtk_misc_set_alignment(GTK_MISC(label
), 1.0,0.5);
714 gtk_table_attach(GTK_TABLE(table
), label
, 0,1,0,1,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
715 username_entry
= gtk_entry_new();
716 if(last_fm_get_username(lfm
) != NULL
) gtk_entry_set_text(GTK_ENTRY(username_entry
),last_fm_get_username(lfm
));
717 gtk_table_attach(GTK_TABLE(table
), username_entry
, 1,2,0,1,GTK_FILL
|GTK_EXPAND
, GTK_FILL
|GTK_SHRINK
, 0,0);
720 label
= gtk_label_new("Password");
721 gtk_misc_set_alignment(GTK_MISC(label
), 1.0,0.5);
722 gtk_table_attach(GTK_TABLE(table
), label
, 0,1,1,2,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
723 password_entry
= gtk_entry_new();
724 gtk_entry_set_visibility(GTK_ENTRY(password_entry
), FALSE
);
725 gtk_table_attach(GTK_TABLE(table
), password_entry
, 1,2,1,2,GTK_FILL
|GTK_EXPAND
, GTK_FILL
|GTK_SHRINK
, 0,0);
728 label
= gtk_button_new_with_label("Set information");
729 gtk_table_attach(GTK_TABLE(table
), label
, 1,2,2,3,GTK_FILL
|GTK_EXPAND
, GTK_FILL
|GTK_SHRINK
, 0,0);
730 g_signal_connect(G_OBJECT(label
), "clicked", G_CALLBACK(lfr_pref_set_info
), NULL
);
732 label
= gtk_label_new(last_fm_is_connected(lfm
)?"connected":"disconnected");
733 gtk_table_attach(GTK_TABLE(table
), label
, 0,1,2,3,GTK_FILL
, GTK_FILL
|GTK_SHRINK
, 0,0);
735 gtk_container_add(GTK_CONTAINER(container
), GTK_WIDGET(GTK_TABLE(table
)));
736 gtk_widget_show_all(table
);
738 id
= g_signal_connect(lfm
, "connection_changed",G_CALLBACK(lfr_pref_conn_changed
), label
);
740 static void lfr_pref_destroy(GtkWidget
*container
)
742 g_signal_handler_disconnect(lfm
, id
);
744 gtk_container_remove(GTK_CONTAINER(container
), gtk_bin_get_child(GTK_BIN(container
)));
747 gmpcPrefPlugin lfr_pref
= {
748 .construct
= lfr_pref_construct
,
749 .destroy
= lfr_pref_destroy
752 * Structure used by gmpc for integrating the browser
754 gmpcPlBrowserPlugin lfr_gbp
= {
755 .add
= lfr_browser_add
,
756 .selected
= lfr_browser_selected
,
757 .unselected
= lfr_browser_unselected
,
761 * This allows gmpc to check the api this plugin is compiled against
763 int plugin_api_version
= PLUGIN_API_VERSION
;
765 * The plugin structure
767 gmpcPlugin plugin
= {
768 .name
= "Last.FM Radio",
769 .version
= {PLUGIN_MAJOR_VERSION
,PLUGIN_MINOR_VERSION
,PLUGIN_MICRO_VERSION
},
770 .plugin_type
= GMPC_PLUGIN_PL_BROWSER
,
771 /* Creation and destruction */
773 .destroy
= lfr_destroy
,
774 .save_yourself
= lfr_save_myself
,
775 .mpd_status_changed
= lfr_mpd_status_changed
,
776 /* Browser extention */
778 /* Preferences pane */
781 /* Get/set enabled */
782 .get_enabled
= lfr_get_enabled
,
783 .set_enabled
= lfr_set_enabled