shroom 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ require 'rake/testtask'
7
7
 
8
8
  spec = Gem::Specification.new do |s|
9
9
  s.name = 'shroom'
10
- s.version = '0.0.4'
10
+ s.version = '0.0.5'
11
11
  s.has_rdoc = true
12
12
  s.extra_rdoc_files = ['README', 'LICENSE']
13
13
  s.summary = 'Shroom is a music player and organizer'
@@ -26,6 +26,7 @@ spec = Gem::Specification.new do |s|
26
26
  s.add_dependency('rbrainz', '>= 0.5.0')
27
27
  s.add_dependency('scrobbler', '>= 0.2.3')
28
28
  s.add_dependency('shared-mime-info', '>= 0.1')
29
+ s.requirements << 'rake'
29
30
  s.requirements << 'libgnome2-ruby'
30
31
  s.requirements << 'libsqlite3-ruby'
31
32
  s.requirements << 'libglade2-ruby'
@@ -63,6 +63,76 @@ module Sh
63
63
  @model.clear
64
64
  fill_model
65
65
  end
66
+
67
+ pbtn_reread_tags = MenuItem.new 'Reread tags'
68
+ menu.append pbtn_reread_tags
69
+ pbtn_reread_tags.signal_connect('activate') do |widget|
70
+ song.read_tags!(true)
71
+ $db.save_song song
72
+ @model.clear
73
+ fill_model
74
+ end
75
+
76
+ pbtn_properties = ImageMenuItem.new Stock::PROPERTIES
77
+ menu.append pbtn_properties
78
+ pbtn_properties.signal_connect('activate') do |widget|
79
+ glade = Global::GLADE['dlg_song']
80
+ dlg_song = glade['dlg_song']
81
+ txt_title = glade['txt_title']
82
+ txt_title.text = song.title
83
+
84
+ # Artists combo box
85
+ sto_artists = ListStore.new(String, Artist)
86
+ cmb_artist = glade['cmb_artist']
87
+ sel = 0
88
+ $db.artists.sort_by{|a| (a.name || '')}.each_with_index do |artist, i|
89
+ iter = sto_artists.append
90
+ iter[0] = artist.name
91
+ iter[1] = artist
92
+ sel = i if song.artist && artist.db_id == song.artist.db_id
93
+ end
94
+ cmb_artist.model = sto_artists
95
+ cmb_artist.active = sel
96
+
97
+ # Albums combo box
98
+ sto_albums = ListStore.new(String, Album)
99
+ cmb_album = glade['cmb_album']
100
+ sel = 0
101
+ $db.albums.sort_by{|a| (a.title || '')}.each_with_index do |album, i|
102
+ iter = sto_albums.append
103
+ iter[0] = album.title
104
+ iter[1] = album
105
+ sel = i if song.album && album.db_id == song.album.db_id
106
+ end
107
+ cmb_album.model = sto_albums
108
+ cmb_album.active = sel
109
+
110
+ glade['chk_image'].sensitive = false
111
+ glade['fbtn_image'].sensitive = false
112
+ glade['btn_add_artist'].sensitive = false
113
+ glade['btn_add_album'].sensitive = false
114
+
115
+ dlg_song.signal_connect('delete-event') do
116
+ dlg_song.hide
117
+ end
118
+ btn_ok = glade['btn_ok']
119
+ ok_handle = btn_ok.signal_connect('clicked') do
120
+ song.title = txt_title.text
121
+ song.artist = cmb_artist.active_iter[1]
122
+ song.album = cmb_album.active_iter[1]
123
+ $db.save_song song
124
+ @model.clear
125
+ fill_model
126
+ dlg_song.hide
127
+ end
128
+ btn_cancel = glade['btn_cancel']
129
+ close_handle = btn_cancel.signal_connect('clicked') do
130
+ dlg_song.hide
131
+ end
132
+ dlg_song.run
133
+ btn_ok.signal_handler_disconnect ok_handle
134
+ btn_cancel.signal_handler_disconnect close_handle
135
+ end
66
136
 
67
137
  menu.show_all
68
138
  menu.popup(nil, nil, event.button, event.time)
@@ -104,7 +174,7 @@ module Sh
104
174
 
105
175
  def fill_model
106
176
  artist_node = album_node = track_node = nil
107
- $db.songs.sort_by {|a| a.to_s}.each do |song|
177
+ $db.songs.sort_by {|a| (a.to_s || '')}.each do |song|
108
178
  artist = song.artist
109
179
  if not artist_node or artist_node[0].db_id != artist.db_id
110
180
  artist_node = @model.append nil
@@ -7,7 +7,7 @@ module Sh
7
7
  def CoverArt.get_cover song
8
8
  if $prefs[:cover_art]
9
9
  artist, album = song.artist.name, song.album.title
