shroom 0.0.9 → 0.0.10

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.
@@ -4,8 +4,7 @@ module Sh
4
4
  class_eval do
5
5
  names.each do |name|
6
6
  define_method(name) do |*args|
7
- case args.size
8
- when 0
7
+ if args.size == 0
9
8
  instance_variable_get("@#{name}")
10
9
  else
11
10
  instance_variable_set("@#{name}", *args)
@@ -18,27 +17,52 @@ module Sh
18
17
 
19
18
  class Plugin
20
19
  @registered_plugins = {}
20
+ @active_plugins = {}
21
+
22
+ def self.init
23
+ begin
24
+ @plugin_prefs = YAML.load_file(Sh::Global::PATHS[:plugin_prefs_file])
25
+ rescue
26
+ @plugin_prefs = {}
27
+ end
28
+ end
29
+
21
30
  class << self
22
- attr_reader :registered_plugins
31
+ attr_reader :registered_plugins, :active_plugins
23
32
  private :new
24
33
  end
25
34
 
26
35
  def self.define(id_name, &block)
27
36
  p = new
37
+ p.id_name id_name
28
38
  p.instance_eval(&block)
29
- Plugin.registered_plugins[id_name] = p
39
+ p.init @plugin_prefs[id_name] if p.respond_to? :init
40
+ registered_plugins[id_name] = p
41
+ active_plugins[id_name] = p
30
42
  end
31
43
 
32
44
  def self.broadcast(method_name, *args)
33
- registered_plugins.each_value do |plugin|
45
+ active_plugins.each_value do |plugin|
34
46
  if plugin.respond_to? method_name
35
47
  Thread.new {plugin.send method_name, *args}
36
48
  end
37
49
  end
38
50
  end
39
51
 
52
+ def self.save_prefs
53
+ prefs = {}
54
+ registered_plugins.each do |id, plugin|
55
+ if plugin.respond_to? :preferences
56
+ prefs[id] = plugin.preferences
57
+ end
58
+ end
59
+ open(Sh::Global::PATHS[:plugin_prefs_file], "w") do |f|
60
+ f.write prefs.to_yaml
61
+ end
62
+ end
63
+
40
64
  extend PluginSugar
41
65
 
42
- def_field :name, :description, :author, :version
66
+ def_field :name, :description, :author, :version, :id_name
43
67
  end
44
- end
68
+ end
@@ -3,9 +3,10 @@ require 'sh_tagreader'
3
3
  require 'sh_album'
4
4
  require 'sh_artist'
5
5
  require 'cgi'
6
- require 'earworm'
7
- require 'rbrainz'
8
- include MusicBrainz
6
+ try_require 'earworm'
7
+ if try_require 'rbrainz'
8
+ include MusicBrainz
9
+ end
9
10
 
10
11
  module Sh
11
12
  class Song
@@ -21,12 +22,10 @@ module Sh
21
22
  end
22
23
 
23
24
  def album
24
- #@album = $db.albums(:id => @album.db_id).first if @album and @album.db_id
25
25
  return @album
26
26
  end
27
27
 
28
28
  def artist
29
- #@artist = $db.artists(:id => @artist.db_id).first if @artist and @artist.db_id
30
29
  return @artist
31
30
  end
32
31
 
@@ -35,7 +34,7 @@ module Sh
35
34
  end
36
35
 
37
36
  def duration
38
- @duration ||= Sh::TagReader.read(path)[:duration]
37
+ return (@duration ||= Sh::TagReader.read(path)[:duration])
39
38
  end
40
39
 
41
40
  def lookup!
@@ -55,10 +54,13 @@ module Sh
55
54
  album.mbid = rel.id.to_mbid.uuid
56
55
  # Determine track number
57
56
  query = Webservice::Query.new
58
- filter = Webservice::TrackFilter.new(:artistid => artist.mbid, :releaseid => album.mbid)
57
+ filter = Webservice::TrackFilter.new(:artistid => artist.mbid,
58
+ :releaseid => album.mbid)
59
59
  tracks = query.get_tracks(filter).entities
60
60
  tracks.to_a.each_with_index do |t, i|
61
- self.track_num = i + 1 if t.title == track.title and t.duration == track.duration
61
+ if t.title == track.title and t.duration == track.duration
62
+ self.track_num = i + 1
63
+ end
62
64
  end
