1 /* Gnome Music Player Client
2 * Copyright (C) 2011-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
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.
24 private const bool use_transition_mb2
= Gmpc
.use_transition
;
25 private const string some_unique_name_mb2
= Config
.VERSION
;
26 private const string np2_LOG_DOMAIN
= "NowPlaying";
29 * This plugin implements an 'improved' now playing interface, modeled after the mockup found here
30 * http://gmpclient.org/wiki/GMPC_Mocup
33 /* create teh plugin of type Gmpc.Plugin.Base that implements the Browser interface */
39 public class Nowplaying
: Gmpc
.Plugin
.Base
, Gmpc
.Plugin
.BrowserIface
41 private bool theme_colors
= (bool) config
.get_int_with_default("Now Playing", "use-theme-color",1);
42 private string title_color
= config
.get_string_with_default("Now Playing", "title-color", "#4d90dd");
43 private string item_color
= config
.get_string_with_default("Now Playing", "item-color", "#304ab8");
44 private Gdk
.Color background
;
45 private Gdk
.Color foreground
;
47 private Gtk
.Label bitrate_label
= null;
48 private Gtk
.TreeRowReference np_ref
= null;
50 private bool use_backdrop
= (bool) config
.get_int_with_default("Now Playing", "use-backdrop",0);
55 /* Set the plugin as Browser type*/
56 this
.plugin_type
= 2|8;
57 /* Track changed status */
58 gmpcconn
.status_changed
.connect(status_changed
);
59 /* Track connect/disconnect */
60 gmpcconn
.connection_changed
.connect((source
, connect
) => {
61 /* If disconnect update the page */
62 if(connect
== 0 && this
.paned
!= null)
63 this
.update_not_playing();
66 var background
= config
.get_string_with_default("Now Playing",
67 "background-color", "#000");
68 var foreground
= config
.get_string_with_default("Now Playing",
69 "foreground-color", "#FFF");
70 Gdk
.Color
.parse(background
,out this
.background
);
71 Gdk
.Color
.parse(foreground
,out this
.foreground
);
73 /* Register easycommand to switch to this browser */
74 easy_command
.add_entry(
75 _("switch now playing"),
77 _("Switch to Now Playing"),
78 (Gmpc
.Easy
.Command
.Callback
*)select_now_playing_browser
,
81 /* Version of the plugin*/
82 private const int[] version
= {0,0,0};
83 public override unowned
int[] get_version()
88 public override unowned
string get_name()
90 return N_("Now Playing");
93 public override void set_enabled(bool state
)
99 browser_add( Gmpc
.Playlist3
.get_category_tree_view());
105 if(this
.np_ref
!= null)
107 var path
= np_ref
.get_path();
110 unowned
int[] indices
= path
.get_indices();
111 config
.set_int(this
.get_name(), "position", indices
[0]);
112 Gtk
.ListStore model
= (Gtk
.ListStore
) np_ref
.get_model();
114 if(model
.get_iter(out iter
, path
))
120 if(this
.paned
!= null)
122 this
.paned
.destroy();
124 this
.song_checksum
= null;
128 if(this
.get_name() != null)
129 Gmpc
.config
.set_int(this
.get_name(), "enabled", (int)state
);
131 /* Save our position in the side-bar */
132 public override void save_yourself()
134 if(this
.np_ref
!= null)
136 var path
= np_ref
.get_path();
139 unowned
int[] indices
= path
.get_indices();
140 config
.set_int(this
.get_name(), "position", indices
[0]);
145 /* React MPD's status changed */
148 status_changed(Gmpc
.Connection conn
, MPD
.Server server
, MPD
.Status
.Changed what
)
150 if(!this
.get_enabled())return;
151 if(!this
.selected
) return;
152 /* If the state changes, update. */
153 if((what
&MPD
.Status
.Changed
.STATE
) == MPD
.Status
.Changed
.STATE
)
157 /* If the playlist changed, this might mean that the metadata of the currently playing song changed, update. */
158 else if ((what
&(MPD
.Status
.Changed
.SONGID
|MPD
.Status
.Changed
.PLAYLIST
)) > 0)
162 /* If the bitrate changed, update the bitrate label. */
163 if((what
&(MPD
.Status
.Changed
.BITRATE
|MPD
.Status
.Changed
.AUDIOFORMAT
)) > 0)
165 if(bitrate_label
!= null)
167 var channels
= MPD
.Status
.get_channels(Gmpc
.server
);
168 debug("bitrate changed");
169 var bitrate
= MPD
.Status
.get_bitrate(Gmpc
.server
);
170 bitrate_label
.set_markup(GLib
.Markup
.printf_escaped(
171 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
172 this
.item_color
, _("Format"),
173 channels
, GLib
.ngettext(N_("Channel"),N_("Channels"), channels
),
174 MPD
.Status
.get_samplerate(Gmpc
.server
)/1000.0, "kHz",
183 private Gtk
.ScrolledWindow paned
= null;
184 private Gtk
.EventBox container
= null;
185 private bool selected
= false;
187 * Browser Interface bindings
189 public void browser_add (Gtk
.Widget category_tree
)
191 Gtk
.TreeView tree
= (Gtk
.TreeView
)category_tree
;
192 Gtk
.ListStore store
= (Gtk
.ListStore
)tree
.get_model();
193 Gtk
.TreeModel model
= tree
.get_model();
195 Gmpc
.Browser
.insert(out iter
, Gmpc
.Playlist
.BrowserType
.TOP
);
196 store
.set(iter
, 0, this
.id
, 1, this
.get_name(), 3, "media-audiofile");
197 /* Create a row reference */
198 this
.np_ref
= new Gtk
.TreeRowReference(model
, model
.get_path(iter
));
200 /* Called by gmpc, telling the plugin to embed itself in container */
201 public void browser_selected (Gtk
.Container container
)
206 this
.selected
= true;
208 container
.add(this
.paned
);
210 container
.show_all();
211 container
.ensure_style();
212 if(this
.theme_colors
)
214 this
.title_color
= this
.paned
.style
.text
[Gtk
.StateType
.PRELIGHT
].to_string();
215 this
.item_color
= this
.paned
.style
.text
[Gtk
.StateType
.PRELIGHT
].to_string();
219 this
.title_color
= "#fff";
220 this
.item_color
= "#fff";
221 this
.theme_colors
= false;
226 /* Called by gmpc, telling the plugin to remove itself from the container */
227 public void browser_unselected(Gtk
.Container container
)
229 this
.selected
= false;
230 container
.remove(this
.paned
);
234 * If the style changed because f.e. the user switched theme, make sure the correct colouring is kept preserved.
237 private void browser_bg_style_changed(Gtk
.Widget bg
,Gtk
.Style? style
)
239 debug("Change style signal");
240 if(this
.theme_colors
)
242 this
.title_color
= this
.paned
.style
.text
[Gtk
.StateType
.PRELIGHT
].to_string();
243 this
.item_color
= this
.paned
.style
.text
[Gtk
.StateType
.PRELIGHT
].to_string();
245 this
.change_color_style(this
.container
);
248 * Recursively force a style on widget bg and children.
250 private void change_color_style(Gtk
.Widget bg
)
252 debug("change style");
253 if(bg is Gtk
.Separator
|| bg is Gtk
.Notebook
|| bg is Gtk
.CheckButton
)
261 bg
.modify_bg(Gtk
.StateType
.NORMAL
,this
.paned
.style
.base[Gtk
.StateType
.NORMAL
]);
262 /*bg.modify_base(Gtk.StateType.NORMAL,this.paned.style.mid[Gtk.StateType.NORMAL]);/*
263 // bg.modify_text(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
264 bg.modify_fg(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
265 bg.modify_text(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);
266 bg.modify_fg(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);*/
270 bg
.modify_bg(Gtk
.StateType
.NORMAL
,this
.background
);
271 bg
.modify_base(Gtk
.StateType
.NORMAL
,this
.background
);
272 bg
.modify_text(Gtk
.StateType
.NORMAL
,this
.foreground
);
273 bg
.modify_fg(Gtk
.StateType
.NORMAL
,this
.foreground
);
274 bg
.modify_text(Gtk
.StateType
.ACTIVE
,this
.foreground
);
275 bg
.modify_fg(Gtk
.StateType
.ACTIVE
,this
.foreground
);
278 /* Recurse into children, if the widget can hold children (so is a container */
279 if(bg is Gtk
.Container
)
281 foreach(Gtk
.Widget child
in ((Gtk
.Container
)bg
).get_children())
283 change_color_style(child
);
287 /* Create the basic gui. on initializing */
288 private void browser_init()
290 if(this
.paned
== null)
293 this
.paned
= new Gtk
.ScrolledWindow(null,null);
294 this
.paned
.set_policy(Gtk
.PolicyType
.AUTOMATIC
, Gtk
.PolicyType
.AUTOMATIC
);
295 this
.paned
.set_shadow_type(Gtk
.ShadowType
.ETCHED_IN
);
298 this
.container
= new Gmpc
.MetaData
.Widgets
.Backdrop(Gmpc
.MetaData
.Type
.BACKDROP_ART
);
302 this
.container
= new Gtk
.EventBox();
305 this.container.set_focus_hadjustment(this.paned.get_hadjustment());
306 this.container.set_focus_vadjustment(this.paned.get_vadjustment());
308 this
.paned
.style_set
.connect(browser_bg_style_changed
);
309 this
.paned
.add_with_viewport(this
.container
);
310 this
.paned
.get_vadjustment().set("step-increment", 20.0);
311 this
.paned
.show_all();
316 /* Clear the view inside the scrolled window*/
320 var list
= this
.container
.get_children();
321 foreach(Gtk
.Widget child
in list
)
325 bitrate_label
= null;
329 private string get_extension(string path
)
331 long length
= path
.length
;
334 for(; i
>0 && (length
-i
) <8; i
--)
338 retv
= path
.substring(i
+1);
345 * Show the page when playing
347 private string song_checksum
= null;
348 private void update_playing()
350 unowned MPD
.Song? song
= server
.playlist_get_current_song();
353 debug("GMPC Is playing, cannot get this");
355 (this
.container as Gmpc
.MetaData
.Widgets
.Backdrop
).set_song(null);
356 update_not_playing();
359 /* Force it so we won't update when not needed */
360 var checksum
= Gmpc
.Misc
.song_checksum(song
);
361 if(checksum
== this
.song_checksum
)
363 /* No need to update. */
366 GLib
.Timer t
= new GLib
.Timer();
369 (this
.container as Gmpc
.MetaData
.Widgets
.Backdrop
).set_song(song
);
370 this
.song_checksum
= checksum
;
372 var vbox
= new Gtk
.VBox (false,6);
373 vbox
.border_width
= 8;
374 /* Start building the gui */
376 var hbox
= new Gtk
.HBox(false, 6);
377 Gtk
.Alignment ali
= null;
379 int meta_size
= (int)(this
.container
.get_allocated_width()*0.20);
380 /* get size based on alloc */
381 meta_size
= int.min(int.max(100, meta_size
), 250);
382 if(config
.get_int_with_default("Interface", "hide-album-art", 0) == 0)
385 ali
= new Gtk
.Alignment(0f
,0f
,0f
,0f
);
386 //ali.set_size_request(meta_size,meta_size);
387 var album_image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ALBUM_ART
, meta_size
);
388 album_image
.set_scale_up(true);
389 album_image
.set_squared(false);
390 ali
.add(album_image
);
391 album_image
.update_from_song(song
);
392 hbox
.pack_start(ali
, false, false, 0);
396 if(config
.get_int_with_default("Interface", "hide-album-art", 0) == 0 && !use_backdrop
)
398 ali
= new Gtk
.Alignment(1f
,0f
,0f
,0f
);
399 var artist_image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ARTIST_ART
, meta_size
);
400 artist_image
.set_scale_up(true);
401 artist_image
.set_squared(false);
402 artist_image
.update_from_song(song
);
403 ali
.add(artist_image
);
404 hbox
.pack_end(ali
, false, false, 0);
407 /* Information box */
408 var info_vbox
= new Gtk
.VBox(false, 6);
410 if(song
.title
!= null)
412 var box
= new Gtk
.HBox(false, 6);
415 if(config
.get_int_with_default("Interface", "hide-favorites-icon",0) == 0)
417 var fav_button
= new Gmpc
.Favorites
.Button();
418 fav_button
.set_song(song
);
419 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,0f
,0f
);
421 box
.pack_start(ali
, false, false, 0);
423 var label
= new Gtk
.Label(song
.title
);
424 label
.selectable
= true;
425 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",
426 this
.title_color
,Pango
.SCALE
*20 ,song
.title
));
427 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
428 label
.set_alignment(0.0f
, 0.5f
);
429 box
.pack_start(label
, true, true, 0);
430 info_vbox
.pack_start(box
, false, false, 0);
433 else if (song
.name
!= null)
435 var label
= new Gtk
.Label(song
.name
);
436 label
.selectable
= true;
437 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this
.
438 title_color
, Pango
.SCALE
*20, song
.name
));
439 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
440 label
.set_alignment(0.0f
, 0.5f
);
441 info_vbox
.pack_start(label
, false, false, 0);
443 else if (song
.file
!= null)
445 var filename
= GLib
.Path
.get_basename(song
.file
);
446 var label
= new Gtk
.Label(song
.name
);
447 label
.selectable
= true;
450 var regex_a
= new GLib
.Regex ("\\.[0-9a-zA-Z]*$");
451 filename
= regex_a
.replace_literal (filename
, -1, 0, "");
453 catch (GLib
.RegexError e
)
455 GLib
.error("%s", e
.message
);
459 var regex_b
= new GLib
.Regex ("_");
460 filename
= regex_b
.replace_literal (filename
, -1, 0, " ");
462 catch (GLib
.RegexError e
)
464 GLib
.error("%s", e
.message
);
466 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this
.
467 title_color
, Pango
.SCALE
*20, filename
));
468 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
469 label
.set_alignment(0.0f
, 0.5f
);
470 info_vbox
.pack_start(label
, false, false, 0);
474 if(song
.artist
!= null)
476 var event
= new Gtk
.EventBox();
477 var box
= new Gtk
.HBox(false, 6);
478 var label
= new Gtk
.Label(song
.artist
);
479 event
.set_visible_window(false);
480 label
.selectable
= true;
481 var image
= new Gtk
.Image
.from_icon_name("media-artist", Gtk
.IconSize
.MENU
);
483 box
.pack_start(event
, false, false, 0);
484 label
.set_markup(GLib
.Markup
.printf_escaped("<span size='xx-large' weight='bold'>%s</span>", song
.artist
));
485 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
486 label
.set_alignment(0.0f
, 0.5f
);
487 box
.pack_start(label
, true, true, 0);
488 info_vbox
.pack_start(box
, false, false, 0);
490 event
.set_data("artist",song
.artist
);
491 event
.button_press_event
.connect((widget
, event
) =>
493 string artist
= (string)widget
.get_data
<string>("artist");
494 Gmpc
.Browser
.Metadata
.show_artist(artist
);
499 if(song
.album
!= null)
501 var event
= new Gtk
.EventBox();
502 var box
= new Gtk
.HBox(false, 6);
503 var label
= new Gtk
.Label(song
.album
);
504 event
.set_visible_window(false);
505 label
.selectable
= true;
506 var image
= new Gtk
.Image
.from_icon_name("media-album", Gtk
.IconSize
.MENU
);
508 box
.pack_start(event
, false, false, 0);
509 label
.set_markup(GLib
.Markup
.printf_escaped("<span size='x-large' weight='bold'>%s %s</span>", song
.album
,
510 (song
.date
!= null)?
"(%s)".printf(song
.date
):""));
511 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
512 label
.set_alignment(0.0f
, 0.5f
);
513 box
.pack_start(label
, true, true, 0);
514 info_vbox
.pack_start(box
, false, false, 0);
518 event
.set_data("artist",song
.artist
);
519 event
.set_data("album",song
.album
);
520 event
.button_press_event
.connect((widget
, event
) =>
522 string artist
= (string)widget
.get_data
<string>("artist");
523 string album
= (string)widget
.get_data
<string>("album");
524 if(artist
!= null && album
!= null)
526 Gmpc
.Browser
.Metadata
.show_album(artist
,album
);
533 if(song
.genre
!= null)
535 var box
= new Gtk
.HBox(false, 6);
536 var label
= new Gtk
.Label(song
.title
);
537 label
.selectable
= true;
538 var image
= new Gtk
.Image
.from_icon_name("media-genre", Gtk
.IconSize
.MENU
);
539 box
.pack_start(image
, false, false, 0);
540 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
541 this
.item_color
,_("Genre"), song
.genre
));
542 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
543 label
.set_alignment(0.0f
, 0.5f
);
544 box
.pack_start(label
, true, true, 0);
545 info_vbox
.pack_start(box
, false, false, 0);
550 var box
= new Gtk
.HBox(false, 6);
551 var image
= new Gtk
.Image
.from_icon_name("media-format", Gtk
.IconSize
.MENU
);
552 box
.pack_start(image
, false, false, 0);
554 bitrate_label
= new Gtk
.Label(song
.title
);
555 bitrate_label
.selectable
= true;
556 bitrate_label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
557 bitrate_label
.set_alignment(0.0f
, 0.5f
);
559 box
.pack_start(bitrate_label
, true, true, 0);
561 var bitrate
= MPD
.Status
.get_bitrate(Gmpc
.server
);
562 var channels
= MPD
.Status
.get_channels(Gmpc
.server
);
563 bitrate_label
.set_markup(GLib
.Markup
.printf_escaped(
564 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
565 this
.item_color
, _("Format"),
566 channels
, GLib
.ngettext(N_("Channel"),N_("Channels"), channels
),
567 MPD
.Status
.get_samplerate(Gmpc
.server
)/1000.0, "kHz",
571 info_vbox
.pack_start(box
, false, false, 0);
573 if(song
.file
!= null)
576 string extension
= null;
577 extension
= get_extension(song
.file
);
578 if(extension
!= null)
580 var box
= new Gtk
.HBox(false, 6);
581 var image
= new Gtk
.Image
.from_icon_name("media-codec", Gtk
.IconSize
.MENU
);
582 box
.pack_start(image
, false, false, 0);
584 var label
= new Gtk
.Label(song
.title
);
585 label
.selectable
= true;
586 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
587 label
.set_alignment(0.0f
, 0.5f
);
588 box
.pack_start(label
, true, true, 0);
589 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
590 this
.item_color
, _("Codec"),
592 info_vbox
.pack_start(box
, false, false, 0);
598 var box
= new Gtk
.HBox(false, 6);
599 var image
= new Gtk
.Image
.from_icon_name("media-track-length", Gtk
.IconSize
.MENU
);
600 box
.pack_start(image
, false, false, 0);
601 var label
= new Gtk
.Label("");
602 label
.selectable
= true;
603 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
604 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
605 this
.item_color
,_("Length"),
606 Gmpc
.Misc
.format_time((ulong) song
.time
, "")));
607 label
.set_alignment(0.0f
, 0.5f
);
608 box
.pack_start(label
, true, true, 0);
609 info_vbox
.pack_start(box
, false, false, 0);
612 if(song
.track
!= null)
614 var box
= new Gtk
.HBox(false, 6);
615 var image
= new Gtk
.Image
.from_icon_name("media-num-tracks", Gtk
.IconSize
.MENU
);
616 box
.pack_start(image
, false, false, 0);
617 var label
= new Gtk
.Label("");
618 label
.selectable
= true;
619 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
620 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s %s",
621 this
.item_color
, _("Track number"),
623 (song
.disc
!= null)?
"[%s]".printf(song
.disc
):""
625 label
.set_alignment(0.0f
, 0.5f
);
626 box
.pack_start(label
, true, true, 0);
627 info_vbox
.pack_start(box
, false, false, 0);
631 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "heading took: %.6f seconds.", t
.elapsed());
632 hbox
.pack_start(info_vbox
, true, true, 0);
633 vbox
.pack_start(hbox
, false, false, 0);
636 var sep
= new Gtk
.HSeparator();
637 sep
.set_size_request(-1, 4);
638 vbox
.pack_start(sep
, false, false, 0);
640 var hboxje
= new Gtk
.HBox(false, 6);
642 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
643 var notebook
= new Gtk
.Notebook();
644 notebook
.set_show_border(false);
645 notebook
.set_show_tabs(false);
649 unowned SList
<unowned Gtk
.RadioButton
> group
= null;
650 if(config
.get_int_with_default("MetaData", "show-lyrics",1) == 1)
652 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
653 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
, Gmpc
.MetaData
.Type
.SONG_TXT
);
655 notebook
.append_page(alib
, new Gtk
.Label("Lyrics"));
656 var button
= new Gtk
.RadioButton(group
);//.with_label(group,("Lyrics"));
657 var label
= new Gtk
.Label(_("Lyrics"));
658 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
659 label
.set_alignment(0.0f
, 0.5f
);
660 // button.add(label);
663 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
664 group
= button
.get_group();
665 hboxje
.pack_start(button
, false, false, 0);
666 hboxje
.pack_start(label
, true, true, 0);
668 button
.clicked
.connect((source
) =>
670 if((source as Gtk
.CheckButton
).get_active())
672 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "lyrics notebook page %i clicked", j
);
673 notebook
.set_current_page(j
);
680 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "lyrics took: %.6f seconds.", t
.elapsed());
682 /* Album information */
683 if(config
.get_int_with_default("MetaData", "show-album-information",1) == 1)
685 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
686 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
, Gmpc
.MetaData
.Type
.ALBUM_TXT
);
688 notebook
.append_page(alib
, new Gtk
.Label("Album information"));
689 var button
= new Gtk
.RadioButton(group
);
690 var label
= new Gtk
.Label(_("Album information"));
691 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
692 label
.set_alignment(0.0f
, 0.5f
);
695 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
696 group
= button
.get_group();
697 hboxje
.pack_start(button
, false, false, 0);
698 hboxje
.pack_start(label
, true, true, 0);
700 button
.clicked
.connect((source
) =>
702 if((source as Gtk
.CheckButton
).get_active())
704 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "lyrics notebook page %i clicked", j
);
705 notebook
.set_current_page(j
);
714 if(config
.get_int_with_default("MetaData", "show-guitar-tabs",1) == 1)
716 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
717 var text_view_queried
= false;
718 notebook
.append_page(alib
, new Gtk
.Label(_("Guitar Tabs")));
719 var button
= new Gtk
.RadioButton(group
);//.with_label(group,_("Guitar Tabs"));
720 var label
= new Gtk
.Label(_("Guitar Tabs"));
721 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
722 label
.set_alignment(0.0f
, 0.5f
);
725 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
726 group
= button
.get_group();
727 hboxje
.pack_start(button
, false, false, 0);
728 hboxje
.pack_start(label
, true, true, 0);
730 /* Only query the guitar-tab when opened or first notebook page*/
731 button
.clicked
.connect((source
) =>
733 if((source as Gtk
.CheckButton
).get_active())
735 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "guitar tab notebook page %i clicked", j
);
736 notebook
.set_current_page(j
);
737 if(!text_view_queried
)
739 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
, Gmpc
.MetaData
.Type
.SONG_GUITAR_TAB
);
741 text_view_queried
= true;
742 this
.change_color_style(text_view
);
749 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
, Gmpc
.MetaData
.Type
.SONG_GUITAR_TAB
);
751 text_view_queried
= true;
756 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "guitar tabs took: %.6f seconds.", t
.elapsed());
760 if(config
.get_int_with_default("MetaData", "show-similar-songs",1) == 1)
762 var similar_songs_queried
= false;
763 var similar_songs_box
= new Gtk
.Alignment(0f
,0f
,0f
,0f
);
765 notebook
.append_page(similar_songs_box
, new Gtk
.Label(_("Similar Songs")));
767 var button
= new Gtk
.RadioButton(group
);//.with_label(group,_("Similar Songs"));
768 var label
= new Gtk
.Label(_("Similar Songs"));
769 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
770 label
.set_alignment(0.0f
, 0.5f
);
773 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
774 group
= button
.get_group();
775 hboxje
.pack_start(button
, false, false, 0);
776 hboxje
.pack_start(label
, true, true, 0);
779 /* Only query when opened or first notebook page*/
780 button
.clicked
.connect((source
) =>
782 if((source as Gtk
.CheckButton
).get_active())
784 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "similar song notebook page %i clicked", j
);
785 notebook
.set_current_page(j
);
786 if(!similar_songs_queried
)
788 var similar_songs
= new Gmpc
.MetaData
.Widgets
.SimilarSongs(song
);
789 similar_songs
.update();
790 similar_songs_queried
= true;
791 similar_songs_box
.add(similar_songs
);
792 this
.change_color_style(similar_songs_box
);
793 similar_songs_box
.show_all();
799 var similar_songs
= new Gmpc
.MetaData
.Widgets
.SimilarSongs(song
);
800 similar_songs
.update();
801 similar_songs_queried
= true;
802 similar_songs_box
.add(similar_songs
);
803 similar_songs_box
.show_all();
805 similar_songs_box
.show();
809 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "similar songs took: %.6f seconds.", t
.elapsed());
810 if(config
.get_int_with_default("MetaData", "show-similar-artist",1) == 1 && song
.artist
!= null)
812 var similar_artist
= new Gmpc
.MetaData
.Widgets
.SimilarArtists(Gmpc
.server
,song
);
814 notebook
.append_page(similar_artist
, new Gtk
.Label(_("Similar Artist")));
816 var button
= new Gtk
.RadioButton(group
);//.with_label(group,_("Similar Artist"));
817 var label
= new Gtk
.Label(_("Similar Artist"));
818 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
819 label
.set_alignment(0.0f
, 0.5f
);
822 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
823 group
= button
.get_group();
824 hboxje
.pack_start(button
, false, false, 0);
825 hboxje
.pack_start(label
, true, true, 0);
828 button
.clicked
.connect((source
) =>
830 if((source as Gtk
.CheckButton
).get_active())
832 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "similar artist notebook page %i clicked", j
);
833 similar_artist
.first_show();
834 notebook
.set_current_page(j
);
837 similar_artist
.show();
840 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "similar Artist took: %.6f seconds.", t
.elapsed());
841 if(config
.get_int_with_default("MetaData", "show-artist-information",1) == 1)
843 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
844 var text_view_queried
= false;
846 notebook
.append_page(alib
, new Gtk
.Label(_("Artist information")));
847 var button
= new Gtk
.RadioButton(group
);//.with_label(group,_("Artist information"));
848 var label
= new Gtk
.Label(_("Artist information"));
849 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
850 label
.set_alignment(0.0f
, 0.5f
);
853 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
854 group
= button
.get_group();
855 hboxje
.pack_start(button
, false, false, 0);
856 hboxje
.pack_start(label
, true, true, 0);
858 /* Only query the guitar-tab when opened or first notebook page*/
859 button
.clicked
.connect((source
) =>
861 if((source as Gtk
.CheckButton
).get_active())
863 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "artist info notebook page %i clicked", j
);
864 notebook
.set_current_page(j
);
865 if(!text_view_queried
)
867 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
,Gmpc
.MetaData
.Type
.ARTIST_TXT
);
869 text_view_queried
= true;
871 this
.change_color_style(text_view
);
877 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
,Gmpc
.MetaData
.Type
.ARTIST_TXT
);
879 text_view_queried
= true;
885 if(config
.get_int_with_default("MetaData", "show-songs-from-album",1) == 1)
887 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
888 var text_view_queried
= false;
890 notebook
.append_page(alib
, new Gtk
.Label(_("Songs from album")));
891 var button
= new Gtk
.RadioButton(group
);//.with_label(group,_("Songs from album"));
892 var label
= new Gtk
.Label(_("Songs from album"));
893 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
894 label
.set_alignment(0.0f
, 0.5f
);
897 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
898 group
= button
.get_group();
899 hboxje
.pack_start(button
, false, false, 0);
900 hboxje
.pack_start(label
, true, true, 0);
902 var sl
= new Gmpc
.Widgets
.Songlist();
904 sl
.song_clicked
.connect((source
, song
) =>
906 if(song
.file
!= null)
908 Gmpc
.MpdInteraction
.play_path(song
.file
);
911 sl
.play_song_clicked
.connect((source
, song
) =>
913 if(song
.file
!= null)
915 Gmpc
.MpdInteraction
.play_path(song
.file
);
919 button
.clicked
.connect((source
) =>
921 if((source as Gtk
.CheckButton
).get_active())
923 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "artist info notebook page %i clicked", j
);
924 notebook
.set_current_page(j
);
925 if(!text_view_queried
)
927 if(song
.artist
!= null && song
.album
!= null)
929 MPD
.Database
.search_start(server
,true);
930 if(song
.albumartist
!= null)
932 MPD
.Database
.search_add_constraint(server
,
933 MPD
.Tag
.Type
.ALBUM_ARTIST
, song
.albumartist
);
937 MPD
.Database
.search_add_constraint(server
,
938 MPD
.Tag
.Type
.ARTIST
, song
.artist
);
940 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, song
.album
);
941 var data
= MPD
.Database
.search_commit(server
);
942 data
.sort_album_disc_track();
943 sl
.set_from_data((owned
)data
, true);
944 this
.change_color_style(sl
);
949 alib
.add(new Gtk
.Label(_("Not available")));
951 text_view_queried
= true;
957 if(song
.artist
!= null && song
.album
!= null)
959 MPD
.Database
.search_start(server
,true);
960 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, song
.artist
);
961 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, song
.album
);
962 var data
= MPD
.Database
.search_commit(server
);
963 data
.sort_album_disc_track();
964 sl
.set_from_data((owned
)data
, true);
969 alib
.add(new Gtk
.Label(_("Not available")));
971 text_view_queried
= true;
977 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "Artist info took: %.6f seconds.", t
.elapsed());
978 /* Track changed pages */
979 notebook
.notify
["page"].connect((source
,spec
) =>
981 var page
= notebook
.get_current_page();
982 config
.set_int("NowPlaying", "last-page", (int)page
);
985 /* Restore right page */
988 var page
= config
.get_int_with_default("NowPlaying", "last-page", 0);
991 notebook
.set_current_page(0);
995 /* The list is in reversed order, compensate for that. */
996 var w
= group
.nth_data(i
-page
-1);
998 notebook
.set_current_page(page
);
1002 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,1f
,0f
);
1005 /* Create pane in 2. */
1006 var bottom_hbox
= new Gtk
.HBox(false, 6);
1008 var metadata_vbox
= new Gtk
.VBox(false, 0);
1009 metadata_vbox
.pack_start(ali
, false, false, 0);
1010 sep
= new Gtk
.HSeparator();
1011 sep
.set_size_request(-1, 1);
1012 metadata_vbox
.pack_start(sep
, false, false, 0);
1013 metadata_vbox
.pack_start(notebook
, false, false, 0);
1015 bottom_hbox
.pack_start(metadata_vbox
, true, true, 0);
1017 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "Building now playing took: %.6f seconds.", t
.elapsed());
1018 /* Create album list */
1019 if(song
.album
!= null && song
.artist
!= null)
1021 var sep2
= new Gtk
.VSeparator();
1022 sep2
.set_size_request(-1, 4);
1023 bottom_hbox
.pack_start(sep2
, false, false, 0);
1025 /* Create album list */
1026 ali
= new Gtk
.Alignment(0.0f
, 0.0f
, 0.0f
, 0.0f
);
1027 var album_hbox
= new Gtk
.VBox(false, 6);
1028 album_hbox
.set_size_request(250, -1);
1029 ali
.add(album_hbox
);
1030 bottom_hbox
.pack_start(ali
, false, false, 0);
1032 var label
= new Gtk
.Label(song
.artist
);
1033 label
.selectable
= true;
1034 label
.set_size_request(240, -1);
1035 label
.set_markup(GLib
.Markup
.printf_escaped("<span size='x-large' weight='bold' color='%s'>%s</span><span size='x-large' weight='bold'> %s</span>",this
.item_color
,_("Other albums by"), song
.artist
));
1036 label
.set_line_wrap_mode(Pango
.WrapMode
.WORD_CHAR
);
1037 label
.set_line_wrap(true);
1038 label
.set_alignment(0.0f
, 0.5f
);
1039 album_hbox
.pack_start(label
, false, false,0);
1041 MPD
.Database
.search_field_start(server
, MPD
.Tag
.Type
.ALBUM
);
1042 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, song
.artist
);
1043 MPD
.Data
.Item list
= null;
1044 var data
= MPD
.Database
.search_commit(server
);
1047 unowned MPD
.Data
.Item iter
= data
.get_first();
1050 if(iter
.tag
== song
.album
)
1056 list
.type
= MPD
.Data
.Type
.SONG
;
1057 list
.song
= new MPD
.Song();
1058 list
.song
.artist
= song
.artist
;
1059 list
.song
.album
= iter
.tag
;
1061 MPD.Database.search_field_start(server,MPD.Tag.Type.DATE);
1062 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
1063 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, iter.tag);
1064 var ydata = MPD.Database.search_commit(server);
1066 list.song.date = ydata.tag;
1071 while(iter
!= null);
1074 list
.sort_album_disc_track();
1077 unowned MPD
.Data
.Item iter
= list
.get_first();
1080 var button
= new Gtk
.Button();
1081 button
.set_relief(Gtk
.ReliefStyle
.NONE
);
1082 var but_hbox
= new Gtk
.HBox(false, 6);
1083 button
.add(but_hbox
);
1084 var image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ALBUM_ART
, 48);
1085 unowned MPD
.Song but_song
= iter
.song
;
1086 image
.set_squared(true);
1087 image
.update_from_song_delayed(but_song
);
1089 but_hbox
.pack_start(image
, false, false, 0);
1091 var but_label
= new Gtk
.Label(iter
.song
.album
);
1092 but_label
.selectable
= true;
1093 but_label
.set_alignment(0.0f
, 0.5f
);
1095 if(iter
.song
.date
!= null && iter
.song
.date
.length
> 0) strlabel
+= "%s\n".printf(iter
.song
.date
);
1096 if(iter
.song
.album
!= null) strlabel
+= iter
.song
.album
;
1097 else strlabel
+= _("No Album");
1098 but_label
.set_markup(GLib
.Markup
.printf_escaped("<b>%s</b>",strlabel
));
1099 but_label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
1100 but_hbox
.pack_start(but_label
, true, true, 0);
1102 album_hbox
.pack_start(button
, false, false,0);
1103 button
.set_data("artist",
1104 but_song
.artist
.dup());
1105 button
.set_data("album",
1106 but_song
.album
.dup());
1107 stdout
.printf("open: %s %s\n", but_song
.artist
, but_song
.album
);
1108 button
.clicked
.connect((source
) =>
1110 unowned
string artist
= (string)source
.get_data
<string>("artist");
1111 unowned
string album
= (string)source
.get_data
<string>("album");
1112 stdout
.printf("open: %s %s\n", artist
, album
);
1113 Gmpc
.Browser
.Metadata
.show_album(artist
, album
);
1124 album_hbox
.destroy();
1128 vbox
.pack_start(bottom_hbox
, true, true, 0);
1131 this
.container
.add(vbox
);
1132 this
.change_color_style(this
.container
);
1133 this
.container
.show_all();
1136 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "Building now playing took: %.6f seconds.", t
.elapsed());
1139 * This shows the page when mpd is not playing, for now it is the gmpc logo + Gnome Music Player Client
1141 private void update_not_playing()
1144 song_checksum
= null;
1146 (this
.container as Gmpc
.MetaData
.Widgets
.Backdrop
).set_song(null);
1148 var it
= Gtk
.IconTheme
.get_default();
1149 Gtk
.IconInfo info
= it
.lookup_icon("gmpc", 150, 0);
1150 var path
= info
.get_filename();
1151 Gtk
.Image image
= null;
1156 var pb
= new Gdk
.Pixbuf
.from_file_at_scale(path
, 150, 150, true);
1157 image
= new Gtk
.Image
.from_pixbuf(pb
);
1161 warning("Failed to load the gmpc logo: %s", e
.message
);
1167 image
= new Gtk
.Image
.from_icon_name("gmpc", Gtk
.IconSize
.DIALOG
);
1170 var hbox
= new Gtk
.HBox(false, 6);
1171 var label
= new Gtk
.Label(_("Gnome Music Player Client"));
1172 label
.set_selectable(true);
1173 label
.set_markup("<span size='%i' weight='bold'>%s</span>".printf(28*Pango
.SCALE
,_("Gnome Music Player Client")));
1174 hbox
.pack_start(image
, false, false, 0);
1175 hbox
.pack_start(label
, false, false, 0);
1177 var ali
= new Gtk
.Alignment(0.5f
,0.5f
,0.0f
, 0.0f
);
1179 this
.container
.add(ali
);
1181 this
.change_color_style(this
.container
);
1182 this
.container
.show_all();
1186 * Update the view according to state. If playing/paused show song info, other wise the not playing page
1188 private void update()
1190 switch(MPD
.Player
.get_state(Gmpc
.server
))
1192 case MPD
.Player
.State
.PLAY
:
1193 case MPD
.Player
.State
.PAUSE
:
1194 debug("Update playing");
1198 debug("update not playing");
1199 update_not_playing();
1205 * Makes gmpc jump to the now playing browser
1207 public void select_now_playing_browser()
1209 unowned Gtk
.TreeView tree
= Gmpc
.Playlist3
.get_category_tree_view();
1210 var sel
= tree
.get_selection();
1211 var path
= np_ref
.get_path();
1214 sel
.select_path(path
);
1219 * Gmpc.Plugin.BrowserIface.add_go_menu
1221 private int browser_add_go_menu(Gtk
.Menu menu
)
1223 if(this
.get_enabled())
1225 var item
= new Gtk
.ImageMenuItem
.with_mnemonic(_("Now Playing"));
1226 item
.set_image(new Gtk
.Image
.from_icon_name("media-audiofile", Gtk
.IconSize
.MENU
));
1227 item
.activate
.connect(select_now_playing_browser
);
1228 item
.add_accelerator("activate", menu
.get_accel_group(),0x069, Gdk
.ModifierType
.CONTROL_MASK
, Gtk
.AccelFlags
.VISIBLE
);