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 int max_albums
= 10;
42 private bool theme_colors
= (bool) config
.get_int_with_default("Now Playing", "use-theme-color",1);
43 private string title_color
= config
.get_string_with_default("Now Playing", "title-color", "#4d90dd");
44 private string item_color
= config
.get_string_with_default("Now Playing", "item-color", "#304ab8");
45 private Gdk
.Color background
;
46 private Gdk
.Color foreground
;
48 private Gtk
.Label bitrate_label
= null;
49 private Gtk
.TreeRowReference np_ref
= null;
51 private bool use_backdrop
= (bool) config
.get_int_with_default("Now Playing", "use-backdrop",0);
56 /* Set the plugin as Browser type*/
57 this
.plugin_type
= 2|8;
58 /* Track changed status */
59 gmpcconn
.status_changed
.connect(status_changed
);
60 /* Track connect/disconnect */
61 gmpcconn
.connection_changed
.connect((source
, connect
) => {
62 /* If disconnect update the page */
63 if(connect
== 0 && this
.paned
!= null)
64 this
.update_not_playing();
67 var background
= config
.get_string_with_default("Now Playing",
68 "background-color", "#000");
69 var foreground
= config
.get_string_with_default("Now Playing",
70 "foreground-color", "#FFF");
71 Gdk
.Color
.parse(background
,out this
.background
);
72 Gdk
.Color
.parse(foreground
,out this
.foreground
);
74 /* Register easycommand to switch to this browser */
75 easy_command
.add_entry(
76 _("switch now playing"),
78 _("Switch to Now Playing"),
79 (Gmpc
.Easy
.Command
.Callback
*)select_now_playing_browser
,
82 /* Version of the plugin*/
83 private const int[] version
= {0,0,0};
84 public override unowned
int[] get_version()
89 public override unowned
string get_name()
91 return N_("Now Playing");
94 public override void set_enabled(bool state
)
100 browser_add( Gmpc
.Playlist3
.get_category_tree_view());
106 if(this
.np_ref
!= null)
108 var path
= np_ref
.get_path();
111 unowned
int[] indices
= path
.get_indices();
112 config
.set_int(this
.get_name(), "position", indices
[0]);
113 Gtk
.ListStore model
= (Gtk
.ListStore
) np_ref
.get_model();
115 if(model
.get_iter(out iter
, path
))
121 if(this
.paned
!= null)
123 this
.paned
.destroy();
125 this
.song_checksum
= null;
129 if(this
.get_name() != null)
130 Gmpc
.config
.set_int(this
.get_name(), "enabled", (int)state
);
132 /* Save our position in the side-bar */
133 public override void save_yourself()
135 if(this
.np_ref
!= null)
137 var path
= np_ref
.get_path();
140 unowned
int[] indices
= path
.get_indices();
141 config
.set_int(this
.get_name(), "position", indices
[0]);
146 /* React MPD's status changed */
149 status_changed(Gmpc
.Connection conn
, MPD
.Server server
, MPD
.Status
.Changed what
)
151 if(!this
.get_enabled())return;
152 if(!this
.selected
) return;
153 /* If the state changes, update. */
154 if((what
&MPD
.Status
.Changed
.STATE
) == MPD
.Status
.Changed
.STATE
)
158 /* If the playlist changed, this might mean that the metadata of the currently playing song changed, update. */
159 else if ((what
&(MPD
.Status
.Changed
.SONGID
|MPD
.Status
.Changed
.PLAYLIST
)) > 0)
163 /* If the bitrate changed, update the bitrate label. */
164 if((what
&(MPD
.Status
.Changed
.BITRATE
|MPD
.Status
.Changed
.AUDIOFORMAT
)) > 0)
166 if(bitrate_label
!= null)
168 var channels
= MPD
.Status
.get_channels(Gmpc
.server
);
169 debug("bitrate changed");
170 var bitrate
= MPD
.Status
.get_bitrate(Gmpc
.server
);
171 bitrate_label
.set_markup(GLib
.Markup
.printf_escaped(
172 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
173 this
.item_color
, _("Format"),
174 channels
, GLib
.ngettext(N_("Channel"),N_("Channels"), channels
),
175 MPD
.Status
.get_samplerate(Gmpc
.server
)/1000.0, "kHz",
184 private Gtk
.ScrolledWindow paned
= null;
185 private Gtk
.EventBox container
= null;
186 private bool selected
= false;
188 * Browser Interface bindings
190 public void browser_add (Gtk
.Widget category_tree
)
192 Gtk
.TreeView tree
= (Gtk
.TreeView
)category_tree
;
193 Gtk
.ListStore store
= (Gtk
.ListStore
)tree
.get_model();
194 Gtk
.TreeModel model
= tree
.get_model();
196 Gmpc
.Browser
.insert(out iter
, Gmpc
.Playlist
.BrowserType
.TOP
);
197 store
.set(iter
, 0, this
.id
, 1, this
.get_name(), 3, "media-audiofile");
198 /* Create a row reference */
199 this
.np_ref
= new Gtk
.TreeRowReference(model
, model
.get_path(iter
));
201 /* Called by gmpc, telling the plugin to embed itself in container */
202 public void browser_selected (Gtk
.Container container
)
207 this
.selected
= true;
209 container
.add(this
.paned
);
211 container
.show_all();
212 container
.ensure_style();
213 if(this
.theme_colors
)
215 this
.title_color
= this
.paned
.style
.text
[Gtk
.StateType
.PRELIGHT
].to_string();
216 this
.item_color
= this
.paned
.style
.text
[Gtk
.StateType
.PRELIGHT
].to_string();
220 this
.title_color
= "#fff";
221 this
.item_color
= "#fff";
222 this
.theme_colors
= false;
227 /* Called by gmpc, telling the plugin to remove itself from the container */
228 public void browser_unselected(Gtk
.Container container
)
230 this
.selected
= false;
231 container
.remove(this
.paned
);
235 * If the style changed because f.e. the user switched theme, make sure the correct colouring is kept preserved.
238 private void browser_bg_style_changed(Gtk
.Widget bg
,Gtk
.Style? style
)
240 debug("Change style signal");
241 if(this
.theme_colors
)
243 this
.title_color
= this
.paned
.style
.text
[Gtk
.StateType
.PRELIGHT
].to_string();
244 this
.item_color
= this
.paned
.style
.text
[Gtk
.StateType
.PRELIGHT
].to_string();
246 this
.change_color_style(this
.container
);
249 * Recursively force a style on widget bg and children.
251 private void change_color_style(Gtk
.Widget bg
)
253 debug("change style");
254 if(bg is Gtk
.Separator
|| bg is Gtk
.Notebook
|| bg is Gtk
.CheckButton
|| bg is Gtk
.Image
)
262 bg
.modify_bg(Gtk
.StateType
.NORMAL
,this
.paned
.style
.base[Gtk
.StateType
.NORMAL
]);
263 /*bg.modify_base(Gtk.StateType.NORMAL,this.paned.style.mid[Gtk.StateType.NORMAL]);/*
264 // bg.modify_text(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
265 bg.modify_fg(Gtk.StateType.NORMAL,this.paned.style.text[Gtk.StateType.NORMAL]);
266 bg.modify_text(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);
267 bg.modify_fg(Gtk.StateType.ACTIVE,this.paned.style.light[Gtk.StateType.NORMAL]);*/
271 bg
.modify_bg(Gtk
.StateType
.NORMAL
,this
.background
);
272 bg
.modify_base(Gtk
.StateType
.NORMAL
,this
.background
);
273 bg
.modify_text(Gtk
.StateType
.NORMAL
,this
.foreground
);
274 bg
.modify_fg(Gtk
.StateType
.NORMAL
,this
.foreground
);
275 bg
.modify_text(Gtk
.StateType
.ACTIVE
,this
.foreground
);
276 bg
.modify_fg(Gtk
.StateType
.ACTIVE
,this
.foreground
);
279 /* Recurse into children, if the widget can hold children (so is a container */
280 if(bg is Gtk
.Container
)
282 foreach(Gtk
.Widget child
in ((Gtk
.Container
)bg
).get_children())
284 change_color_style(child
);
288 /* Create the basic gui. on initializing */
289 private void browser_init()
291 if(this
.paned
== null)
294 this
.paned
= new Gtk
.ScrolledWindow(null,null);
295 this
.paned
.set_policy(Gtk
.PolicyType
.AUTOMATIC
, Gtk
.PolicyType
.AUTOMATIC
);
296 this
.paned
.set_shadow_type(Gtk
.ShadowType
.ETCHED_IN
);
299 this
.container
= new Gmpc
.MetaData
.Widgets
.Backdrop(Gmpc
.MetaData
.Type
.BACKDROP_ART
);
303 this
.container
= new Gtk
.EventBox();
306 this.container.set_focus_hadjustment(this.paned.get_hadjustment());
307 this.container.set_focus_vadjustment(this.paned.get_vadjustment());
309 this
.paned
.style_set
.connect(browser_bg_style_changed
);
310 this
.paned
.add_with_viewport(this
.container
);
311 this
.paned
.get_vadjustment().set("step-increment", 20.0);
312 this
.paned
.show_all();
317 /* Clear the view inside the scrolled window*/
321 var list
= this
.container
.get_children();
322 foreach(Gtk
.Widget child
in list
)
326 bitrate_label
= null;
330 private string get_extension(string path
)
332 long length
= path
.length
;
335 for(; i
>0 && (length
-i
) <8; i
--)
339 retv
= path
.substring(i
+1);
346 * Show the page when playing
348 private string song_checksum
= null;
349 private void update_playing()
351 unowned MPD
.Song? song
= server
.playlist_get_current_song();
354 debug("GMPC Is playing, cannot get this");
356 (this
.container as Gmpc
.MetaData
.Widgets
.Backdrop
).set_song(null);
357 update_not_playing();
360 /* Force it so we won't update when not needed */
361 var checksum
= Gmpc
.Misc
.song_checksum(song
);
362 if(checksum
== this
.song_checksum
)
364 /* No need to update. */
367 GLib
.Timer t
= new GLib
.Timer();
370 (this
.container as Gmpc
.MetaData
.Widgets
.Backdrop
).set_song(song
);
371 this
.song_checksum
= checksum
;
373 var vbox
= new Gtk
.VBox (false,6);
374 vbox
.border_width
= 8;
375 /* Start building the gui */
377 var hbox
= new Gtk
.HBox(false, 6);
378 Gtk
.Alignment ali
= null;
380 int meta_size
= (int)(this
.container
.get_allocated_width()*0.20);
381 /* get size based on alloc */
382 meta_size
= int.min(int.max(100, meta_size
), 250);
383 if(config
.get_int_with_default("Interface", "hide-album-art", 0) == 0)
386 ali
= new Gtk
.Alignment(0f
,0f
,0f
,0f
);
387 //ali.set_size_request(meta_size,meta_size);
388 var album_image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ALBUM_ART
, meta_size
);
389 album_image
.set_scale_up(true);
390 album_image
.set_squared(false);
391 ali
.add(album_image
);
392 album_image
.update_from_song(song
);
393 hbox
.pack_start(ali
, false, false, 0);
397 if(config
.get_int_with_default("Interface", "hide-album-art", 0) == 0 && !use_backdrop
)
399 ali
= new Gtk
.Alignment(1f
,0f
,0f
,0f
);
400 var artist_image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ARTIST_ART
, meta_size
);
401 artist_image
.set_scale_up(true);
402 artist_image
.set_squared(false);
403 artist_image
.update_from_song(song
);
404 ali
.add(artist_image
);
405 hbox
.pack_end(ali
, false, false, 0);
408 /* Information box */
409 var info_vbox
= new Gtk
.VBox(false, 6);
411 if(song
.title
!= null)
413 var box
= new Gtk
.HBox(false, 6);
416 if(config
.get_int_with_default("Interface", "hide-favorites-icon",0) == 0)
418 var fav_button
= new Gmpc
.Favorites
.Button();
419 fav_button
.set_song(song
);
420 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,0f
,0f
);
422 box
.pack_start(ali
, false, false, 0);
424 var label
= new Gtk
.Label(song
.title
);
425 label
.selectable
= true;
426 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",
427 this
.title_color
,Pango
.SCALE
*20 ,song
.title
));
428 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
429 label
.set_alignment(0.0f
, 0.5f
);
430 box
.pack_start(label
, true, true, 0);
431 info_vbox
.pack_start(box
, false, false, 0);
434 else if (song
.name
!= null)
436 var label
= new Gtk
.Label(song
.name
);
437 label
.selectable
= true;
438 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this
.
439 title_color
, Pango
.SCALE
*20, song
.name
));
440 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
441 label
.set_alignment(0.0f
, 0.5f
);
442 info_vbox
.pack_start(label
, false, false, 0);
444 else if (song
.file
!= null)
446 var filename
= GLib
.Path
.get_basename(song
.file
);
447 var label
= new Gtk
.Label(song
.name
);
448 label
.selectable
= true;
451 var regex_a
= new GLib
.Regex ("\\.[0-9a-zA-Z]*$");
452 filename
= regex_a
.replace_literal (filename
, -1, 0, "");
454 catch (GLib
.RegexError e
)
456 GLib
.error("%s", e
.message
);
460 var regex_b
= new GLib
.Regex ("_");
461 filename
= regex_b
.replace_literal (filename
, -1, 0, " ");
463 catch (GLib
.RegexError e
)
465 GLib
.error("%s", e
.message
);
467 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this
.
468 title_color
, Pango
.SCALE
*20, filename
));
469 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
470 label
.set_alignment(0.0f
, 0.5f
);
471 info_vbox
.pack_start(label
, false, false, 0);
475 if(song
.artist
!= null)
477 var event
= new Gtk
.EventBox();
478 var box
= new Gtk
.HBox(false, 6);
479 var label
= new Gtk
.Label(song
.artist
);
480 event
.set_visible_window(false);
481 label
.selectable
= true;
482 var image
= new Gtk
.Image
.from_icon_name("media-artist", Gtk
.IconSize
.MENU
);
484 box
.pack_start(event
, false, false, 0);
485 label
.set_markup(GLib
.Markup
.printf_escaped("<span size='xx-large' weight='bold'>%s</span>", song
.artist
));
486 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
487 label
.set_alignment(0.0f
, 0.5f
);
488 box
.pack_start(label
, true, true, 0);
489 info_vbox
.pack_start(box
, false, false, 0);
491 event
.set_data("artist",song
.artist
);
492 event
.button_press_event
.connect((widget
, event
) =>
494 string artist
= (string)widget
.get_data
<string>("artist");
495 Gmpc
.Browser
.Metadata
.show_artist(artist
);
500 if(song
.album
!= null)
502 var event
= new Gtk
.EventBox();
503 var box
= new Gtk
.HBox(false, 6);
504 var label
= new Gtk
.Label(song
.album
);
505 event
.set_visible_window(false);
506 label
.selectable
= true;
507 var image
= new Gtk
.Image
.from_icon_name("media-album", Gtk
.IconSize
.MENU
);
509 box
.pack_start(event
, false, false, 0);
510 label
.set_markup(GLib
.Markup
.printf_escaped("<span size='x-large' weight='bold'>%s %s</span>", song
.album
,
511 (song
.date
!= null)?
"(%s)".printf(song
.date
):""));
512 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
513 label
.set_alignment(0.0f
, 0.5f
);
514 box
.pack_start(label
, true, true, 0);
515 info_vbox
.pack_start(box
, false, false, 0);
519 event
.set_data("artist",song
.artist
);
520 event
.set_data("album",song
.album
);
521 event
.button_press_event
.connect((widget
, event
) =>
523 string artist
= (string)widget
.get_data
<string>("artist");
524 string album
= (string)widget
.get_data
<string>("album");
525 if(artist
!= null && album
!= null)
527 Gmpc
.Browser
.Metadata
.show_album(artist
,album
);
534 if(song
.genre
!= null)
536 var box
= new Gtk
.HBox(false, 6);
537 var label
= new Gtk
.Label(song
.title
);
538 label
.selectable
= true;
539 var image
= new Gtk
.Image
.from_icon_name("media-genre", Gtk
.IconSize
.MENU
);
540 box
.pack_start(image
, false, false, 0);
541 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
542 this
.item_color
,_("Genre"), song
.genre
));
543 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
544 label
.set_alignment(0.0f
, 0.5f
);
545 box
.pack_start(label
, true, true, 0);
546 info_vbox
.pack_start(box
, false, false, 0);
551 var box
= new Gtk
.HBox(false, 6);
552 var image
= new Gtk
.Image
.from_icon_name("media-format", Gtk
.IconSize
.MENU
);
553 box
.pack_start(image
, false, false, 0);
555 bitrate_label
= new Gtk
.Label(song
.title
);
556 bitrate_label
.selectable
= true;
557 bitrate_label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
558 bitrate_label
.set_alignment(0.0f
, 0.5f
);
560 box
.pack_start(bitrate_label
, true, true, 0);
562 var bitrate
= MPD
.Status
.get_bitrate(Gmpc
.server
);
563 var channels
= MPD
.Status
.get_channels(Gmpc
.server
);
564 bitrate_label
.set_markup(GLib
.Markup
.printf_escaped(
565 "<span color='%s' weight='bold'>%s:</span> %i %s, %.1f %s, %i %s",
566 this
.item_color
, _("Format"),
567 channels
, GLib
.ngettext(N_("Channel"),N_("Channels"), channels
),
568 MPD
.Status
.get_samplerate(Gmpc
.server
)/1000.0, "kHz",
572 info_vbox
.pack_start(box
, false, false, 0);
574 if(song
.file
!= null)
577 string extension
= null;
578 extension
= get_extension(song
.file
);
579 if(extension
!= null)
581 var box
= new Gtk
.HBox(false, 6);
582 var image
= new Gtk
.Image
.from_icon_name("media-codec", Gtk
.IconSize
.MENU
);
583 box
.pack_start(image
, false, false, 0);
585 var label
= new Gtk
.Label(song
.title
);
586 label
.selectable
= true;
587 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
588 label
.set_alignment(0.0f
, 0.5f
);
589 box
.pack_start(label
, true, true, 0);
590 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
591 this
.item_color
, _("Codec"),
593 info_vbox
.pack_start(box
, false, false, 0);
599 var box
= new Gtk
.HBox(false, 6);
600 var image
= new Gtk
.Image
.from_icon_name("media-track-length", Gtk
.IconSize
.MENU
);
601 box
.pack_start(image
, false, false, 0);
602 var label
= new Gtk
.Label("");
603 label
.selectable
= true;
604 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
605 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s",
606 this
.item_color
,_("Length"),
607 Gmpc
.Misc
.format_time((ulong) song
.time
, "")));
608 label
.set_alignment(0.0f
, 0.5f
);
609 box
.pack_start(label
, true, true, 0);
610 info_vbox
.pack_start(box
, false, false, 0);
613 if(song
.track
!= null)
615 var box
= new Gtk
.HBox(false, 6);
616 var image
= new Gtk
.Image
.from_icon_name("media-num-tracks", Gtk
.IconSize
.MENU
);
617 box
.pack_start(image
, false, false, 0);
618 var label
= new Gtk
.Label("");
619 label
.selectable
= true;
620 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
621 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' weight='bold'>%s:</span> %s %s",
622 this
.item_color
, _("Track number"),
624 (song
.disc
!= null)?
"[%s]".printf(song
.disc
):""
626 label
.set_alignment(0.0f
, 0.5f
);
627 box
.pack_start(label
, true, true, 0);
628 info_vbox
.pack_start(box
, false, false, 0);
632 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "heading took: %.6f seconds.", t
.elapsed());
633 hbox
.pack_start(info_vbox
, true, true, 0);
634 vbox
.pack_start(hbox
, false, false, 0);
637 var sep
= new Gtk
.HSeparator();
638 sep
.set_size_request(-1, 4);
639 vbox
.pack_start(sep
, false, false, 0);
641 var hboxje
= new Gtk
.HBox(false, 6);
643 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
644 var notebook
= new Gtk
.Notebook();
645 notebook
.set_show_border(false);
646 notebook
.set_show_tabs(false);
650 unowned SList
<unowned Gtk
.RadioButton
> group
= null;
651 if(config
.get_int_with_default("MetaData", "show-lyrics",1) == 1)
653 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
654 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
, Gmpc
.MetaData
.Type
.SONG_TXT
);
656 notebook
.append_page(alib
, new Gtk
.Label("Lyrics"));
657 var button
= new Gtk
.RadioButton(group
);//.with_label(group,("Lyrics"));
658 var label
= new Gtk
.Label(_("Lyrics"));
659 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
660 label
.set_alignment(0.0f
, 0.5f
);
661 // button.add(label);
664 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
665 group
= button
.get_group();
666 hboxje
.pack_start(button
, false, false, 0);
667 hboxje
.pack_start(label
, true, true, 0);
669 button
.clicked
.connect((source
) =>
671 if((source as Gtk
.CheckButton
).get_active())
673 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "lyrics notebook page %i clicked", j
);
674 notebook
.set_current_page(j
);
681 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "lyrics took: %.6f seconds.", t
.elapsed());
683 /* Album information */
684 if(config
.get_int_with_default("MetaData", "show-album-information",1) == 1)
686 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
687 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
, Gmpc
.MetaData
.Type
.ALBUM_TXT
);
689 notebook
.append_page(alib
, new Gtk
.Label("Album information"));
690 var button
= new Gtk
.RadioButton(group
);
691 var label
= new Gtk
.Label(_("Album information"));
692 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
693 label
.set_alignment(0.0f
, 0.5f
);
696 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
697 group
= button
.get_group();
698 hboxje
.pack_start(button
, false, false, 0);
699 hboxje
.pack_start(label
, true, true, 0);
701 button
.clicked
.connect((source
) =>
703 if((source as Gtk
.CheckButton
).get_active())
705 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "lyrics notebook page %i clicked", j
);
706 notebook
.set_current_page(j
);
715 if(config
.get_int_with_default("MetaData", "show-guitar-tabs",1) == 1)
717 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
718 var text_view_queried
= false;
719 notebook
.append_page(alib
, new Gtk
.Label(_("Guitar Tabs")));
720 var button
= new Gtk
.RadioButton(group
);//.with_label(group,_("Guitar Tabs"));
721 var label
= new Gtk
.Label(_("Guitar Tabs"));
722 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
723 label
.set_alignment(0.0f
, 0.5f
);
726 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
727 group
= button
.get_group();
728 hboxje
.pack_start(button
, false, false, 0);
729 hboxje
.pack_start(label
, true, true, 0);
731 /* Only query the guitar-tab when opened or first notebook page*/
732 button
.clicked
.connect((source
) =>
734 if((source as Gtk
.CheckButton
).get_active())
736 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "guitar tab notebook page %i clicked", j
);
737 notebook
.set_current_page(j
);
738 if(!text_view_queried
)
740 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
, Gmpc
.MetaData
.Type
.SONG_GUITAR_TAB
);
742 text_view_queried
= true;
743 this
.change_color_style(text_view
);
750 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
, Gmpc
.MetaData
.Type
.SONG_GUITAR_TAB
);
752 text_view_queried
= true;
757 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "guitar tabs took: %.6f seconds.", t
.elapsed());
761 if(config
.get_int_with_default("MetaData", "show-similar-songs",1) == 1)
763 var similar_songs_queried
= false;
764 var similar_songs_box
= new Gtk
.Alignment(0f
,0f
,0f
,0f
);
766 notebook
.append_page(similar_songs_box
, new Gtk
.Label(_("Similar Songs")));
768 var button
= new Gtk
.RadioButton(group
);//.with_label(group,_("Similar Songs"));
769 var label
= new Gtk
.Label(_("Similar Songs"));
770 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
771 label
.set_alignment(0.0f
, 0.5f
);
774 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
775 group
= button
.get_group();
776 hboxje
.pack_start(button
, false, false, 0);
777 hboxje
.pack_start(label
, true, true, 0);
780 /* Only query when opened or first notebook page*/
781 button
.clicked
.connect((source
) =>
783 if((source as Gtk
.CheckButton
).get_active())
785 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "similar song notebook page %i clicked", j
);
786 notebook
.set_current_page(j
);
787 if(!similar_songs_queried
)
789 var similar_songs
= new Gmpc
.MetaData
.Widgets
.SimilarSongs(song
);
790 similar_songs
.update();
791 similar_songs_queried
= true;
792 similar_songs_box
.add(similar_songs
);
793 this
.change_color_style(similar_songs_box
);
794 similar_songs_box
.show_all();
800 var similar_songs
= new Gmpc
.MetaData
.Widgets
.SimilarSongs(song
);
801 similar_songs
.update();
802 similar_songs_queried
= true;
803 similar_songs_box
.add(similar_songs
);
804 similar_songs_box
.show_all();
806 similar_songs_box
.show();
810 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "similar songs took: %.6f seconds.", t
.elapsed());
811 if(config
.get_int_with_default("MetaData", "show-similar-artist",1) == 1 && song
.artist
!= null)
813 var similar_artist
= new Gmpc
.MetaData
.Widgets
.SimilarArtists(Gmpc
.server
,song
);
815 notebook
.append_page(similar_artist
, new Gtk
.Label(_("Similar Artist")));
817 var button
= new Gtk
.RadioButton(group
);//.with_label(group,_("Similar Artist"));
818 var label
= new Gtk
.Label(_("Similar Artist"));
819 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
820 label
.set_alignment(0.0f
, 0.5f
);
823 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
824 group
= button
.get_group();
825 hboxje
.pack_start(button
, false, false, 0);
826 hboxje
.pack_start(label
, true, true, 0);
829 button
.clicked
.connect((source
) =>
831 if((source as Gtk
.CheckButton
).get_active())
833 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "similar artist notebook page %i clicked", j
);
834 similar_artist
.first_show();
835 notebook
.set_current_page(j
);
838 similar_artist
.show();
841 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "similar Artist took: %.6f seconds.", t
.elapsed());
842 if(config
.get_int_with_default("MetaData", "show-artist-information",1) == 1)
844 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
845 var text_view_queried
= false;
847 notebook
.append_page(alib
, new Gtk
.Label(_("Artist information")));
848 var button
= new Gtk
.RadioButton(group
);//.with_label(group,_("Artist information"));
849 var label
= new Gtk
.Label(_("Artist information"));
850 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
851 label
.set_alignment(0.0f
, 0.5f
);
854 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
855 group
= button
.get_group();
856 hboxje
.pack_start(button
, false, false, 0);
857 hboxje
.pack_start(label
, true, true, 0);
859 /* Only query the guitar-tab when opened or first notebook page*/
860 button
.clicked
.connect((source
) =>
862 if((source as Gtk
.CheckButton
).get_active())
864 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "artist info notebook page %i clicked", j
);
865 notebook
.set_current_page(j
);
866 if(!text_view_queried
)
868 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
,Gmpc
.MetaData
.Type
.ARTIST_TXT
);
870 text_view_queried
= true;
872 this
.change_color_style(text_view
);
878 var text_view
= new Gmpc
.MetaData
.Widgets
.TextLabel(song
,Gmpc
.MetaData
.Type
.ARTIST_TXT
);
880 text_view_queried
= true;
886 if(config
.get_int_with_default("MetaData", "show-songs-from-album",1) == 1)
888 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
889 var text_view_queried
= false;
891 notebook
.append_page(alib
, new Gtk
.Label(_("Songs from album")));
892 var button
= new Gtk
.RadioButton(group
);//.with_label(group,_("Songs from album"));
893 var label
= new Gtk
.Label(_("Songs from album"));
894 label
.ellipsize
= Pango
.EllipsizeMode
.END
;
895 label
.set_alignment(0.0f
, 0.5f
);
898 hboxje
.pack_start(new Gtk
.VSeparator(), false, false, 0);
899 group
= button
.get_group();
900 hboxje
.pack_start(button
, false, false, 0);
901 hboxje
.pack_start(label
, true, true, 0);
903 var sl
= new Gmpc
.DataView("now-playing-song-from-album");
904 var sl_model
= new Gmpc
.MpdData
.Model();
905 sl
.set_model(sl_model
);
908 button
.clicked
.connect((source
) =>
910 if((source as Gtk
.CheckButton
).get_active())
912 GLib
.log(np2_LOG_DOMAIN
,GLib
.LogLevelFlags
.LEVEL_DEBUG
, "artist info notebook page %i clicked", j
);
913 notebook
.set_current_page(j
);
914 if(!text_view_queried
)
916 if(song
.artist
!= null && song
.album
!= null)
918 MPD
.Database
.search_start(server
,true);
919 if(song
.albumartist
!= null)
921 MPD
.Database
.search_add_constraint(server
,
922 MPD
.Tag
.Type
.ALBUM_ARTIST
, song
.albumartist
);
926 MPD
.Database
.search_add_constraint(server
,
927 MPD
.Tag
.Type
.ARTIST
, song
.artist
);
929 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, song
.album
);
930 var data
= MPD
.Database
.search_commit(server
);
931 data
.sort_album_disc_track();
932 sl_model
.set_mpd_data((owned
)data
);
933 // sl.set_from_data((owned)data, true);
934 // this.change_color_style(sl);
939 alib
.add(new Gtk
.Label(_("Not available")));
941 text_view_queried
= true;
947 if(song
.artist
!= null && song
.album
!= null)
949 MPD
.Database
.search_start(server
,true);
950 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, song
.artist
);
951 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, song
.album
);
952 var data
= MPD
.Database
.search_commit(server
);
953 data
.sort_album_disc_track();
954 sl_model
.set_mpd_data((owned
)data
);
955 //sl.set_from_data((owned)data, true);
960 alib
.add(new Gtk
.Label(_("Not available")));
962 text_view_queried
= true;
968 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "Artist info took: %.6f seconds.", t
.elapsed());
969 /* Track changed pages */
970 notebook
.notify
["page"].connect((source
,spec
) =>
972 var page
= notebook
.get_current_page();
973 config
.set_int("NowPlaying", "last-page", (int)page
);
976 /* Restore right page */
979 var page
= config
.get_int_with_default("NowPlaying", "last-page", 0);
982 notebook
.set_current_page(0);
986 /* The list is in reversed order, compensate for that. */
987 var w
= group
.nth_data(i
-page
-1);
989 notebook
.set_current_page(page
);
993 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,1f
,0f
);
996 /* Create pane in 2. */
997 var bottom_hbox
= new Gtk
.HBox(false, 6);
999 var metadata_vbox
= new Gtk
.VBox(false, 0);
1000 metadata_vbox
.pack_start(ali
, false, false, 0);
1001 sep
= new Gtk
.HSeparator();
1002 sep
.set_size_request(-1, 1);
1003 metadata_vbox
.pack_start(sep
, false, false, 0);
1004 metadata_vbox
.pack_start(notebook
, false, false, 0);
1006 bottom_hbox
.pack_start(metadata_vbox
, true, true, 0);
1008 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "Building now playing took: %.6f seconds.", t
.elapsed());
1009 /* Create album list */
1010 if(song
.album
!= null && song
.artist
!= null)
1012 var sep2
= new Gtk
.VSeparator();
1013 sep2
.set_size_request(-1, 4);
1014 bottom_hbox
.pack_start(sep2
, false, false, 0);
1016 /* Create album list */
1017 ali
= new Gtk
.Alignment(0.0f
, 0.0f
, 0.0f
, 0.0f
);
1018 var album_hbox
= new Gtk
.VBox(false, 6);
1019 album_hbox
.set_size_request(250, -1);
1020 ali
.add(album_hbox
);
1021 bottom_hbox
.pack_start(ali
, false, false, 0);
1023 var label
= new Gtk
.Label(song
.artist
);
1024 label
.selectable
= true;
1025 label
.set_size_request(240, -1);
1026 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
));
1027 label
.set_line_wrap_mode(Pango
.WrapMode
.WORD_CHAR
);
1028 label
.set_line_wrap(true);
1029 label
.set_alignment(0.0f
, 0.5f
);
1030 album_hbox
.pack_start(label
, false, false,0);
1032 MPD
.Database
.search_field_start(server
, MPD
.Tag
.Type
.ALBUM
);
1033 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, song
.artist
);
1034 MPD
.Data
.Item list
= null;
1035 var data
= MPD
.Database
.search_commit(server
);
1038 unowned MPD
.Data
.Item iter
= data
.get_first();
1041 if(iter
.tag
== song
.album
)
1047 list
.type
= MPD
.Data
.Type
.SONG
;
1048 list
.song
= new MPD
.Song();
1049 list
.song
.artist
= song
.artist
;
1050 list
.song
.album
= iter
.tag
;
1052 MPD.Database.search_field_start(server,MPD.Tag.Type.DATE);
1053 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, song.artist);
1054 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, iter.tag);
1055 var ydata = MPD.Database.search_commit(server);
1057 list.song.date = ydata.tag;
1062 while(iter
!= null);
1065 list
.sort_album_disc_track();
1069 unowned MPD
.Data
.Item iter
= list
.get_first();
1072 if(count
> this
.max_albums
)
1074 var l
= new Gtk
.Label(_("More..."));
1075 l
.set_alignment(0, 0.5f
);
1076 album_hbox
.pack_start(l
, false,false, 0);
1082 var button
= new Gtk
.Button();
1083 button
.set_relief(Gtk
.ReliefStyle
.NONE
);
1084 var but_hbox
= new Gtk
.HBox(false, 6);
1085 button
.add(but_hbox
);
1086 var image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ALBUM_ART
, 48);
1087 unowned MPD
.Song but_song
= iter
.song
;
1088 image
.set_squared(true);
1089 image
.update_from_song_delayed(but_song
);
1091 but_hbox
.pack_start(image
, false, false, 0);
1093 var but_label
= new Gtk
.Label(iter
.song
.album
);
1094 but_label
.selectable
= true;
1095 but_label
.set_alignment(0.0f
, 0.5f
);
1097 if(iter
.song
.date
!= null && iter
.song
.date
.length
> 0) strlabel
+= "%s\n".printf(iter
.song
.date
);
1098 if(iter
.song
.album
!= null) strlabel
+= iter
.song
.album
;
1099 else strlabel
+= _("No Album");
1100 but_label
.set_markup(GLib
.Markup
.printf_escaped("<b>%s</b>",strlabel
));
1101 but_label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
1102 but_hbox
.pack_start(but_label
, true, true, 0);
1104 album_hbox
.pack_start(button
, false, false,0);
1105 button
.set_data("artist",
1106 but_song
.artist
.dup());
1107 button
.set_data("album",
1108 but_song
.album
.dup());
1109 stdout
.printf("open: %s %s\n", but_song
.artist
, but_song
.album
);
1110 button
.clicked
.connect((source
) =>
1112 unowned
string artist
= (string)source
.get_data
<string>("artist");
1113 unowned
string album
= (string)source
.get_data
<string>("album");
1114 stdout
.printf("open: %s %s\n", artist
, album
);
1115 Gmpc
.Browser
.Metadata
.show_album(artist
, album
);
1126 album_hbox
.destroy();
1130 vbox
.pack_start(bottom_hbox
, true, true, 0);
1133 this
.container
.add(vbox
);
1134 this
.change_color_style(this
.container
);
1135 this
.container
.show_all();
1138 GLib
.log(np2_LOG_DOMAIN
, GLib
.LogLevelFlags
.LEVEL_DEBUG
, "Building now playing took: %.6f seconds.", t
.elapsed());
1141 * This shows the page when mpd is not playing, for now it is the gmpc logo + Gnome Music Player Client
1143 private void update_not_playing()
1146 song_checksum
= null;
1148 (this
.container as Gmpc
.MetaData
.Widgets
.Backdrop
).set_song(null);
1150 var it
= Gtk
.IconTheme
.get_default();
1151 Gtk
.IconInfo info
= it
.lookup_icon("gmpc", 150, 0);
1152 var path
= info
.get_filename();
1153 Gtk
.Image image
= null;
1158 var pb
= new Gdk
.Pixbuf
.from_file_at_scale(path
, 150, 150, true);
1159 image
= new Gtk
.Image
.from_pixbuf(pb
);
1163 warning("Failed to load the gmpc logo: %s", e
.message
);
1169 image
= new Gtk
.Image
.from_icon_name("gmpc", Gtk
.IconSize
.DIALOG
);
1172 var hbox
= new Gtk
.HBox(false, 6);
1173 var label
= new Gtk
.Label(_("Gnome Music Player Client"));
1174 label
.set_selectable(true);
1175 label
.set_markup("<span size='%i' weight='bold'>%s</span>".printf(28*Pango
.SCALE
,_("Gnome Music Player Client")));
1176 hbox
.pack_start(image
, false, false, 0);
1177 hbox
.pack_start(label
, false, false, 0);
1179 var ali
= new Gtk
.Alignment(0.5f
,0.5f
,0.0f
, 0.0f
);
1181 this
.container
.add(ali
);
1183 this
.change_color_style(this
.container
);
1184 this
.container
.show_all();
1188 * Update the view according to state. If playing/paused show song info, other wise the not playing page
1190 private void update()
1192 switch(MPD
.Player
.get_state(Gmpc
.server
))
1194 case MPD
.Player
.State
.PLAY
:
1195 case MPD
.Player
.State
.PAUSE
:
1196 debug("Update playing");
1200 debug("update not playing");
1201 update_not_playing();
1207 * Makes gmpc jump to the now playing browser
1209 public void select_now_playing_browser()
1211 unowned Gtk
.TreeView tree
= Gmpc
.Playlist3
.get_category_tree_view();
1212 var sel
= tree
.get_selection();
1213 var path
= np_ref
.get_path();
1216 sel
.select_path(path
);
1221 * Gmpc.Plugin.BrowserIface.add_go_menu
1223 private int browser_add_go_menu(Gtk
.Menu menu
)
1225 if(this
.get_enabled())
1227 var item
= new Gtk
.ImageMenuItem
.with_mnemonic(_("Now Playing"));
1228 item
.set_image(new Gtk
.Image
.from_icon_name("media-audiofile", Gtk
.IconSize
.MENU
));
1229 item
.activate
.connect(select_now_playing_browser
);
1230 item
.add_accelerator("activate", menu
.get_accel_group(),0x069, Gdk
.ModifierType
.CONTROL_MASK
, Gtk
.AccelFlags
.VISIBLE
);