63
65
  rescue Exception
64
66
  return false
@@ -73,7 +75,7 @@ module Sh
73
75
  ew = Earworm::Client.new(Sh::KEYS[:music_dns])
74
76
  begin
75
77
  info = ew.identify(:file => path)
76
- rescue
78
+ rescue Exception
77
79
  printf "Couldn't generate fingerprint for %s\n> %s\n\n", path, $!
78
80
  return
79
81
  end
@@ -84,7 +86,8 @@ module Sh
84
86
  return if not title or not artist.name
85
87
  # Get more information from MusicBrainz
86
88
  query = Webservice::Query.new
87
- filter = Webservice::TrackFilter.new(:artist => artist.name, :title => title, :puid => puids.first)
89
+ filter = Webservice::TrackFilter.new(:artist => artist.name,
90
+ :title => title, :puid => puids.first)
88
91
  tracks = query.get_tracks(filter).entities
89
92
  @matches = (tracks || [])
90
93
  return @matches
@@ -1,22 +1,42 @@
1
+ require 'sh_util'
2
+ require 'sh_log'
3
+
1
4
  module Sh
2
5
  class TagReader
3
- def TagReader.read path, &block
6
+ def self.read path, &block
7
+ # Ensure that the path is absolute
4
8
  @path = File.expand_path path
5
- metadata = {}
6
9
 
10
+ # Use shared-mime-info to determine MIME types if
11
+ # it is available.
7
12
  if try_require 'shared-mime-info'
8
- type = MIME.check(path)
13
+ type = MIME.check(@path)
9
14
  @mime = type.to_s if type.media == 'audio'
15
+ else
16
+ # Attempt to use the `file` command
17
+ begin
18
+ type = `file --mime-type -b #{@path}`
19
+ @mime = type if type[0..5] == 'audio/'
20
+ rescue Exception
21
+ @mime = nil
22
+ end
23
+
24
+ # As a fallback, guess MIME type from file extension.
25
+ if not @mime or @mime.empty?
26
+ @mime = {
27
+ '.mp3' => 'audio/mpeg',
28
+ '.m4a' => 'audio/mp4',
29
+ '.flac' => 'audio/x-flac',
30
+ '.ogg' => 'audio/ogg',
31
+ '.wav' => 'audio/x-wav',
32
+ '.wma' => 'audio/x-ms-wma'
33
+ }[File.extname @path]
34
+ end
10
35
  end
11
- @mime ||= {
12
- '.mp3' => 'audio/mpeg',
13
- '.m4a' => 'audio/mp4',
14
- '.flac' => 'audio/x-flac',
15
- '.ogg' => 'audio/ogg',
16
- '.wav' => 'audio/x-wav',
17
- '.wma' => 'audio/x-ms-wma'
18
- }[File.extname path]
19
-
36
+
37
+ metadata = {}
38
+
39
+ # Choose appropriate method for MIME type
20
40
  begin
21
41
  case @mime
22
42
  when 'audio/mpeg'
@@ -33,14 +53,16 @@ module Sh
33
53
  metadata = TagReader.read_wave path
34
54
  end
35
55
  rescue Exception
36
- puts "Error parsing tags for " + path
56
+ Log.warning "Couldn't parse tags for " + path
37
57
  end
38
-
58
+
59
+ # Report on our metadata findings
39
60
  yield metadata if block
40
61
  return metadata
41
62
  end
42
-
43
- def TagReader.read_mp3 path, &block
63
+
64
+ # Read metadata from MP3 file
65
+ def self.read_mp3 path, &block
44
66
  metadata = {}
45
67
  if try_require 'mp3info'
46
68
  Mp3Info.open path do |mp3|
@@ -53,13 +75,14 @@ module Sh
53
75
  metadata[:duration] = mp3.length
54
76
  end
55
77
  else
56
- puts 'Please install the "mp3info" gem in order to read MP3 info'
78
+ Log.info 'Please install the "mp3info" gem in order to read MP3 info'
57
79
  end
58
80
  yield metadata if block
59
81
  return metadata
60
82
  end
61
-
62
- def TagReader.read_m4a path, &block
83
+
84
+ # Read metadata from M4A file
85
+ def self.read_m4a path, &block
63
86
  metadata = {}
64
87
  if try_require 'mp4info'