10
- path = "#{$cover_dir}/#{artist} - #{album}"
10
+ path = "#{$cover_dir}/#{artist.to_md5}_#{album.to_md5}"
11
11
  return path if File.exists? path
12
12
  doc = lastfm("album.getInfo", {:artist => artist, :album => album})
13
13
  img_url = REXML::XPath.first(doc, '//image[@size="extralarge"]').text
@@ -1,5 +1,6 @@
1
1
  require 'fileutils'
2
2
  require 'yaml'
3
+ require 'libglade2'
3
4
 
4
5
  module Sh
5
6
  KEYS = {
@@ -8,8 +9,10 @@ module Sh
8
9
  }
9
10
 
10
11
  class Global
12
+ SUPPORTED_EXTENSIONS = ['.mp3', '.m4a', '.ogg', '.flac', '.wma', '.wav']
13
+ GLADE = {}
14
+
11
15
  def initialize
12
- #$KCODE = 'u'
13
16
  # Won't work on Windows
14
17
  $home = ENV['HOME']
15
18
  $config_dir = "#{$home}/.shroom"
@@ -28,6 +31,10 @@ module Sh
28
31
  }
29
32
 
30
33
  Global.load_prefs
34
+
35
+ add_toplevel_glade('dlg_preferences')
36
+ add_toplevel_glade('dlg_song')
37
+ GLADE.freeze
31
38
  end
32
39
 
33
40
  def Global.load_prefs
@@ -48,6 +55,11 @@ module Sh
48
55
  def Global.locate(file)
49
56
  find_in_load_path("shroom-res/#{file}") || "shroom-res/#{file}"
50
57
  end
58
+
59
+ private
60
+ def add_toplevel_glade name
61
+ GLADE[name] = GladeXML.new(Global.locate('shroom.glade'), name)
62
+ end
51
63
  end
52
64
  end
53
65
 
@@ -0,0 +1,44 @@
1
+ module Sh
2
+ class MMKeys
3
+ def initialize &block
4
+ raise(ArgumentError, "No callback block provided") unless block
5
+ @supported = try_require('rubygems') and try_require('rbus')
6
+
7
+ if supported?
8
+ bus = RBus.session_bus
9
+
10
+ begin
11
+ @mmkeys = bus.get_object('org.gnome.SettingsDaemon', '/org/gnome/SettingsDaemon/MediaKeys')
12
+ @mmkeys.interface!('org.gnome.SettingsDaemon.MediaKeys')
13
+ @mmkeys.GrabMediaPlayerKeys('Shroom', 0)
14
+ rescue
15
+ begin
16
+ @mmkeys = bus.get_object('org.gnome.SettingsDaemon', '/org/gnome/SettingsDaemon/MediaKeys')
17
+ @mmkeys.interface!('org.gnome.SettingsDaemon.MediaKeys')
18
+ @mmkeys.GrabMediaPlayerKeys('Shroom', 0)
19
+ rescue
20
+ # MediaKeys are not supported after all
21
+ @supported = false
22
+ end
23
+ end
24
+ end
25
+
26
+ # Do we still think that MediaKeys are supported?
27
+ if supported? and @mmkeys
28
+ @mmkeys.connect!(:MediaPlayerKeyPressed) do |app, key|
29
+ if app.downcase == 'shroom'
30
+ block.call key
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def supported?
37
+ return @supported
38
+ end
39
+
40
+ def destroy
41
+ @mmkeys.ReleaseMediaPlayerKeys('Shroom')
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,36 @@
1
+ module Sh
2
+ class Playlist
3
+ def initialize dir
4
+ @dir = dir
5
+ @songs = []
6
+ end
7
+
8
+ def Playlist.parse(path)
9
+ list = Playlist.new(File.dirname(path))
10
+ open(path) do |f|
11
+ while line = f.gets
12
+ line.strip!
13
+ unless line[0] == ?# or line.empty?
14
+ ref = File.expand_path(line.gsub('\\', '/'), File.dirname(path))
15
+ if File.exists? ref
16
+ if Sh::Global::SUPPORTED_EXTENSIONS.include? File.extname(ref)
17
+ list << ($db.songs(:path => ref).first || Sh::Song.new(ref).read_tags!)
18
+ end
19
+ else
20
+ puts "Not found: " + ref
21
+ end
22
+ end
23
+ end
24
+ end
25
+ return list
26
+ end
27
+
28
+ def <<(song)
29
+ @songs << song
30
+ end
31
+
32
+ def songs
33
+ return @songs.dup
34
+ end
35
+ end
36
+ end
@@ -34,7 +34,12 @@ module Sh
34
34
  end
35
35
 
36
36
  def lookup!
37
- track = lookup_multiple.first
37
+ begin
38
+ track = lookup_multiple.first
39
+ rescue Exception
40
+ return
41
+ end
42
+
38
43
  if track
