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 +2 -1
- data/lib/sh_browse.rb +71 -1
- data/lib/sh_cover_art.rb +1 -1
- data/lib/sh_global.rb +13 -1
- data/lib/sh_mmkeys.rb +44 -0
- data/lib/sh_playlist.rb +36 -0
- data/lib/sh_song.rb +8 -2
- data/lib/sh_tagreader.rb +18 -13
- data/lib/sh_util.rb +50 -2
- data/lib/sh_view.rb +115 -58
- data/lib/shroom-res/shroom.glade +339 -2
- metadata +5 -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.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'
|
data/lib/sh_browse.rb
CHANGED
@@ -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
|
data/lib/sh_cover_art.rb
CHANGED
@@ -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}
|
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
|
data/lib/sh_global.rb
CHANGED
@@ -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
|
|
data/lib/sh_mmkeys.rb
ADDED
@@ -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
|
data/lib/sh_playlist.rb
ADDED
@@ -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
|
data/lib/sh_song.rb
CHANGED
@@ -34,7 +34,12 @@ module Sh
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def lookup!
|
37
|
-
|
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
|
data/lib/sh_tagreader.rb
CHANGED
@@ -17,20 +17,25 @@ module Sh
|
|
17
17
|
'.wma' => 'audio/x-ms-wma'
|
18
18
|
}[File.extname path]
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
data/lib/sh_util.rb
CHANGED
@@ -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
|
-
|
70
|
-
|
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 }
|
data/lib/sh_view.rb
CHANGED
@@ -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 '
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
281
|
+
fbtn_library = glade['fbtn_library']
|
263
282
|
fbtn_library.current_folder = $prefs[:library_dir]
|
264
|
-
chk_lastfm =
|
283
|
+
chk_lastfm = glade['chk_lastfm']
|
265
284
|
chk_lastfm.active = $prefs[:lastfm]
|
266
|
-
txt_lastfm_user =
|
285
|
+
txt_lastfm_user = glade['txt_lastfm_user']
|
267
286
|
txt_lastfm_user.text = $prefs[:lastfm_user]
|
268
|
-
txt_lastfm_pass =
|
287
|
+
txt_lastfm_pass = glade['txt_lastfm_pass']
|
269
288
|
txt_lastfm_pass.text = $prefs[:lastfm_password]
|
270
|
-
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
|
-
|
280
|
-
close_handle =
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/shroom-res/shroom.glade
CHANGED
@@ -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">●</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="
|
171
|
-
<property name="label">gtk-
|
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">●</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
|
+
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-
|
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
|