65
88
  mp4 = MP4Info.open path
@@ -70,13 +93,14 @@ module Sh
70
93
  metadata[:track_num] = mp4.TRKN.first.to_i
71
94
  metadata[:duration] = mp4.SECS
72
95
  else
73
- puts 'Please install the "mp4info" gem in order to read M4A info'
96
+ Log.info 'Please install the "mp4info" gem in order to read M4A info'
74
97
  end
75
98
  yield metadata if block
76
99
  return metadata
77
100
  end
78
-
79
- def TagReader.read_ogg path, &block
101
+
102
+ # Read metadata from OGG Vorbis file
103
+ def self.read_ogg path, &block
80
104
  metadata = {}
81
105
  if try_require 'ogginfo'
82
106
  OggInfo.open path do |ogg|
@@ -89,13 +113,14 @@ module Sh
89
113
  metadata[:duration] = ogg.length
90
114
  end rescue Exception
91
115
  else
92
- puts 'Please install the "ogginfo" gem in order to read OGG info'
116
+ Log.info 'Please install the "ogginfo" gem in order to read OGG info'
93
117
  end
94
118
  yield metadata if block
95
119
  return metadata
96
120
  end
97
-
98
- def TagReader.read_flac path, &block
121
+
122
+ # Read metadata from FLAC file
123
+ def self.read_flac path, &block
99
124
  metadata = {}
100
125
  if try_require 'flacinfo'
101
126
  flac = FlacInfo.new(path)
@@ -118,13 +143,14 @@ module Sh
118
143
  end
119
144
  end
120
145
  else
121
- puts 'Please install the "flacinfo" gem in order to read FLAC info'
146
+ Log.info 'Please install the "flacinfo" gem in order to read FLAC info'
122
147
  end
123
148
  yield metadata if block
124
149
  return metadata
125
150
  end
126
-
127
- def TagReader.read_wma path, &block
151
+
152
+ # Read metadata from WMA file
153
+ def self.read_wma path, &block
128
154
  metadata = {}
129
155
  if try_require 'wmainfo'
130
156
  wma = WmaInfo.new(path)
@@ -146,19 +172,20 @@ module Sh
146
172
  end
147
173
  metadata[:duration] = wma.info["playtime_seconds"]
148
174
  else
149
- puts 'Please install the "wmainfo" gem in order to read WMA info'
175
+ Log.info 'Please install the "wmainfo" gem in order to read WMA info'
150
176
  end
151
177
  yield metadata if block
152
178
  return metadata
153
179
  end
154
-
155
- def TagReader.read_wave path, &block
180
+
181
+ # Read metadata from Wave file
182
+ def self.read_wave path, &block
156
183
  metadata = {}
157
184
  if try_require 'waveinfo'
158
185
  wave = WaveInfo.new path
159
186
  metadata[:duration] = wave.duration
160
187
  else
161
- puts 'Please install the "waveinfo" gem in order to read WAV info'
188
+ Log.info 'Please install the "waveinfo" gem in order to read WAV info'
162
189
  end
163
190
  yield metadata if block
164
191
  return metadata
@@ -21,82 +21,47 @@ class Object
21
21
  end
22
22
  end
23
23
 
24
- require 'digest/md5'
25
- class String
26
- def to_md5
27
- return (Digest::MD5.new << self).to_s
28
- end
29
-
30
- def to_u
31
- begin
32
- raise "Binary data!" if is_binary_data?
33
- utf8 = isutf8
34
- if utf8
35
- utf8 = utf8.to_s
36
- else
37
- utf8 = unpack('C*').pack('U*')
38
- end
39
- return utf8
40
- rescue Exception
41
- return nil
24
+ require 'open-uri'
25
+ module Rest
26
+ class Get
27
+ def initialize(url, params={})
28
+ @url = url.dup
29
+ @query = ''
30
+ @query = build_query params
42
31
  end
43
- end
44
- end
45
-
46
- class File
47
- def empty? path
48
- return size? path
49
- end
50
- end
51
-
52
- class StringMatcher
53
- def initialize str1, str2
54
- @str1, @str2 = str1, str2
55
- end
56
-
57
- def self.compare(str1, str2)
58
- return StringMatcher.new(str1, str2).compare
59
- end
60
-
61
- def self.compare_ignore_case(str1, str2)
62
- return StringMatcher.new(str1, str2).compare_ignore_case
63
- end
64
32
 