39
44
  # Don't distinguish between bands with the same name by adding to the name
40
45
  track.artist.disambiguation = false
@@ -74,7 +79,8 @@ module Sh
74
79
  query = Webservice::Query.new
75
80
  filter = Webservice::TrackFilter.new(:artist => artist.name, :title => title, :puid => puids.first)
76
81
  tracks = query.get_tracks(filter).entities
77
- @matches = tracks || []
82
+ @matches = (tracks || [])
83
+ return @matches
78
84
  end
79
85
 
80
86
  public
@@ -17,20 +17,25 @@ module Sh
17
17
  '.wma' => 'audio/x-ms-wma'
18
18
  }[File.extname path]
19
19
 
20
- case @mime
21
- when 'audio/mpeg'
22
- metadata = TagReader.read_mp3 path
23
- when 'audio/mp4'
24
- metadata = TagReader.read_m4a path
25
- when 'audio/ogg'
26
- metadata = TagReader.read_ogg path
27
- when 'audio/x-flac'
28
- metadata = TagReader.read_flac path
29
- when 'audio/x-ms-wma'
30
- metadata = TagReader.read_wma path
31
- when 'audio/x-wav'
32
- metadata = TagReader.read_wave path
20
+ begin
21
+ case @mime
22
+ when 'audio/mpeg'
23
+ metadata = TagReader.read_mp3 path
24
+ when 'audio/mp4'
25
+ metadata = TagReader.read_m4a path
26
+ when 'audio/ogg'
27
+ metadata = TagReader.read_ogg path
28
+ when 'audio/x-flac'
29
+ metadata = TagReader.read_flac path
30
+ when 'audio/x-ms-wma'
31
+ metadata = TagReader.read_wma path
32
+ when 'audio/x-wav'
33
+ metadata = TagReader.read_wave path
34
+ end
35
+ rescue Exception
36
+ puts "Error parsing tags for " + path
33
37
  end
38
+
34
39
  yield metadata if block
35
40
  return metadata
36
41
  end
@@ -21,6 +21,54 @@ class Object
21
21
  end
22
22
  end
23
23
 
24
+ require 'digest/md5'
25
+
26
+ class String
27
+ def to_md5
28
+ return (Digest::MD5.new << self).to_s
29
+ end
30
+ end
31
+
32
+ class StringMatcher
33
+ def initialize str1, str2
34
+ @str1, @str2 = str1, str2
35
+ end
36
+
37
+ def compare
38
+ pairs1 = word_letter_pairs @str1
39
+ pairs2 = word_letter_pairs @str2
40
+ union = pairs1.size + pairs2.size
41
+ intersection = 0
42
+ pairs1.size.times do
43
+ intersection += 1 if pairs2.delete pairs1.pop
44
+ end
45
+ return (2 * intersection).to_f / union
46
+ end
47
+
48
+ def compare_ignore_case
49
+ compare @str1.upcase, @str2.upcase
50
+ end
51
+
52
+ private
53
+ def letter_pairs str
54
+ n_pairs = str.length - 1
55
+ pairs = []
56
+ n_pairs.times do |i|
57
+ pairs[i] = str.slice(i, 2)
58
+ end
59
+ return pairs
60
+ end
61
+
62
+ def word_letter_pairs str
63
+ pairs = []
64
+ words = str.split(/\s/)
65
+ words.each do |word|
66
+ pairs.concat letter_pairs(word)
67
+ end
68
+ return pairs
69
+ end
70
+ end
71
+
24
72
  module Kelp
25
73
  class ProgressDialog < Gtk::Dialog
26
74
  def initialize(title)
@@ -66,8 +114,8 @@ module Kelp
66
114
  @image = Image.new(pixbuf)
67
115
  vbox.pack_start @image, true, true, 8
68
116
  if pixbuf
69
- self.width_request = pixbuf.width + 16
70
- self.height_request = size[1] + pixbuf.height + 16
117
+ self.width_request = pixbuf.width + 16
118
+ self.height_request = size[1] + pixbuf.height + 16
71
119
  end
72
120
  vbox.show_all
73
121
  signal_connect('response') { destroy }
@@ -1,8 +1,9 @@
1
1
  require 'sh_browse'
2
2
  require 'sh_queue'
3
+ require 'sh_playlist'
3
4
  require 'sh_lyrics'
4
5
  require 'sh_cover_art'
5
- require 'libglade2'
6
+ require 'sh_mmkeys'
6
7
  require 'gtk2'
7
8
  include Gtk
8
9
 
@@ -22,8 +23,6 @@ module Sh
22
23
 
23
24
  Notify.init 'Shroom' if @rnotify
24
25
 
25
- @glade= GladeXML.new(Global.locate('shroom.glade'))
26
-
27
26
  if File.exists? $prefs[:library_dir]
28
27
  cancelled = false
