shroom 0.0.5 → 0.0.6

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.5'
10
+ s.version = '0.0.6'
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'
@@ -28,6 +28,7 @@ spec = Gem::Specification.new do |s|
28
28
  s.add_dependency('shared-mime-info', '>= 0.1')
29
29
  s.requirements << 'rake'
30
30
  s.requirements << 'libgnome2-ruby'
31
+ s.requirements << 'libgtk-mozembed-ruby'
31
32
  s.requirements << 'libsqlite3-ruby'
32
33
  s.requirements << 'libglade2-ruby'
33
34
  # Requirements for icanhasaudio
@@ -33,7 +33,7 @@ module Sh
33
33
  # Right-click
34
34
  if event.button == 3
35
35
  path = @tree.get_path_at_pos(event.x, event.y).first
36
- data = @tree.model.get_iter(path)[0]
36
+ data = @model.get_iter(path)[0]
37
37
  selection = @tree.selection
38
38
  selected_rows = selection.selected_rows
39
39
  clicked_in_selection = false
@@ -58,80 +58,26 @@ module Sh
58
58
  pbtn_lookup = MenuItem.new 'Lookup metadata automatically'
59
59
  menu.append pbtn_lookup
60
60
  pbtn_lookup.signal_connect('activate') do |widget|
61
- song.lookup!
62
- $db.save_song song
63
- @model.clear
64
- fill_model
61
+ if song.lookup!
62
+ remove_song @model.get_iter(path)
63
+ $db.save_song song
64
+ insert_song song
65
+ end
65
66
  end
66
67
 
67
68
  pbtn_reread_tags = MenuItem.new 'Reread tags'
68
69
  menu.append pbtn_reread_tags
69
70
  pbtn_reread_tags.signal_connect('activate') do |widget|
71
+ remove_song @model.get_iter(path)
70
72
  song.read_tags!(true)
71
73
  $db.save_song song
72
- @model.clear
73
- fill_model
74
+ insert_song song
74
75
  end
75
76
 
76
77
  pbtn_properties = ImageMenuItem.new Stock::PROPERTIES
77
78
  menu.append pbtn_properties
78
79
  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
80
+ show_song_properties_dialog(song)
135
81
  end
136
82
 
137
83
  menu.show_all
@@ -172,6 +118,125 @@ module Sh
172
118
  @scroll.add @tree
173
119
  end
174
120
 