65
- def compare
66
- return 1 if @str1 == @str2
67
- pairs1 = word_letter_pairs @str1
68
- pairs2 = word_letter_pairs @str2
69
- union = pairs1.size + pairs2.size
70
- intersection = 0
71
- pairs1.size.times do
72
- intersection += 1 if pairs2.delete pairs1.pop
33
+ def [](params={})
34
+ query = build_query params
35
+ open(@url + query).read
73
36
  end
74
- return (2 * intersection).to_f / union
75
- end
76
37
 
77
- def compare_ignore_case
78
- @str1 = @str1.upcase
79
- @str2 = @str2.upcase
80
- return compare
38
+ private
39
+ def build_query(params)
40
+ query = @query
41
+ params.each do |key, value|
42
+ query << (query.empty? ? '?' : '&')
43
+ query << CGI.escape(key.to_s)
44
+ query << '='
45
+ query << CGI.escape(value.to_s)
46
+ end
47
+ return query
48
+ end
81
49
  end
50
+ end
82
51
 
83
- private
84
- def letter_pairs str
85
- n_pairs = str.length - 1
86
- pairs = []
87
- n_pairs.times do |i|
88
- pairs[i] = str.slice(i, 2)
89
- end
90
- return pairs
52
+ require 'digest/md5'
53
+ class String
54
+ def to_md5
55
+ return (Digest::MD5.new << self).to_s
91
56
  end
92
57
 
93
- def word_letter_pairs str
94
- pairs = []
95
- words = str.split(/\s/)
96
- words.each do |word|
97
- pairs.concat letter_pairs(word)
58
+ def to_u
59
+ if is_binary_data?
60
+ return isutf8 ? self : nil
61
+ else
62
+ utf8 = isutf8
63
+ return utf8 ? utf8.to_s : unpack('C*').pack('U*')
98
64
  end
99
- return pairs
100
65
  end
101
66
  end
102
67
 
@@ -175,7 +140,7 @@ module Kelp
175
140
  end
176
141
  end
177
142
 
178
- def Kelp.process_events
143
+ def self.process_events
179
144
  Gtk.main_iteration while Gtk.events_pending?
180
145
  end
181
146
  end
@@ -1,23 +1,32 @@
1
1
  require 'sh_browse'
2
+ require 'sh_cover_browse'
2
3
  require 'sh_queue'
3
4
  require 'sh_playlist'
4
5
  require 'sh_lyrics'
5
6
  require 'sh_cover_art'
6
7
  require 'sh_mmkeys'
8
+ require 'sh_actions'
7
9
  require 'gtk2'
8
10
  require 'gtkhtml2'
9
11
  include Gtk
10
12
 
11
13
  module Sh
12
14
  class View
13
- TAB_QUEUE, TAB_BROWSE, TAB_LYRICS, NUM_TABS = *(0..3).to_a
15
+ TAB_QUEUE, TAB_BROWSE, TAB_LYRICS, TAB_COVER_BROWSE, TAB_PLAYLISTS, NUM_TABS = (0..5).to_a
14
16
  TAB_NAMES = {
15
17
  TAB_QUEUE => 'Queue',
16
18
  TAB_BROWSE => 'Browse',
17
- TAB_LYRICS => 'Lyrics'
19
+ TAB_LYRICS => 'Lyrics',
20
+ TAB_COVER_BROWSE => 'Cover Browse',
21
+ TAB_PLAYLISTS => 'Playlists'
18
22
  }
23
+
24
+ @@instance = nil
19
25
 
20
26
  def initialize
27
+ Sh::Log.warning 'Instance of Browse already created!' if @@instance
28
+ @@instance = self
29
+
21
30
  # Initialize GTK
22
31
  Gtk.init
23
32
 
@@ -52,16 +61,17 @@ module Sh
52
61
  new_songs.each do |song|
53
62
  # Show path to song in the dialog
54
63
  dialog.message = song.path
55
- puts "Adding: #{song.path}"
64
+
56
65
  begin
57
66
  # Read metadata from song tags
58
67
  song.read_tags!
59
68
  # Save song to the database
60
69
  $db.save_song song
