]> git.netwichtig.de Git - user/henk/code/ruby/grux.git/blob - bin/grux.rb
3583f3d66d6edf46c1a5b87094e90aa7c21ee4f1
[user/henk/code/ruby/grux.git] / bin / grux.rb
1 #!/usr/bin/env ruby
2
3 #$: << File.expand_path(File.dirname(FILE) + “/../lib”))
4
5 #require 'libgruxclient'
6 require 'gtk2'
7 require 'xmmsclient'
8 require 'xmmsclient_glib'
9
10 class Grux
11 end
12
13 class Grux::ClientWin < Gtk::VBox
14   attr_reader :status
15
16   def initialize
17     super
18
19     @status                 = Hash.new
20
21     @server                 = Xmms::Client.new( 'Grux' )
22     begin
23       @server.connect( ENV['XMMS_PATH'] )
24       @server.add_to_glib_mainloop
25     rescue Xmms::Client::ClientError => ex
26       warn "Connection failed. Error Code:"
27       warn ex
28       raise
29     end
30
31
32     @statusBox              = Gtk::HBox.new
33     @mainBox                = Gtk::VPaned.new
34     @statusBar              = Gtk::Statusbar.new
35
36     self.pack_start @statusBox, false
37     self.pack_start @mainBox
38     self.pack_end @statusBar, false
39
40
41     @statusWdgts            = [
42       @currentartistFrame     = Gtk::Frame.new( "Artist" ).add( @currentartistLabel = Gtk::Label.new ),
43       @currenttitleFrame      = Gtk::Frame.new( "Title" ).add( @currenttitleLabel = Gtk::Label.new ),
44       @currentalbumFrame      = Gtk::Frame.new( "Album" ).add( @currentalbumLabel = Gtk::Label.new )
45     ]
46     @statusWdgts.each { |frame| @statusBox.pack_start frame }
47
48
49     @mainWdgts              = [
50       @cntrlBox               = Gtk::HBox.new,
51       @medialistsWin          = Gtk::Notebook.new
52     ]
53     @mainBox.pack1 @cntrlBox, true, false
54     @mainBox.pack2 @medialistsWin, true, false
55
56
57     @toolWdgts              = [
58       @cntrlBtnBox            = Gtk::VButtonBox.new.set_layout_style( Gtk::ButtonBox::CENTER ),
59       @toolChsr               = Gtk::Notebook.new
60     ]
61     @cntrlBox.pack_start @cntrlBtnBox, false
62     @cntrlBox.pack_start @toolChsr
63
64
65     @cntrlbtns      = [
66       @playBtn        = Gtk::ToggleButton.new('_Play', true),
67       @pauseBtn       = Gtk::ToggleButton.new('Pa_use', true),
68       @stopBtn        = Gtk::ToggleButton.new('_Stop', true),
69       @nextBtn        = Gtk::Button.new('_Next'),
70       @prevBtn        = Gtk::Button.new('P_revious'),
71       @rndmBtn        = Gtk::Button.new('Randomi_ze'),
72       @rptBtn         = Gtk::ToggleButton.new('Repeat _All', true),
73       @rpt1Btn        = Gtk::ToggleButton.new('Repeat _One', true)
74     ]
75     @cntrlbtns.each do |button|
76       @cntrlBtnBox.pack_start button
77     end
78
79
80     @toolTabs                 = [
81       [ @extinfoTab             = Gtk::VBox.new,
82         @extinfoTabLbl          = Gtk::Label.new( "Status" ) ],
83       [ @tageditorTab           = Gtk::VBox.new,
84         @tageditorTabLbl        = Gtk::Label.new( "Tag Editor" ) ]
85     ]
86     @toolTabs.each do |content, label|
87       @toolChsr.append_page( Gtk::ScrolledWindow.new.add_with_viewport( content ), label )
88     end
89
90
91     @medialistTextRenderer    = Gtk::CellRendererText.new
92     @medialistColumns         = [ 'id', 'artist', 'title' ]
93
94     @medialists               = [
95       [ @plalistViewLbl         = Gtk::Label.new( "Current Playlist" ),
96         @playlistViewWin        = Gtk::ScrolledWindow.new,
97         @playlistView           = Gtk::TreeView.new,
98         @playlistStore           = Gtk::ListStore.new( String, String, String )
99       ],
100       [ @medialibViewLbl        = Gtk::Label.new( "Medialib" ),
101         @medialibViewWin        = Gtk::ScrolledWindow.new,
102         @medialibView           = Gtk::TreeView.new,
103         @medialibList           = Gtk::ListStore.new( String, String, String )
104       ]
105     ]
106
107     @medialists.each do |label, window, view, store|
108       @medialistColumns.each_with_index do |tag, index|
109         view.append_column Gtk::TreeViewColumn.new( tag, @medialistTextRenderer, :text => index )
110       end
111       @medialistsWin.append_page( window.add( view ), label )
112     end
113
114
115     self.show_all
116
117
118     @server.broadcast_coll_changed do |*foo|
119       p foo
120     end
121     @server.broadcast_config_value_changed do |*foo|
122       p foo
123     end
124     @server.broadcast_mediainfo_reader_status do |*foo|
125       p foo
126     end
127     @server.broadcast_medialib_entry_added do |*foo|
128       p foo
129     end
130     @server.broadcast_medialib_entry_changed do |*foo|
131       p foo
132     end
133     @server.broadcast_playback_current_id.notifier do |id|
134       self.handle_current_id id
135     end
136     @server.broadcast_playback_status.notifier do |playing|
137       self.handle_playback_status playing
138     end
139     @server.broadcast_playback_volume_changed do |*foo|
140       p foo
141     end
142     @server.broadcast_playlist_changed do |*foo|
143       p foo
144     end
145     @server.broadcast_playlist_current_pos.notifier do |pos|
146       self.handle_current_pos pos
147     end
148     @server.broadcast_playlist_loaded do |*foo|
149       p foo
150     end
151     @server.broadcast_quit do |*foo|
152       p foo
153     end
154
155
156     @playBtnClkdHndlr = @playBtn.signal_connect :clicked do
157       self.start_playback
158     end
159     @pauseBtnClkdHndlr = @pauseBtn.signal_connect :clicked do
160       self.pause_playback
161     end
162     @stopBtnClkdHndlr = @stopBtn.signal_connect :clicked do
163       self.stop_playback
164     end
165     @nextBtn.signal_connect :clicked do
166       self.step_in_playlist 1
167     end
168     @prevBtn.signal_connect :clicked do
169       self.step_in_playlist -1
170     end
171     @rndmBtn.signal_connect :clicked do
172       self.randomize_playlist
173     end
174     @rptBtnClkdHndlr = @rptBtn.signal_connect :clicked do
175       self.toggle_repeat_all
176     end
177     @rpt1BtnClkdHndlr = @rpt1Btn.signal_connect :clicked do
178       self.toggle_repeat_one
179     end
180
181
182     @playlistView.signal_connect :row_activated do |view, path, column|
183       @server.playlist_set_next( path.to_str.to_i ).notifier do
184         @server.playback_tickle.notifier do
185           self.start_playback
186           true
187         end
188         true
189       end
190     end
191
192
193     @medialibView.signal_connect :row_activated do |view, path, column|
194       @server.playlist.add_entry( path.to_str.to_i ).notifier do
195         @server.playlist_set_next( path.to_str.to_i ).notifier do
196           @server.playback_tickle.notifier do
197             self.start_playback
198             true
199           end
200           true
201         end
202       end
203     end
204
205
206     self.resync_complete
207
208   end
209
210
211   def xmmspls_to_lststor( playlist, store )
212     @status[:playlist] = playlist
213     playlist.each_with_index do |id, index|
214       current_row = store.append
215       @server.medialib_get_info( id ).notifier do |songinfo|
216         current_row[0] = index.to_s
217         current_row[1] = songinfo[:artist] ? songinfo[:artist].first[1] : ""
218         current_row[2] = songinfo[:title] ? songinfo[:title].first[1] : ""
219         true
220       end
221     end
222     store
223   end
224
225
226   def handle_current_id( id )
227     songpath = Gtk::TreePath.new( @status[:playlist].index id )
228     @playlistView.scroll_to_cell( songpath, nil, true, 0.5, 0.5 )
229     @playlistView.set_cursor( songpath, nil, false )
230     @server.medialib_get_info( id ).notifier do |songinfo|
231       @currentartistLabel.text = ""
232       @currenttitleLabel.text = ""
233       @currentalbumLabel.text = ""
234
235       @extinfoTab.each do |child| @extinfoTab.remove child end
236
237       songinfo[:artist] && songinfo[:artist].each_pair do |src, value|
238         @currentartistLabel.text += @currentartistLabel.text.empty? ? value : "\n#{value}"
239       end
240       songinfo[:title] && songinfo[:title].each_pair do |src, value|
241         @currenttitleLabel.text += @currenttitleLabel.text.empty? ? value : "\n#{value}"
242       end
243       songinfo[:album] && songinfo[:album].each_pair do |src, value|
244         @currentalbumLabel.text += @currentalbumLabel.text.empty? ? value : "\n#{value}"
245       end
246       songinfo.each_key do |key|
247         infos = String.new
248         songinfo[key].each_pair do |src,value|
249           p key, value if src == :server
250           infos.empty? || infos += "\n"
251           infos += "#{value} (#{src})"
252         end
253         @extinfoTab.pack_end( Gtk::Frame.new( key.to_s ).add( Gtk::Label.new( infos ) ) )
254       end
255       @extinfoTab.show_all
256       true
257     end
258     true
259   end
260
261
262
263   def start_playback
264     @server.playback_start.notifier do |res|
265       @playBtn.signal_handler_block( @playBtnClkdHndlr ) do
266         @playBtn.active = true
267       end
268       @pauseBtn.signal_handler_block( @pauseBtnClkdHndlr ) do
269         @pauseBtn.active = false
270       end
271       @stopBtn.signal_handler_block( @stopBtnClkdHndlr ) do
272         @stopBtn.active = false
273       end
274       @statusBar.push( @statusBar.get_context_id( "playback" ), "Started playback" )
275       true
276     end
277   end
278
279
280   def pause_playback
281     @server.playback_pause.notifier do |res|
282       @playBtn.signal_handler_block( @playBtnClkdHndlr ) do
283         @playBtn.active = false
284       end
285       @pauseBtn.signal_handler_block( @pauseBtnClkdHndlr ) do
286         @pauseBtn.active = true
287       end
288       @stopBtn.signal_handler_block( @stopBtnClkdHndlr ) do
289         @stopBtn.active = false
290       end
291       @statusBar.push( @statusBar.get_context_id( "playback" ), "Paused playback" )
292       true
293     end
294   end
295
296
297   def stop_playback
298     @server.playback_stop.notifier do |res|
299       @playBtn.signal_handler_block( @playBtnClkdHndlr ) do
300         @playBtn.active = false
301       end
302       @pauseBtn.signal_handler_block( @pauseBtnClkdHndlr ) do
303         @pauseBtn.active = false
304       end
305       @stopBtn.signal_handler_block( @stopBtnClkdHndlr ) do
306         @stopBtn.active = true
307       end
308       @statusBar.push( @statusBar.get_context_id( "playback" ), "Stopped playback" )
309       true
310     end
311   end
312
313
314   def toggle_playback
315     if @playbackState == 1
316       @server.playback_pause.notifier do |res|
317         @statusBar.push( @statusBar.get_context_id( "playback" ), "Paused playback" )
318         true
319       end
320     elsif @playbackState == 0 || 2
321       @server.playback_start.notifier do |res|
322         @statusBar.push( @statusBar.get_context_id( "playback" ), "Started playback" )
323         true
324       end
325     else
326       warn "Playbackstate unknown"
327       @server.playback_start.notifier do |res|
328         @statusBar.push( @statusBar.get_context_id( "playback" ), "Started playback" )
329         true
330       end
331     end
332   end
333
334
335   def step_in_playlist( offset = 1 )
336     @server.playlist_set_next_rel( offset ).notifier do
337       @server.playback_tickle.notifier do |res|
338         @statusBar.push( @statusBar.get_context_id( "playback" ), "Skipped playback by #{offset} song#{offset.abs >= 1 ? "s" : ''}" )
339         true
340       end
341       true
342     end
343   end
344
345
346   def handle_playback_status( status )
347     @playbackState = status
348     true
349   end
350
351
352   def handle_current_pos( pos )
353     #@server.playlist.entries.notifier do |playlist|
354     #  @server.medialib_get_info( playlist[pos[:position]] ).notifier do |songinfo|
355     #    @nextSongLbl.text = ""
356     #    songinfo.each_pair do |key, info|
357     #      info.each_pair do |src, value|
358     #        @nextSongLbl.text += "[#{src}] #{key} = #{value}\n"
359     #      end
360     #    end
361     #    true
362     #  end
363     #  true
364     #end
365     true
366   end
367
368
369   def handle_repeat_all_state( state )
370     @currentconfig[:"playlist.repeat_all"] = ( state ? "1" : "0" )
371     @rptBtn.signal_handler_block( @rptBtnClkdHndlr ) do
372       @rptBtn.active = state
373     end
374   end
375
376
377   def handle_repeat_one_state( state )
378     @currentconfig[:"playlist.repeat_one"] = ( state ? "1" : "0" )
379     @rpt1Btn.signal_handler_block( @rpt1BtnClkdHndlr ) do
380       @rpt1Btn.active = state
381     end
382   end
383
384
385   def toggle_repeat_all
386     if @currentconfig[:"playlist.repeat_all"] == "1"
387       @server.config_set_value( "playlist.repeat_all", "0" ).notifier do |res|
388         @server.config_get_value( "playlist.repeat_all" ).notifier do |value|
389           self.handle_repeat_all_state( value == "1" ? true : false )
390           true
391         end
392         true
393       end
394     elsif @currentconfig[:"playlist.repeat_all"] == "0"
395       @server.config_set_value( "playlist.repeat_all", "1" ).notifier do |res|
396         @server.config_get_value( "playlist.repeat_all" ).notifier do |value|
397           self.handle_repeat_all_state( value == "1" ? true : false )
398           true
399         end
400         true
401       end
402     else
403       warn "Unknown state: #{@currentconfig[:"playlist.repeat_all"]}"
404     end
405     true
406   end
407
408
409   def toggle_repeat_one
410     if @currentconfig[:"playlist.repeat_one"] == "1"
411       @server.config_set_value( "playlist.repeat_one", "0" ).notifier do |res|
412         @server.config_get_value( "playlist.repeat_one" ).notifier do |value|
413           self.handle_repeat_one_state( value == "1" ? true : false )
414           true
415         end
416         true
417       end
418     elsif @currentconfig[:"playlist.repeat_one"] == "0"
419       @server.config_set_value( "playlist.repeat_one", "1" ).notifier do |res|
420         @server.config_get_value( "playlist.repeat_one" ).notifier do |value|
421           self.handle_repeat_one_state( value == "1" ? true : false )
422           true
423         end
424         true
425       end
426     else
427       warn "Unknown state: #{@currentconfig[:"playlist.repeat_one"]}"
428     end
429     true
430   end
431
432
433   def resync_complete
434     @server.playlist.entries.notifier do |playlist|
435       @playlistView.model = self.xmmspls_to_lststor( playlist, @playlistStore )
436       true
437     end
438
439     @server.playback_current_id.notifier do |id|
440       self.handle_current_id id
441     end
442
443     @server.config_list_values.notifier do |res|
444       @currentconfig = {}
445       res.each_pair do |key, value|
446         @currentconfig[key] = value
447       end
448
449       @rpt1Btn.signal_handler_block( @rpt1BtnClkdHndlr ) do
450         @rpt1Btn.active = if( @currentconfig[:"playlist.repeat_one"] == "1" )
451                             true
452                           else
453                             false
454                           end
455       end
456       @rptBtn.signal_handler_block( @rptBtnClkdHndlr ) do
457         @rptBtn.active = if @currentconfig[:"playlist.repeat_all"] == "1"
458                            true
459                          else
460                            false
461                          end
462       end
463       true
464     end
465
466     @server.coll_list.notifier do |colls|
467       colls.each do |collname|
468         @server.coll_get( collname ).notifier do |coll|
469           @server.coll_query_ids( coll ).notifier do |ids|
470             p collname
471             p ids.join( "', '" )
472             true
473           end
474         true
475         end
476       end
477       true
478     end
479
480     @server.coll_query_ids( Xmms::Collection.universe ).notifier do |medialibids|
481       p medialibids.join( ", " )
482       true
483     end
484     true
485   end
486 end
487
488
489 class Grux::MainWin < Gtk::Window
490   def initialize
491     super
492
493     @mainCont       = Gtk::VBox.new
494     @btnCont        = Gtk::HBox.new
495     @clntCont       = Gtk::Notebook.new
496
497     @cnnctBtn       = Gtk::Button.new "_Connect"
498     @quitBtn        = Gtk::Button.new "_Quit"
499
500     self.title      = "Grux"
501
502     @winDstryHndlr  = self.signal_connect :destroy do
503       Gtk.main_quit
504     end
505
506     @cnnctBtnHndlr  = @cnnctBtn.signal_connect :clicked do
507       begin
508         @clntCont.append_page( Grux::ClientWin.new, Gtk::Label.new( "Client" ) )
509       rescue Xmms::Client::ClientError => ex
510         warn ex
511       end
512     end
513     @quitBtnHndlr   = @quitBtn.signal_connect :clicked do
514       Gtk.main_quit
515     end
516
517     @btnCont.pack_start @cnnctBtn
518     @btnCont.pack_end @quitBtn
519
520     @mainCont.pack_start @btnCont, false
521     @mainCont.pack_end @clntCont
522
523     self.add @mainCont
524     self.show_all
525   end
526 end
527
528
529 gruxWin = Grux::MainWin.new
530 Gtk.main
531
532
533 #:added
534 #:chain
535 #:id
536 #:laststarted
537 #:status
538 #:timesplayed
539 #:url
540