121
+ def show_song_properties_dialog song
122
+ glade = Global::GLADE['dlg_song']
123
+ dlg_song = glade['dlg_song']
124
+ txt_title = glade['txt_title']
125
+ txt_title.text = song.title
126
+
127
+ # Artists combo box
128
+ sto_artists = ListStore.new(String, Artist)
129
+ cmb_artist = glade['cmb_artist']
130
+ sel = 0
131
+ $db.artists.sort_by{|a| (a.name || '')}.each_with_index do |artist, i|
132
+ iter = sto_artists.append
133
+ iter[0] = artist.name
134
+ iter[1] = artist
135
+ sel = i if song.artist && artist.db_id == song.artist.db_id
136
+ end
137
+ cmb_artist.model = sto_artists
138
+ cmb_artist.active = sel
139
+
140
+ # Albums combo box
141
+ sto_albums = ListStore.new(String, Album)
142
+ cmb_album = glade['cmb_album']
143
+ sel = 0
144
+ $db.albums.sort_by{|a| (a.title || '')}.each_with_index do |album, i|
145
+ iter = sto_albums.append
146
+ iter[0] = album.title
147
+ iter[1] = album
148
+ sel = i if song.album && album.db_id == song.album.db_id
149
+ end
150
+ cmb_album.model = sto_albums
151
+ cmb_album.active = sel
152
+
153
+ glade['chk_image'].sensitive = false
154
+ glade['fbtn_image'].sensitive = false
155
+ glade['btn_add_artist'].sensitive = false
156
+ glade['btn_add_album'].sensitive = false
157
+
158
+ dlg_song.signal_connect('delete-event') do
159
+ dlg_song.hide
160
+ end
161
+ btn_ok = glade['btn_ok']
162
+ ok_handle = btn_ok.signal_connect('clicked') do
163
+ song.title = txt_title.text
164
+ song.artist = cmb_artist.active_iter[1]
165
+ song.album = cmb_album.active_iter[1]
166
+ remove_song song
167
+ $db.save_song song
168
+ insert_song song
169
+ dlg_song.hide
170
+ end
171
+ btn_cancel = glade['btn_cancel']
172
+ close_handle = btn_cancel.signal_connect('clicked') do
173
+ dlg_song.hide
174
+ end
175
+ dlg_song.run
176
+ btn_ok.signal_handler_disconnect ok_handle
177
+ btn_cancel.signal_handler_disconnect close_handle
178
+ end
179
+
180
+ def remove_song song
181
+ song_node = nil
182
+ if song.is_a? TreeIter
183
+ song_node = song
184
+ else
185
+ @model.each do |model, path, iter|
186
+ if iter[0] == song
187
+ song_node = iter
188
+ end
189
+ end
190
+ end
191
+
192
+ if song_node
193
+ album_node = song_node.parent
194
+ artist_node = album_node.parent
195
+ @model.remove song_node
196
+ album_node[1].delete song
197
+ @model.remove album_node unless album_node.has_child?
198
+ artist_node[1].delete song
199
+ @model.remove artist_node unless artist_node.has_child?
200
+ end
201
+ end
202
+
203
+ def insert_song song
204
+ artist_node = album_node = prev_song_node = nil
205
+ @model.each do |model, path, iter|
206
+ data = iter[0]
207
+
208
+ if data.is_a? Artist
209
+ artist_node = iter if data.db_id == song.artist.db_id
210
+ elsif artist_node and data.is_a? Album
211
+ album_node = iter if iter.parent == artist_node and data.db_id == song.album.db_id
212
+ end
213
+
214
+ if album_node and iter.parent == album_node and data.is_a? Song
215
+ if data.track_num < song.track_num
216
+ prev_song_node = iter
217
+ end
218
+ end
219
+ end
220
+ # Artist node
221
+ unless artist_node
222
+ artist_node = @model.append nil
223
+ artist_node[0] = song.artist
224
+ artist_node[1] = []
225
+ end
226
+ artist_node[1] << song
227
+ # Album node
228
+ unless album_node
229
+ album_node = @model.append artist_node
230
+ album_node[0] = song.album
231
+ album_node[1] = []
232
+ end
233
+ album_node[1] << song
234
+ # Song node
235
+ song_node = @model.insert_after(album_node, prev_song_node)
236
+ song_node[0] = song
237
+ song_node[1] = [song]
238
+ end
239
+
175
240
  def fill_model
176
241
  artist_node = album_node = track_node = nil
177
242
  $db.songs.sort_by {|a| (a.to_s || '')}.each do |song|
@@ -196,6 +261,8 @@ module Sh
196
261
  track_node = @model.append album_node
197
262
  track_node[0] = song
198
263
  track_node[1] = [song]
264
+
265
+ Kelp.process_events
199
266
  end
200
267
  end
201
268
 
@@ -1,5 +1,5 @@
1
1
  require 'open-uri'
2
- require 'rexml/document'
2
+ require 'hpricot'
3
3
  require 'cgi'
4
4
 
5
5
  module Sh
@@ -15,8 +15,15 @@ module Sh
15
15
  url = "http://lyricwiki.org/api.php?func=getSong&fmt=xml" +
16
16
  "&artist=#{CGI.escape(artist)}" +
17
17
  "&song=#{CGI.escape(title)}"
18
- doc = REXML::Document.new(open(url).read)
19
- REXML::XPath.first(doc, '//lyrics').text
18
+ doc = Hpricot(open(url))
19
+ page_url = (doc/'url').inner_text
20
+ lyrics = nil
21
+ unless page_url.end_with? ';action=edit'
22
+ doc = Hpricot(open(page_url).read.gsub(/<[\s]*br[\s]*\/?>/, "\n"))
23
+ #TODO: Choose most appropriate lyricbox, not just the first
24
+ lyrics = (doc/'.lyricbox').first.inner_text.strip
25
+ end
26
+ return lyrics
20
27
  end
21
28
  end
22
29
  end
@@ -5,21 +5,21 @@ module Sh
5
5
  @supported = try_require('rubygems') and try_require('rbus')