29
28
  dialog = Kelp::ProgressDialog.new("Updating database...")
@@ -31,7 +30,7 @@ module Sh
31
30
  new_songs = []
32
31
  Dir[$prefs[:library_dir]+'/**/*'].each do |path|
33
32
  ext = File.extname path
34
- if ['.mp3', '.m4a', '.ogg', '.flac'].include? ext
33
+ if Sh::Global::SUPPORTED_EXTENSIONS.include? ext
35
34
  new_songs << Song.new(path) unless $db.contains? path
36
35
  end
37
36
  end
@@ -66,7 +65,7 @@ module Sh
66
65
  @window.signal_connect('destroy') do
67
66
  quit
68
67
  end
69
-
68
+
70
69
  @status_icon = StatusIcon.new
71
70
  @status_icon.pixbuf = icon
72
71
  @status_icon.visible = true
@@ -136,34 +135,10 @@ module Sh
136
135
  end if @player
137
136
  end
138
137
  btn_next.signal_connect('clicked') do |btn|
139
- if @queue
140
- playing = @player.playing?
141
- @player.stop
142
- @queue_pos += 1
143
- if @queue_pos < @queue.size
144
- prepare_song
145
- play if playing
146
- else
147
- @queue_pos = 0
148
- prepare_song
149
- @btn_play.active = false
150
- end
151
- end
138
+ next_song
152
139
  end
153
140
  btn_prev.signal_connect('clicked') do |btn|
154
- if @queue
155
- playing = @player.playing?
156
- @player.stop
157
- @queue_pos -= 1
158
- if @queue_pos >= 0
159
- prepare_song
160
- play if playing
161
- else
162
- @queue_pos = 0
163
- prepare_song
164
- @btn_play.active = false
165
- end
166
- end
141
+ prev_song
167
142
  end
168
143
 
169
144
  # Horizontally split area
@@ -232,6 +207,32 @@ module Sh
232
207
  i += 1
233
208
  end
234
209
 
210
+ # Multimedia keys
211
+ MMKeys.new do |key|
212
+ case key
213
+ when 'Stop'
214
+ stop
215
+ when 'Next'
216
+ next_song
217
+ when 'Previous'
218
+ prev_song
219
+ when 'Play'
220
+ if playing?
221
+ pause
222
+ else
223
+ play
224
+ end
225
+ when 'PlayPause'
226
+ if playing?
227
+ pause
228
+ else
229
+ play
230
+ end
231
+ when 'Pause'
232
+ pause
233
+ end
234
+ end
235
+
235
236
  # Show everything
236
237
  @window.show_all
237
238
  end
@@ -240,6 +241,7 @@ module Sh
240
241
  def create_menu
