shroom 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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