6
6
 
7
7
  if supported?
8
- bus = RBus.session_bus
9
-
10
8
  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
9
+ bus = RBus.session_bus
10
+
15
11
  begin
16
12
  @mmkeys = bus.get_object('org.gnome.SettingsDaemon', '/org/gnome/SettingsDaemon/MediaKeys')
17
13
  @mmkeys.interface!('org.gnome.SettingsDaemon.MediaKeys')
18
14
  @mmkeys.GrabMediaPlayerKeys('Shroom', 0)
19
15
  rescue
20
- # MediaKeys are not supported after all
21
- @supported = false
16
+ @mmkeys = bus.get_object('org.gnome.SettingsDaemon', '/org/gnome/SettingsDaemon/MediaKeys')
17
+ @mmkeys.interface!('org.gnome.SettingsDaemon.MediaKeys')
18
+ @mmkeys.GrabMediaPlayerKeys('Shroom', 0)
22
19
  end
20
+ rescue
21
+ # MediaKeys are not supported after all
22
+ @supported = false
23
23
  end
24
24
  end
25
25
 
@@ -87,7 +87,7 @@ module Sh
87
87
  end
88
88
  end
89
89
 
90
- @@scrobble_queue << Scrobbler::Scrobble.new(
90
+ @@scrobble_queue << {
91
91
  :session_id => auth.session_id,
92
92
  :submission_url => auth.submission_url,
93
93
  :artist => song.artist.name,
@@ -95,7 +95,7 @@ module Sh
95
95
  :album => song.album.title,
96
96
  :time => Time.new,
97
97
  :length => duration,
98
- :track_number => song.track_num)
98
+ :track_number => song.track_num}
99
99
 
100
100
  # No point attempting to scrobble without authentication
101
101
  return if auth.status.strip.upcase != 'OK'
@@ -103,10 +103,15 @@ module Sh
103
103
  Thread.new do
104
104
  failed_scrobbles = []
105
105
  until @@scrobble_queue.empty?
106
- scrobble = @@scrobble_queue.pop
107
- scrobble.submit! rescue Exception
106
+ scrobble = nil
107
+ begin
108
+ scrobble = Scrobbler::Scrobble.new(@@scrobble_queue.pop)
109
+ scrobble.submit!
110
+ rescue
111
+ scrobble = nil
112
+ end
108
113
 
109
- if scrobble.status.strip.upcase == 'OK'
114
+ if scrobble and scrobble.status.strip.upcase == 'OK'
110
115
  puts "Scrobble for '#{scrobble.track}' succeeded"
111
116
  else
112
117
  puts "Warning: Scrobble for '#{scrobble.track}' failed"
@@ -9,8 +9,8 @@ include MusicBrainz
9
9
  module Sh
10
10
  class Song
11
11
  attr_reader :path, :mime, :matches
12
- attr_writer :album, :artist
13
- attr_accessor :title, :mbid, :lyrics, :track_num
12
+ attr_writer :album, :artist, :track_num
13
+ attr_accessor :title, :mbid, :lyrics
14
14
  attr_accessor :db_id
15
15
 
16
16
  def initialize path
@@ -29,6 +29,10 @@ module Sh
29
29
  return @artist
30
30
  end
31
31
 
32
+ def track_num
33
+ return (@track_num || 0).to_i
34
+ end
35
+
32
36
  def duration
33
37
  @duration ||= Sh::TagReader.read(path)[:duration]
34
38
  end
@@ -36,11 +40,6 @@ module Sh
36
40
  def lookup!
37
41
  begin
38
42
  track = lookup_multiple.first
39
- rescue Exception
40
- return
41
- end
42
-
43
- if track
44
43
  # Don't distinguish between bands with the same name by adding to the name
45
44
  track.artist.disambiguation = false
46
45
  # Pull data from response
@@ -57,7 +56,11 @@ module Sh
57
56
  tracks.to_a.each_with_index do |t, i|
58
57
  self.track_num = i + 1 if t.title == track.title and t.duration == track.duration
59
58
  end
59
+ rescue Exception
60
+ return false
60
61
  end
62
+
63
+ return true
61
64
  end
62
65
 
63
66
  private
@@ -69,6 +69,23 @@ class StringMatcher
69
69
  end
