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 +2 -1
- data/lib/sh_browse.rb +130 -63
- data/lib/sh_lyrics.rb +10 -3
- data/lib/sh_mmkeys.rb +8 -8
- data/lib/sh_player.rb +10 -5
- data/lib/sh_song.rb +10 -7
- data/lib/sh_util.rb +17 -0
- data/lib/sh_view.rb +29 -6
- metadata +3 -2
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.
|
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
|
data/lib/sh_browse.rb
CHANGED
@@ -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 = @
|
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
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
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
|
-
|
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
|
|
data/lib/sh_lyrics.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'open-uri'
|
2
|
-
require '
|
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 =
|
19
|
-
|
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
|
data/lib/sh_mmkeys.rb
CHANGED
@@ -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
|
-
|
12
|
-
|
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
|
-
|
21
|
-
@
|
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
|
|
data/lib/sh_player.rb
CHANGED
@@ -87,7 +87,7 @@ module Sh
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
@@scrobble_queue <<
|
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 =
|
107
|
-
|
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"
|
data/lib/sh_song.rb
CHANGED
@@ -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
|
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
|
data/lib/sh_util.rb
CHANGED
@@ -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)
|
data/lib/sh_view.rb
CHANGED
@@ -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(
|
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
|
-
@
|
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 @
|
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
|
-
@
|
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
|
-
|
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.
|
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-
|
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
|