241
242
  menu_items = [
242
243
  ['/_File'],
244
+ ['/File/Import playlist', '<StockItem>', '<control>I', Stock::OPEN, lambda {import_playlist}],
243
245
  ['/File/sep1', '<Separator>', nil, nil, lambda {}],
244
246
  ['/File/Quit', '<StockItem>', '<control>Q', Stock::QUIT, lambda {Gtk.main_quit}],
245
247
  ['/_Edit'],
@@ -254,20 +256,37 @@ module Sh
254
256
  item_factory.get_widget('<main>')
255
257
  end
256
258
 
259
+ def import_playlist
260
+ dialog = Gtk::FileChooserDialog.new("Open File",
261
+ @window,
262
+ Gtk::FileChooser::ACTION_OPEN,
263
+ nil,
264
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
265
+ [Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT])
266
+
267
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
268
+ stop
269
+ self.queue = Sh::Playlist.parse(dialog.filename).songs
270
+ play
271
+ end
272
+ dialog.destroy
273
+ end
274
+
257
275
  def show_preferences
258
- dlg_prefs = @glade.get_widget("dlg_preferences")
276
+ glade = Sh::Global::GLADE['dlg_preferences']
277
+ dlg_prefs = glade['dlg_preferences']
259
278
  dlg_prefs.signal_connect('delete-event') do
260
279
  dlg_prefs.hide
261
280
  end
262
- fbtn_library = @glade.get_widget("fbtn_library")
281
+ fbtn_library = glade['fbtn_library']
263
282
  fbtn_library.current_folder = $prefs[:library_dir]
264
- chk_lastfm = @glade.get_widget("chk_lastfm")
283
+ chk_lastfm = glade['chk_lastfm']
265
284
  chk_lastfm.active = $prefs[:lastfm]
266
- txt_lastfm_user = @glade.get_widget("txt_lastfm_user")
285
+ txt_lastfm_user = glade['txt_lastfm_user']
267
286
  txt_lastfm_user.text = $prefs[:lastfm_user]
268
- txt_lastfm_pass = @glade.get_widget("txt_lastfm_pass")
287
+ txt_lastfm_pass = glade['txt_lastfm_pass']
269
288
  txt_lastfm_pass.text = $prefs[:lastfm_password]
270
- btn_ok = @glade.get_widget("btn_ok")
289
+ btn_ok = glade['btn_ok']
271
290
  ok_handle = btn_ok.signal_connect('clicked') do
272
291
  $prefs[:library_dir] = fbtn_library.filename
273
292
  $prefs[:lastfm] = chk_lastfm.active?
@@ -276,16 +295,13 @@ module Sh
276
295
  Sh::Global.save_prefs
277
296
  dlg_prefs.hide
278
297
  end
279
- btn_close = @glade.get_widget("btn_close")
280
- close_handle = btn_close.signal_connect('clicked') do
298
+ btn_cancel = glade['btn_cancel']
299
+ close_handle = btn_cancel.signal_connect('clicked') do
281
300
  dlg_prefs.hide
282
301
  end
283
- dlg_prefs.show
284
- while dlg_prefs.visible?
285
- Gtk.main_iteration
286
- end
302
+ dlg_prefs.run
287
303
  btn_ok.signal_handler_disconnect ok_handle
288
- btn_close.signal_handler_disconnect close_handle
304
+ btn_cancel.signal_handler_disconnect close_handle
289
305
  end
290
306
 
291
307
  def show_about
@@ -305,18 +321,7 @@ module Sh
305
321
  @player.demolish if @player
306
322
  @player = Sh::Player.new @queue[@queue_pos]
307
323
  @player.on_finished do |player|
308
- if player == @player
309
- @player.stop
310
- @queue_pos += 1
311
- if @queue_pos < @queue.size
312
- prepare_song
313
- play
314
- else
315
- @queue_pos = 0
316
- prepare_song
317
- @btn_play.active = false
318
- end
319
- end
324
+ next_song
320
325
  end
321
326
  on_song_changed
322
327
  end
@@ -346,7 +351,13 @@ module Sh
346
351
  # Cover art
347
352
  if $prefs[:cover_art]
348
353
  @pixbuf = nil
349
- (@pixbuf = Gdk::Pixbuf.new(song.album.image_path)) rescue Exception
354
+ begin
355
+ if File.exists? song.album.image_path
356
+ @pixbuf = Gdk::Pixbuf.new(song.album.image_path)
357
+ end
358
+ rescue
359
+ @pixbuf = nil
360
+ end
350
361
  if @pixbuf
351
362
  @note.pixbuf_icon = @pixbuf.scale(48, 48) if @rnotify
352
363
  @img_cover.pixbuf = @pixbuf.scale(132, 132)
@@ -411,18 +422,64 @@ module Sh
411
422
  end
412
423
 
413
424
  def play
414
- stop
415
425
  if @player
416
426
  @btn_play.active = true
417
427
  @player.play
418
428
  end
419
429
  end
420
430
 
431
+ def pause
432
+ if @player
433
+ @btn_play.active = false
434
+ @player.pause
435
+ end
436
+ end
437
+
438
+ def playing?
439
+ return @player && @player.playing?
440
+ end
441
+
442
+ def paused?
443
+ return @player && @player.paused?
444
+ end
445
+
421
446
  def stop
422
447
  @btn_play.active = false
423
448
  @player.stop if @player
424
449
  end
425
450
 
451
+ def next_song
452
+ if @queue
453
+ playing = @player.playing?
454
+ @player.stop
455
+ @queue_pos += 1
456
+ if @queue_pos < @queue.size
457
+ prepare_song
458
+ play if playing
459
+ else
460
+ @queue_pos = 0
461
+ prepare_song
462
+ @btn_play.active = false
463
+ end
464
+ end
465
+ end
466
+
467
+ def prev_song
468
+ if @queue
469
+ playing = @player.playing?
470
+ @player.stop
471
+ @queue_pos -= 1
472
+ if @queue_pos >= 0
473
+ prepare_song
474
+ play if playing
475
+ else
476
+ @queue_pos = 0
477
+ prepare_song
478
+ @btn_play.active = false
479
+ end
480
+ end
481
+ end
482
+
426
483
  def show
427
484
  Gtk.main
428
485
  end
@@ -87,6 +87,7 @@
87
87
  <packing>
88
88
  <property name="left_attach">1</property>
89
89
  <property name="right_attach">2</property>
90
+ <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
90
91
  </packing>
91
92
  </child>
92
93
  <child>
@@ -101,6 +102,7 @@
101
102
  <property name="right_attach">2</property>
102
103
  <property name="top_attach">1</property>
103
104
  <property name="bottom_attach">2</property>
105
+ <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
104
106
  </packing>
105
107
  </child>
106
108
  <child>
@@ -152,6 +154,20 @@
152
154
  <widget class="GtkHButtonBox" id="dialog-action_area1">
153
155
  <property name="visible">True</property>
154
156
  <property name="layout_style">end</property>
157
+ <child>
158
+ <widget class="GtkButton" id="btn_cancel">
159
+ <property name="label">gtk-cancel</property>
160
+ <property name="visible">True</property>
161
+ <property name="can_focus">True</property>
162
+ <property name="receives_default">True</property>
163
+ <property name="use_stock">True</property>
164
+ </widget>
165
+ <packing>
166
+ <property name="expand">False</property>
167
+ <property name="fill">False</property>
168
+ <property name="position">0</property>
169
+ </packing>
170
+ </child>
155
171
  <child>
156
172
  <widget class="GtkButton" id="btn_ok">
157
173
  <property name="label">gtk-ok</property>
@@ -160,6 +176,235 @@
160
176
  <property name="receives_default">True</property>
161
177
  <property name="use_stock">True</property>
162
178
  </widget>
179
+ <packing>
180
+ <property name="expand">False</property>
181
+ <property name="fill">False</property>
182
+ <property name="position">1</property>
183
+ </packing>
184
+ </child>
185
+ </widget>
186
+ <packing>
187
+ <property name="expand">False</property>
188
+ <property name="pack_type">end</property>
189
+ <property name="position">0</property>
190
+ </packing>
191
+ </child>
192
+ </widget>
193
+ </child>
194
+ </widget>
195
+ <widget class="GtkDialog" id="dlg_song">
196
+ <property name="border_width">5</property>
197
+ <property name="type_hint">normal</property>
198
+ <property name="has_separator">False</property>
199
+ <child internal-child="vbox">
200
+ <widget class="GtkVBox" id="dialog-vbox1">
201
+ <property name="visible">True</property>
202
+ <property name="orientation">vertical</property>
203
+ <property name="spacing">2</property>
204
+ <child>
205
+ <widget class="GtkTable" id="table1">
206
+ <property name="visible">True</property>
207
+ <property name="n_rows">5</property>
208
+ <property name="n_columns">3</property>
209
+ <property name="row_spacing">4</property>
210
+ <child>
211
+ <widget class="GtkLabel" id="lbl_title">
212
+ <property name="visible">True</property>
213
+ <property name="label" translatable="yes">Title:</property>
214
+ </widget>
215
+ <packing>
216
+ <property name="x_options"></property>
217
+ <property name="y_options"></property>
218
+ </packing>
219
+ </child>
220
+ <child>
221
+ <widget class="GtkEntry" id="txt_title">
222
+ <property name="visible">True</property>
223
+ <property name="can_focus">True</property>
224
+ <property name="invisible_char">&#x25CF;</property>
225
+ </widget>
226
+ <packing>
227
+ <property name="left_attach">1</property>
228
+ <property name="right_attach">3</property>
229
+ <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
230
+ <property name="y_options"></property>
231
+ </packing>
232
+ </child>
233
+ <child>
234
+ <widget class="GtkButton" id="btn_add_album">
235
+ <property name="label" translatable="yes">gtk-add</property>
236
+ <property name="visible">True</property>
237
+ <property name="can_focus">True</property>
238
+ <property name="receives_default">True</property>
239
+ <property name="use_stock">True</property>
240
+ </widget>
241
+ <packing>
242
+ <property name="left_attach">2</property>
243
+ <property name="right_attach">3</property>
244
+ <property name="top_attach">2</property>
245
+ <property name="bottom_attach">3</property>
246
+ <property name="x_options">GTK_FILL</property>
247
+ <property name="y_options"></property>
248
+ </packing>
249
+ </child>
250
+ <child>
251
+ <widget class="GtkComboBox" id="cmb_album">
252
+ <property name="visible">True</property>
253
+ <property name="active">0</property>
254
+ <property name="items" translatable="yes">Unknown</property>
255
+ </widget>
256
+ <packing>
257
+ <property name="left_attach">1</property>
258
+ <property name="right_attach">2</property>
259
+ <property name="top_attach">2</property>
260
+ <property name="bottom_attach">3</property>
261
+ <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
262
+ <property name="y_options"></property>
263
+ </packing>
264
+ </child>
265
+ <child>
266
+ <widget class="GtkLabel" id="lbl_album">
267
+ <property name="visible">True</property>
268
+ <property name="label" translatable="yes">Album:</property>
269
+ </widget>
270
+ <packing>
271
+ <property name="top_attach">2</property>
272
+ <property name="bottom_attach">3</property>
273
+ <property name="x_options"></property>
274
+ <property name="y_options"></property>
275
+ </packing>
276
+ </child>
277
+ <child>
278
+ <widget class="GtkLabel" id="lbl_artist">
279
+ <property name="visible">True</property>
280
+ <property name="label" translatable="yes">Artist:</property>
281
+ </widget>
282
+ <packing>
283
+ <property name="top_attach">1</property>
284
+ <property name="bottom_attach">2</property>
285
+ <property name="x_options"></property>
286
+ <property name="y_options"></property>
287
+ </packing>
288
+ </child>
289
+ <child>
290
+ <widget class="GtkComboBox" id="cmb_artist">
291
+ <property name="visible">True</property>
292
+ <property name="active">0</property>
293
+ <property name="items" translatable="yes">Unknown</property>
294
+ </widget>
295
+ <packing>
296
+ <property name="left_attach">1</property>
297
+ <property name="right_attach">2</property>
298
+ <property name="top_attach">1</property>
299
+ <property name="bottom_attach">2</property>
300
+ <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
301
+ <property name="y_options"></property>
302
+ </packing>
303
+ </child>
304
+ <child>
305
+ <widget class="GtkButton" id="btn_add_artist">
306
+ <property name="label" translatable="yes">gtk-add</property>
307
+ <property name="visible">True</property>
308
+ <property name="can_focus">True</property>
309
+ <property name="receives_default">True</property>
310
+ <property name="use_stock">True</property>
311
+ </widget>
312
+ <packing>
313
+ <property name="left_attach">2</property>
314
+ <property name="right_attach">3</property>
315
+ <property name="top_attach">1</property>
316
+ <property name="bottom_attach">2</property>
317
+ <property name="x_options">GTK_FILL</property>
318
+ <property name="y_options"></property>
319
+ </packing>
320
+ </child>
321
+ <child>
322
+ <widget class="GtkLabel" id="lbl_image">
323
+ <property name="visible">True</property>
324
+ <property name="label" translatable="yes">Image:</property>
325
+ </widget>
326
+ <packing>
327
+ <property name="top_attach">3</property>
328
+ <property name="bottom_attach">4</property>
329
+ <property name="x_options"></property>
330
+ <property name="y_options"></property>
331
+ </packing>
332
+ </child>
333
+ <child>
334
+ <widget class="GtkImage" id="img_image">
335
+ <property name="visible">True</property>
336
+ <property name="stock">gtk-missing-image</property>
337
+ </widget>
338
+ <packing>
339
+ <property name="left_attach">1</property>
340
+ <property name="right_attach">2</property>
341
+ <property name="top_attach">3</property>
342
+ <property name="bottom_attach">4</property>
343
+ </packing>
344
+ </child>
345
+ <child>
346
+ <widget class="GtkVBox" id="vbox1">
347
+ <property name="visible">True</property>
348
+ <property name="orientation">vertical</property>
349
+ <child>
350
+ <widget class="GtkCheckButton" id="chk_image">
351
+ <property name="label" translatable="yes">Separate image</property>
352
+ <property name="visible">True</property>
353
+ <property name="can_focus">True</property>
354
+ <property name="receives_default">False</property>
355
+ <property name="draw_indicator">True</property>
356
+ </widget>
357
+ <packing>
358
+ <property name="expand">False</property>
359
+ <property name="fill">False</property>
360
+ <property name="position">0</property>
361
+ </packing>
362
+ </child>
363
+ <child>
364
+ <widget class="GtkFileChooserButton" id="fbtn_image">
365
+ <property name="visible">True</property>
366
+ <property name="title" translatable="yes">Select A Image</property>
367
+ </widget>
368
+ <packing>
369
+ <property name="expand">False</property>
370
+ <property name="fill">False</property>
371
+ <property name="position">1</property>
372
+ </packing>
373
+ </child>
374
+ </widget>
375
+ <packing>
376
+ <property name="left_attach">2</property>
377
+ <property name="right_attach">3</property>
378
+ <property name="top_attach">3</property>
379
+ <property name="bottom_attach">4</property>
380
+ </packing>
381
+ </child>
382
+ <child>
383
+ <placeholder/>
384
+ </child>
385
+ <child>
386
+ <placeholder/>
387
+ </child>
388
+ <child>
389
+ <placeholder/>
390
+ </child>
391
+ </widget>
392
+ <packing>
393
+ <property name="position">1</property>
394
+ </packing>
395
+ </child>
396
+ <child internal-child="action_area">
397
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
398
+ <property name="visible">True</property>
399
+ <property name="layout_style">end</property>
400
+ <child>
401
+ <widget class="GtkButton" id="btn_cancel">
402
+ <property name="label" translatable="yes">gtk-cancel</property>
403
+ <property name="visible">True</property>
404
+ <property name="can_focus">True</property>
405
+ <property name="receives_default">True</property>
406
+ <property name="use_stock">True</property>
407
+ </widget>
163
408
  <packing>
164
409
  <property name="expand">False</property>
165
410
  <property name="fill">False</property>
@@ -167,8 +412,8 @@
167
412
  </packing>
168
413
  </child>
169
414
  <child>
170
- <widget class="GtkButton" id="btn_close">
171
- <property name="label">gtk-close</property>
415
+ <widget class="GtkButton" id="btn_ok">
416
+ <property name="label" translatable="yes">gtk-ok</property>
172
417
  <property name="visible">True</property>
173
418
  <property name="can_focus">True</property>
174
419
  <property name="receives_default">True</property>
@@ -190,4 +435,96 @@
190
435
  </widget>
191
436
  </child>
192
437
  </widget>
438
+ <widget class="GtkDialog" id="dlg_artist">
439
+ <property name="border_width">5</property>
440
+ <property name="type_hint">normal</property>
441
+ <property name="has_separator">False</property>
442
+ <child internal-child="vbox">
443
+ <widget class="GtkVBox" id="dialog-vbox3">
444
+ <property name="visible">True</property>
445
+ <property name="orientation">vertical</property>
446
+ <property name="spacing">2</property>
447
+ <child>
448
+ <widget class="GtkTable" id="table1">
449
+ <property name="visible">True</property>
450
+ <property name="n_rows">2</property>
451
+ <property name="n_columns">3</property>
452
+ <property name="row_spacing">4</property>
453
+ <child>
454
+ <widget class="GtkLabel" id="lbl_name">
455
+ <property name="visible">True</property>
456
+ <property name="label" translatable="yes">Name:</property>
457
+ </widget>
458
+ <packing>
459
+ <property name="x_options"></property>
460
+ <property name="y_options"></property>
461
+ </packing>
462
+ </child>
463
+ <child>
464
+ <widget class="GtkEntry" id="entry1">
465
+ <property name="visible">True</property>
466
+ <property name="can_focus">True</property>
467
+ <property name="invisible_char">&#x25CF;</property>
468
+ </widget>
469
+ <packing>
470
+ <property name="left_attach">1</property>
471
+ <property name="right_attach">3</property>
472
+ <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
473
+ <property name="y_options"></property>
474
+ </packing>
475
+ </child>
476
+ <child>
477
+ <placeholder/>
478
+ </child>
479
+ <child>
480
+ <placeholder/>
481
+ </child>
482
+ <child>
483
+ <placeholder/>
484
+ </child>
485
+ </widget>
486
+ <packing>
487
+ <property name="position">1</property>
488
+ </packing>
489
+ </child>
490
+ <child internal-child="action_area">
491
+ <widget class="GtkHButtonBox" id="dialog-action_area3">
492
+ <property name="visible">True</property>
493
+ <property name="layout_style">end</property>
494
+ <child>
495
+ <widget class="GtkButton" id="button2">
496
+ <property name="label" translatable="yes">button</property>
497
+ <property name="visible">True</property>
498
+ <property name="can_focus">True</property>
499
+ <property name="receives_default">True</property>
500
+ </widget>
501
+ <packing>
502
+ <property name="expand">False</property>
503
+ <property name="fill">False</property>
504
+ <property name="position">0</property>
505
+ </packing>
506
+ </child>
507
+ <child>
508
+ <widget class="GtkButton" id="button1">
509
+ <property name="label" translatable="yes">button</property>
510
+ <property name="visible">True</property>
511
+ <property name="can_focus">True</property>
512
+ <property name="receives_default">True</property>
513
+ </widget>
514
+ <packing>
515
+ <property name="expand">False</property>
516
+ <property name="fill">False</property>
517
+ <property name="position">1</property>
518
+ </packing>
519
+ </child>
520
+ </widget>
521
+ <packing>
522
+ <property name="expand">False</property>
523
+ <property name="pack_type">end</property>
524
+ <property name="position">0</property>
525
+ </packing>
526
+ </child>
527
+ </widget>
528
+ </child>
529
+ </widget>
193
530
  </glade-interface>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shroom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aiden Nibali
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-26 00:00:00 +10:00
12
+ date: 2009-07-31 00:00:00 +10:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -131,6 +131,7 @@ files:
131
131
  - lib/sh_main.rb
132
132
  - lib/sh_queue.rb
133
133
  - lib/sh_album.rb
134
+ - lib/sh_playlist.rb
134
135
  - lib/sh_song.rb
135
136
  - lib/sh_artist.rb
136
137
  - lib/sh_cover_art.rb
@@ -138,6 +139,7 @@ files:
138
139
  - lib/sh_lyrics.rb
139
140
  - lib/sh_database.rb
140
141
  - lib/sh_util.rb
142
+ - lib/sh_mmkeys.rb
141
143
  - lib/shroom-res
142
144
  - lib/shroom-res/icon_16x16.png
143
145
  - lib/shroom-res/icon.svg
@@ -165,6 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
167
  version: "0"
166
168
  version:
167
169
  requirements:
170
+ - rake
168
171
  - libgnome2-ruby
169
172
  - libsqlite3-ruby
170
173
  - libglade2-ruby