70
70
  end
71
71
 
72
+ require 'thread'
73
+ require 'gtkhtml2'
74
+ module Gtk
75
+ class HtmlView
76
+ def set_html content=nil
77
+ @doc_mutex ||= Mutex.new
78
+ doc = self.document ||= HtmlDocument.new
79
+ @doc_mutex.synchronize do
80
+ doc.open_stream 'text/html'
81
+ content ||= (yield || '')
82
+ doc.write_stream content
83
+ doc.close_stream
84
+ end
85
+ end
86
+ end
87
+ end
88
+
72
89
  module Kelp
73
90
  class ProgressDialog < Gtk::Dialog
74
91
  def initialize(title)
@@ -5,6 +5,7 @@ require 'sh_lyrics'
5
5
  require 'sh_cover_art'
6
6
  require 'sh_mmkeys'
7
7
  require 'gtk2'
8
+ require 'gtkhtml2'
8
9
  include Gtk
9
10
 
10
11
  module Sh
@@ -173,17 +174,16 @@ module Sh
173
174
  @img_cover = Image.new
174
175
  event_box = EventBox.new
175
176
  event_box.add @img_cover
176
- event_box.signal_connect("button-press-event") do |w, event|
177
+ event_box.signal_connect('button-press-event') do |w, event|
177
178
  Kelp::ImageDialog.new(@pixbuf, @player.song.album.title).show if @pixbuf and @player
178
179
  end
179
180
  @img_cover.height_request = 150
180
181
  sidebar.pack_start event_box, false, false, 0
181
182
  # Lyrics text view
182
- @txt_lyrics = TextView.new
183
- @txt_lyrics.editable = false
183
+ @html_lyrics = HtmlView.new
184
184
  scr_lyrics = ScrolledWindow.new(nil, nil)
185
185
  scr_lyrics.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
186
- scr_lyrics.add @txt_lyrics
186
+ scr_lyrics.add @html_lyrics
187
187
  # Browse area
188
188
  browse = Sh::Browse.new self
189
189
  queue = Sh::Queue.new self
@@ -384,14 +384,16 @@ module Sh
384
384
  end
385
385
  # Lyrics
386
386
  if $prefs[:lyrics]
387
- @txt_lyrics.buffer.text = "Loading..."
387
+ @html_lyrics.set_html 'Loading...'
388
388
  Thread.new do
389
389
  if not song.lyrics
390
390
  song.lyrics = Sh::Lyrics.get_lyrics(song)
391
391
  $db.save_song song
392
392
  end
393
393
  # Show lyrics unless requests have been shuffled
394
- @txt_lyrics.buffer.text = song.lyrics if @player.song == song
394
+ if @player.song == song
395
+ show_lyrics song
396
+ end
395
397
  end
396
398
  end
397
399
  if @rnotify
@@ -404,6 +406,27 @@ module Sh
404
406
  end
405
407
  end
406
408
 
409
+ def show_lyrics song
410
+ lyrics = song.lyrics || "[Lyrics not found]"
411
+ @html_lyrics.set_html do
412
+ %{
413
+ <h2>#{song.title}</h2>
414
+ <pre style='font-family: sans-serif;'>#{lyrics}</pre>
415
+ <p></p><a href="#reload">Reload lyrics</a>
416
+ }
417
+ end
418
+ @html_lyrics.document.signal_connect('link-clicked') do |doc, loc|
419
+ if loc == '#reload'
420
+ @html_lyrics.set_html 'Loading...'
421
+ Thread.new do
422
+ song.lyrics = Sh::Lyrics.get_lyrics(song)
423
+ $db.save_song song
424
+ show_lyrics song if @player and @player.song == song
425
+ end
426
+ end
427
+ end
428
+ end
429
+
407
430
  public
408
431
  def queue
409
432
  return @queue
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.5
4
+ version: 0.0.6
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-31 00:00:00 +10:00
12
+ date: 2009-08-08 00:00:00 +10:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -169,6 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
169
  requirements:
170
170
  - rake
171
171
  - libgnome2-ruby
172
+ - libgtk-mozembed-ruby
172
173
  - libsqlite3-ruby
173
174
  - libglade2-ruby
174
175
  - ruby-dev