61
- # Increment progress bar
70
+ Sh::Log.debug "Added #{song.path} to database"
62
71
  rescue
63
- puts "Couldn't add song. Reason: #{$!}"
72
+ Sh::Log.info "Failed to add ${song.path} to database", $!
64
73
  end
74
+ # Increment progress bar
65
75
  dialog.fraction += inc
66
76
  # Make sure that the GUI is updated
67
77
  Kelp.process_events
@@ -80,6 +90,8 @@ module Sh
80
90
  # Clean up
81
91
  new_songs = dialog = nil
82
92
  end
93
+
94
+ Sh::Log.debug 'Synchronized library dir with database'
83
95
 
84
96
  # Load small 16x16 pixel Shroom logo
85
97
  icon = Gdk::Pixbuf.new Global.locate('icon_16x16.png')
@@ -218,9 +230,14 @@ module Sh
218
230
  scr_lyrics = ScrolledWindow.new(nil, nil)
219
231
  scr_lyrics.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
220
232
  scr_lyrics.add @html_lyrics
221
- # Browse area
222
- browse = Sh::Browse.new self
233
+ box_lyrics = VBox.new false, 0
234
+ box_lyrics.add scr_lyrics
235
+ @btn_refresh_lyrics = Button.new Stock::REFRESH
236
+ box_lyrics.pack_start @btn_refresh_lyrics, false, false
223
237
  queue = Sh::Queue.new self
238
+ browse = Sh::Browse.new self
239
+ cover_browse = Sh::CoverBrowse.new self
240
+ playlists = Sh::Playlists.new self
224
241
  lst_tabs.selection.signal_connect('changed') do |selection|
225
242
  frm_content.remove frm_content.child if frm_content.child
226
243
  case selection.selected.path.indices[0]
@@ -230,11 +247,15 @@ module Sh
230
247
  when TAB_BROWSE
231
248
  frm_content.child = browse.widget
232
249
  when TAB_LYRICS
233
- frm_content.child = scr_lyrics
250
+ frm_content.child = box_lyrics
251
+ when TAB_COVER_BROWSE
252
+ frm_content.child = cover_browse.widget
253
+ when TAB_PLAYLISTS
254
+ frm_content.child = playlists.widget
234
255
  end
235
256
  frm_content.show_all
236
257
  end
237
- # Select 'Browse' tab
258
+ # Select 'Browse' tab on startup
238
259
  i = 0
239
260
  lst_tabs.model.each do |row|
240
261
  lst_tabs.selection.select_path row[1] if i == TAB_BROWSE
@@ -250,13 +271,7 @@ module Sh
250
271
  next_song
251
272
  when 'Previous'
252
273
  prev_song
253
- when 'Play'
254
- if playing?
255
- pause
256
- else
257
- play
258
- end
259
- when 'PlayPause'
274
+ when 'Play', 'PlayPause'
260
275
  if playing?
261
276
  pause
262
277
  else
@@ -266,10 +281,16 @@ module Sh
266
281
  pause
267
282
  end
268
283
  end
284
+
285
+ ShroomActions.init
269
286
 
270
287
  # Show everything
271
288
  @window.show_all
272
289
  end
290
+
291
+ def self.instance
292
+ return @@instance
293
+ end
273
294
 
274
295
  private
275
296
  def create_menu
@@ -333,6 +354,21 @@ module Sh
333
354
  else
334
355
  sto_plugins = lst_plugins.model = ListStore.new(Object, Plugin)
335
356
  ren_enabled = CellRendererToggle.new
357
+ ren_enabled.activatable = true
358
+ ren_enabled.signal_connect('toggled') do |w, path|
359
+ iter = sto_plugins.get_iter(path)
360
+ iter[0] = !iter[0]
361
+ plugin = iter[1]
362
+ if iter[0]
363
+ unless Plugin.active_plugins[plugin.id_name]
364
+ Plugin.active_plugins[plugin.id_name] = plugin
365
+ end
366
+ else
367
+ if Plugin.active_plugins[plugin.id_name]
368
+ Plugin.active_plugins.delete plugin.id_name
369
+ end
370
+ end
371
+ end
336
372
  col_enabled = TreeViewColumn.new('Enabled',
337
373
  ren_enabled,
338
374
  'active' => 0)
@@ -351,19 +387,26 @@ module Sh
351
387
  lbl_name.markup = "<b>#{plugin.name}</b>"
352
388
  lbl_version.markup = "<i>#{plugin.version}</i>"
353
389
  txt_description.buffer.text = plugin.description
354
- btn_preferences.sensitive = plugin.respond_to? :show_preferences
390
+ btn_preferences.sensitive = plugin.respond_to? :edit_preferences
391
+
392
+ btn_preferences.signal_handler_disconnect @prefs_hnd_id if @prefs_hnd_id
393
+ @prefs_hnd_id = btn_preferences.signal_connect('clicked') do |*args|
394
+ plugin.edit_preferences
395
+ end
355
396
  end
356
397
  end
357
398
  end
358
399
 
359
400
  Plugin.registered_plugins.each do |name, plugin|
360
401
  iter = sto_plugins.append
361
- iter[0] = true
402
+ iter[0] = Plugin.active_plugins[plugin.id_name] == plugin
362
403
  iter[1] = plugin
363
404
  lst_plugins.selection.select_iter iter if lst_plugins.selection.count_selected_rows == 0
364
405
  end
365
406
 
366
407
  dlg_plugins.run
408
+
409
+ Plugin.save_prefs
367
410
  end
368
411
 
369
412
  def show_preferences
@@ -374,18 +417,9 @@ module Sh
374
417
  end
375
418
  fbtn_library = glade['fbtn_library']
376
419
  fbtn_library.current_folder = Global.prefs[:library_dir]
377
- chk_lastfm = glade['chk_lastfm']
378
- chk_lastfm.active = Global.prefs[:lastfm]
379
- txt_lastfm_user = glade['txt_lastfm_user']
380
- txt_lastfm_user.text = Global.prefs[:lastfm_user]
381
- txt_lastfm_pass = glade['txt_lastfm_pass']
382
- txt_lastfm_pass.text = Global.prefs[:lastfm_password]
383
420
  btn_ok = glade['btn_ok']
384
421
  ok_handle = btn_ok.signal_connect('clicked') do
385
422
  Global.prefs[:library_dir] = fbtn_library.filename
386
- Global.prefs[:lastfm] = chk_lastfm.active?
387
- Global.prefs[:lastfm_user] = txt_lastfm_user.text
388
- Global.prefs[:lastfm_password] = txt_lastfm_pass.text
389
423
  Sh::Global.save_prefs
390
424
  dlg_prefs.hide
391
425
  end
@@ -428,6 +462,7 @@ module Sh
428
462
  def on_song_changed
429
463
  if @player
430
464
  song = @player.song
465
+ Sh::Log.debug "Playback started for \"#{song.title}\""
431
466
  @note.close if @note
432
467
  @note = nil
433
468
  if @rnotify
@@ -436,42 +471,8 @@ module Sh
436
471
  @note = Notify::Notification.new(song.title || 'Unknown track', msg, nil, @status_icon)
437
472
  end
438
473
  # Cover art
439
- if Global.prefs[:cover_art]
440
- @pixbuf = nil
441
- begin
442
- image_path = song.album.image_path
443
- @pixbuf = Gdk::Pixbuf.new(image_path) unless File.empty? image_path
444
- rescue
445
- @pixbuf = nil
446
- end
447
-
448
- if @pixbuf
449
- @note.pixbuf_icon = @pixbuf.scale(48, 48) if @rnotify
450
- @img_cover.pixbuf = @pixbuf.scale(128, 128)
451
- else
452
- @img_cover.pixbuf = Gdk::Pixbuf.new(Global.locate("cover_unavailable.png")).scale(132, 132)
453
- Thread.new do
454
- song.album.image_path = Sh::CoverArt.get_cover(song)
455
- if song.album.image_path
456
- $db.save_song song
457
- # Show cover unless requests have been shuffled
458
- if song == @player.song
459
- @pixbuf = nil
460
- (@pixbuf = Gdk::Pixbuf.new(song.album.image_path)) rescue Exception
461
- if @pixbuf
462
- if @rnotify
463
- @note.close
464
- @note.pixbuf_icon = @pixbuf.scale(48, 48)
465
- @note.show
466
- end
467
- @img_cover.pixbuf = @pixbuf.scale(128, 128)
468
- plasmarize_background @pixbuf
469
- end
470
- end
471
- end
472
- end
473
- end
474
- end
474
+ @pixbuf = nil
475
+ Thread.new {update_image song} if Global.prefs[:cover_art]
475
476
  # Lyrics
476
477
  if Global.prefs[:lyrics]
477
478
  @html_lyrics.set_html 'Loading...'
@@ -504,26 +505,54 @@ module Sh
504
505
  %{
505
506
  <h2>#{song.title}</h2>
506
507
  <pre style='font-family: sans-serif;'>#{lyrics}</pre>
507
- <p></p><a href="#reload">Reload lyrics</a>
508
508
  }
509
509
  end
510
- doc = @html_lyrics.document
511
- if @html_signal_id and doc.signal_handler_is_connected?(@html_signal_id)
512
- doc.signal_handler_disconnect(@html_signal_id)
510
+ if @html_signal_id and @btn_refresh_lyrics.signal_handler_is_connected?(@html_signal_id)
511
+ @btn_refresh_lyrics.signal_handler_disconnect(@html_signal_id)
513
512
  end
514
- @html_signal_id = doc.signal_connect('link-clicked') do |doc, loc|
515
- if loc == '#reload'
516
- @html_lyrics.set_html 'Loading...'
517
- Thread.new do
518
- song.lyrics = Sh::Lyrics.get_lyrics(song)
513
+ @html_signal_id = @btn_refresh_lyrics.signal_connect('pressed') do |*args|
514
+ @html_lyrics.set_html 'Loading...'
515
+ Thread.new do
516
+ song.lyrics = Sh::Lyrics.get_lyrics(song)
517
+ $db.save_song song
518
+ show_lyrics song if @player and @player.song == song
519
+ end
520
+ end
521
+ end
522
+
523
+ def update_image song
524
+ image_path = song.album.image_path
525
+ # Use image path in database if valid
526
+ if image_path and File.size? image_path
527
+ (@pixbuf = Gdk::Pixbuf.new(image_path)) rescue Exception
528
+ end
529
+ # Lookup cover art on Internet if necessary
530
+ unless @pixbuf
531
+ @img_cover.pixbuf = Gdk::Pixbuf.new(Global.locate("cover_unavailable.png")).scale(132, 132)
532
+ image_path = Sh::CoverArt.get_cover(song)
533
+ if image_path
534
+ begin
535
+ @pixbuf = Gdk::Pixbuf.new(image_path)
536
+ song.album.image_path = image_path
519
537
  $db.save_song song
520
- show_lyrics song if @player and @player.song == song
538
+ rescue
521
539
  end
522
540
  end
523
541
  end
542
+ # Show cover image unless requests have been shuffled
543
+ if @pixbuf and song == @player.song
544
+ if @rnotify
545
+ @note.close
546
+ @note.pixbuf_icon = @pixbuf.scale(48, 48)
547
+ @note.show
548
+ end
549
+ @img_cover.pixbuf = @pixbuf.scale(128, 128)
550
+ plasmarize_background @pixbuf
551
+ end
524
552
  end
525
553
 
526
554
  def plasmarize_background image_path
555
+ return unless image_path
527
556
  begin
528
557
  pixbuf = nil
529
558
  if image_path.is_a? Gdk::Pixbuf
@@ -545,14 +574,14 @@ module Sh
545
574
  if color != @plasma_color
546
575
  @plasma_color = color.dup
547
576
  require 'sh_plasma'
548
- pixmap = Plasma.new(600, 600, 3).generate_pixmap(color)
577
+ pixmap = Plasma.new(512, 512, 3).generate_pixmap(color)
549
578
  style = @window.style.copy
550
579
  style.set_bg_pixmap(Gtk::STATE_NORMAL, pixmap)
551
580
  @window.set_style style
552
581
  end
553
582
  end
554
583
  rescue
555
- puts "Plasma fail: #{$!}"
584
+ Sh::Log.info "Plasma generation failed", $!
556
585
  end
557
586
  end
558
587
 
@@ -632,6 +661,7 @@ module Sh
632
661
  end
633
662
 
634
663
  def show
664
+ Sh::Log.debug 'Starting GTK main loop'
635
665
  Gtk.main
636
666
  end
637
667
 
@@ -639,4 +669,4 @@ module Sh
639
669
  Gtk.main_quit
640
670
  end
641
671
  end
642
- end
672
+ end