lyrics-ebook 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +340 -0
- data/README +46 -0
- data/bin/lyrics-ebook +47 -0
- data/lib/eeepub/LICENSE +20 -0
- data/lib/eeepub/README.md +77 -0
- data/lib/eeepub/Rakefile +49 -0
- data/lib/eeepub/VERSION +1 -0
- data/lib/eeepub/examples/files/bar.html +42 -0
- data/lib/eeepub/examples/files/foo.html +42 -0
- data/lib/eeepub/examples/simple_epub.rb +25 -0
- data/lib/eeepub/lib/eeepub.rb +17 -0
- data/lib/eeepub/lib/eeepub/container_item.rb +108 -0
- data/lib/eeepub/lib/eeepub/easy.rb +100 -0
- data/lib/eeepub/lib/eeepub/maker.rb +127 -0
- data/lib/eeepub/lib/eeepub/ncx.rb +68 -0
- data/lib/eeepub/lib/eeepub/ocf.rb +112 -0
- data/lib/eeepub/lib/eeepub/opf.rb +148 -0
- data/lib/eeepub/spec/eeepub/easy_spec.rb +66 -0
- data/lib/eeepub/spec/eeepub/maker_spec.rb +124 -0
- data/lib/eeepub/spec/eeepub/ncx_spec.rb +80 -0
- data/lib/eeepub/spec/eeepub/ocf_spec.rb +43 -0
- data/lib/eeepub/spec/eeepub/opf_spec.rb +262 -0
- data/lib/eeepub/spec/eeepub_spec.rb +4 -0
- data/lib/eeepub/spec/spec_helper.rb +12 -0
- data/lib/lyrics_ebook.rb +71 -0
- data/lib/lyrics_ebook/cache2html.rb +33 -0
- data/lib/lyrics_ebook/cache_manager.rb +77 -0
- data/lib/lyrics_ebook/lyric.rb +32 -0
- data/lib/lyrics_ebook/lyric_download.rb +50 -0
- data/lib/lyrics_ebook/lyrics2html.rb +106 -0
- data/lib/lyrics_ebook/mini_lyrics_parser.rb +26 -0
- data/lib/lyrics_ebook/mp3_parser.rb +37 -0
- data/lib/wiki_lyrics/amarok/COPYING +340 -0
- data/lib/wiki_lyrics/amarok/README +51 -0
- data/lib/wiki_lyrics/amarok/amarok.rb +355 -0
- data/lib/wiki_lyrics/amarok/pluginadapter.rb +113 -0
- data/lib/wiki_lyrics/amarok/plugins.rb +95 -0
- data/lib/wiki_lyrics/amarok/wikilyrics.rb +578 -0
- data/lib/wiki_lyrics/amarok/wikilyrics.spec +4 -0
- data/lib/wiki_lyrics/amarok/wikipluginadapter.rb +392 -0
- data/lib/wiki_lyrics/cli/optionsparser.rb +228 -0
- data/lib/wiki_lyrics/cli/pluginadapter.rb +56 -0
- data/lib/wiki_lyrics/cli/plugins.rb +79 -0
- data/lib/wiki_lyrics/cli/wikilyrics.rb +178 -0
- data/lib/wiki_lyrics/cli/wikipluginadapter.rb +140 -0
- data/lib/wiki_lyrics/docs/COPYING +340 -0
- data/lib/wiki_lyrics/docs/ChangeLog +293 -0
- data/lib/wiki_lyrics/docs/HOWTO.pdf +0 -0
- data/lib/wiki_lyrics/docs/HOWTO.tex +151 -0
- data/lib/wiki_lyrics/docs/HOWTO.txt +139 -0
- data/lib/wiki_lyrics/docs/README +45 -0
- data/lib/wiki_lyrics/docs/TODO +12 -0
- data/lib/wiki_lyrics/gui/gui-gtk.rb +945 -0
- data/lib/wiki_lyrics/gui/gui-qt3.rb +785 -0
- data/lib/wiki_lyrics/gui/gui-qt4.rb +845 -0
- data/lib/wiki_lyrics/gui/gui-tk.rb +1104 -0
- data/lib/wiki_lyrics/gui/gui.rb +268 -0
- data/lib/wiki_lyrics/gui/test.rb +74 -0
- data/lib/wiki_lyrics/i18n/README +1 -0
- data/lib/wiki_lyrics/i18n/en.rb +181 -0
- data/lib/wiki_lyrics/i18n/es.rb +181 -0
- data/lib/wiki_lyrics/i18n/i18n.rb +126 -0
- data/lib/wiki_lyrics/i18n/sk.rb +174 -0
- data/lib/wiki_lyrics/itrans/COPYRIGHT +31 -0
- data/lib/wiki_lyrics/itrans/itrans +0 -0
- data/lib/wiki_lyrics/itrans/itrans.txt +8 -0
- data/lib/wiki_lyrics/itrans/lyric.txt +23 -0
- data/lib/wiki_lyrics/itrans/udvng.ifm +206 -0
- data/lib/wiki_lyrics/lyrics.rb +567 -0
- data/lib/wiki_lyrics/lyrics_AZLyrics.rb +113 -0
- data/lib/wiki_lyrics/lyrics_DarkLyrics.rb +124 -0
- data/lib/wiki_lyrics/lyrics_Giitaayan.rb +124 -0
- data/lib/wiki_lyrics/lyrics_Jamendo.rb +166 -0
- data/lib/wiki_lyrics/lyrics_LeosLyrics.rb +142 -0
- data/lib/wiki_lyrics/lyrics_LoudSongs.rb +135 -0
- data/lib/wiki_lyrics/lyrics_LyricWiki.rb +329 -0
- data/lib/wiki_lyrics/lyrics_LyricsDownload.rb +118 -0
- data/lib/wiki_lyrics/lyrics_LyricsMania.rb +141 -0
- data/lib/wiki_lyrics/lyrics_Lyriki.rb +287 -0
- data/lib/wiki_lyrics/lyrics_SeekLyrics.rb +108 -0
- data/lib/wiki_lyrics/lyrics_Sing365.rb +103 -0
- data/lib/wiki_lyrics/lyrics_TerraLetras.rb +126 -0
- data/lib/wiki_lyrics/mediawikilyrics.rb +1464 -0
- data/lib/wiki_lyrics/tests/plugin_tests.rb +161 -0
- data/lib/wiki_lyrics/tests/tests.rb +74 -0
- data/lib/wiki_lyrics/utils/formdata.rb +56 -0
- data/lib/wiki_lyrics/utils/htmlentities.rb +291 -0
- data/lib/wiki_lyrics/utils/http.rb +198 -0
- data/lib/wiki_lyrics/utils/itrans.rb +160 -0
- data/lib/wiki_lyrics/utils/kde.rb +88 -0
- data/lib/wiki_lyrics/utils/logger.rb +123 -0
- data/lib/wiki_lyrics/utils/strings.rb +378 -0
- data/lib/wiki_lyrics/utils/xmlhash.rb +111 -0
- data/lib/wiki_lyrics/wikilyrics.kdevelop +152 -0
- data/lib/wiki_lyrics/wikilyrics.kdevses +18 -0
- data/lib/wiki_lyrics/win/gtk_fix.bat +3 -0
- data/lib/wiki_lyrics/win/tk_fix.bat +3 -0
- data/lib/wiki_lyrics/win/wikilyrics.bat +4 -0
- data/lib/wiki_lyrics/win/win_fix.rb +52 -0
- data/templates/art_.erb.xhtml +29 -0
- data/templates/artists.erb.xhtml +19 -0
- data/templates/cover.erb.xhtml +22 -0
- data/test/cache_manager_test.rb +73 -0
- data/test/data/artist name/title name.lyric +6 -0
- data/test/lyric_test.rb +41 -0
- metadata +194 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
# Copyright (C) 2006-2008 by Sergio Pistone
|
2
|
+
# sergio_pistone@yahoo.com.ar
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program; if not, write to the
|
16
|
+
# Free Software Foundation, Inc.,
|
17
|
+
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
18
|
+
|
19
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/amarok" )
|
20
|
+
|
21
|
+
require "cgi"
|
22
|
+
|
23
|
+
module PluginAdapter
|
24
|
+
|
25
|
+
# Hack to make module methods become class methods when the module gets included
|
26
|
+
def PluginAdapter.included( including )
|
27
|
+
if including.is_a?( Class )
|
28
|
+
including.extend( ClassMethods ) # adds class methods
|
29
|
+
else # if including.is_a?( Module )
|
30
|
+
including::ClassMethods.append_class_methods( self )
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Methods under this module will became class methods when the module gets included
|
35
|
+
# Note: don't use def self.<method name> but just <method name>
|
36
|
+
module ClassMethods
|
37
|
+
def ClassMethods.append_class_methods( mod )
|
38
|
+
include mod::ClassMethods
|
39
|
+
end
|
40
|
+
|
41
|
+
def plugin_name()
|
42
|
+
return site_name()
|
43
|
+
end
|
44
|
+
|
45
|
+
def notify( message )
|
46
|
+
Amarok.notify( "<b>" + plugin_name() + "</b>: " + message.gsub( "\n", " " ) )
|
47
|
+
end
|
48
|
+
|
49
|
+
def popup( message )
|
50
|
+
Amarok.popup( "<b>" + plugin_name() + "</b>:<br/>" + message )
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_custom_menu_item( menu_item )
|
54
|
+
Amarok.add_custom_menu_item( plugin_name(), menu_item )
|
55
|
+
end
|
56
|
+
|
57
|
+
def remove_custom_menu_item( menu_item )
|
58
|
+
Amarok.remove_custom_menu_item( plugin_name(), menu_item )
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_custom_checkeable_menu_item( menu_item, checked )
|
62
|
+
Amarok.add_custom_checkeable_menu_item( plugin_name(), menu_item, checked )
|
63
|
+
end
|
64
|
+
|
65
|
+
def remove_custom_checkeable_menu_item( menu_item )
|
66
|
+
Amarok.remove_custom_checkeable_menu_item( plugin_name(), menu_item )
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def plugin_name()
|
71
|
+
return self.class.plugin_name()
|
72
|
+
end
|
73
|
+
|
74
|
+
def notify( message )
|
75
|
+
self.class.notify( message )
|
76
|
+
end
|
77
|
+
|
78
|
+
def popup( message )
|
79
|
+
self.class.popup( message )
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_custom_menu_item( menu_item )
|
83
|
+
self.class.add_custom_menu_item( menu_item )
|
84
|
+
end
|
85
|
+
|
86
|
+
def remove_custom_menu_item( menu_item )
|
87
|
+
self.class.remove_custom_menu_item( menu_item )
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_custom_checkeable_menu_item( menu_item, checked )
|
91
|
+
self.class.add_custom_checkeable_menu_item( menu_item, checked )
|
92
|
+
end
|
93
|
+
|
94
|
+
def remove_custom_checkeable_menu_item( menu_item )
|
95
|
+
self.class.remove_custom_checkeable_menu_item( menu_item )
|
96
|
+
end
|
97
|
+
|
98
|
+
def on_start()
|
99
|
+
end
|
100
|
+
|
101
|
+
def on_quit()
|
102
|
+
end
|
103
|
+
|
104
|
+
def configure()
|
105
|
+
end
|
106
|
+
|
107
|
+
def read_config( config_file )
|
108
|
+
end
|
109
|
+
|
110
|
+
def write_config( config_file )
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Copyright (C) 2007 by Sergio Pistone
|
2
|
+
# sergio_pistone@yahoo.com.ar
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program; if not, write to the
|
16
|
+
# Free Software Foundation, Inc.,
|
17
|
+
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
18
|
+
|
19
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/../mediawikilyrics" )
|
20
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/pluginadapter" )
|
21
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/wikipluginadapter" )
|
22
|
+
|
23
|
+
module Plugins
|
24
|
+
|
25
|
+
@@ALL = []
|
26
|
+
@@WIKI = []
|
27
|
+
|
28
|
+
# Load lyrics plugins:
|
29
|
+
|
30
|
+
plugins_dir = Dir.new( File.expand_path( File.dirname( __FILE__ ) + "/.." ) )
|
31
|
+
plugins_dir.each() do |file_name|
|
32
|
+
file_name = File.expand_path( File.dirname( __FILE__ ) + "/../" + file_name )
|
33
|
+
next if ! File.file?( file_name ) || (md = /\/lyrics_([A-Za-z_0-9]*)\.rb$/.match( file_name )) == nil
|
34
|
+
require( file_name )
|
35
|
+
class_name = md[1]
|
36
|
+
class_obj = eval( class_name )
|
37
|
+
if class_obj.ancestors().include?( MediaWikiLyrics )
|
38
|
+
eval( "class Amarok#{class_name} < #{class_name}\ninclude WikiPluginAdapter\nend" )
|
39
|
+
plugin = eval( "Amarok#{class_name}.new()" )
|
40
|
+
@@WIKI << plugin
|
41
|
+
else
|
42
|
+
eval( "class Amarok#{class_name} < #{class_name}\ninclude PluginAdapter\nend" )
|
43
|
+
plugin = eval( "Amarok#{class_name}.new()" )
|
44
|
+
end
|
45
|
+
@@ALL << plugin
|
46
|
+
end
|
47
|
+
|
48
|
+
@@ALL.sort!() { |x,y| x.site_name <=> y.site_name }
|
49
|
+
@@WIKI.sort!() { |x,y| y.site_name() <=> x.site_name() }
|
50
|
+
@@USED = @@WIKI + (@@ALL - @@WIKI)
|
51
|
+
|
52
|
+
def Plugins.all_plugins()
|
53
|
+
return @@ALL
|
54
|
+
end
|
55
|
+
|
56
|
+
def Plugins.all_names()
|
57
|
+
return @@ALL.collect(){ |plugin| plugin.plugin_name() }
|
58
|
+
end
|
59
|
+
|
60
|
+
def Plugins.used_plugins()
|
61
|
+
return @@USED
|
62
|
+
end
|
63
|
+
|
64
|
+
def Plugins.used_names()
|
65
|
+
return @@USED.collect(){ |plugin| plugin.plugin_name() }
|
66
|
+
end
|
67
|
+
|
68
|
+
def Plugins.used_names=( names )
|
69
|
+
@@USED = []
|
70
|
+
names.uniq().each() do |name|
|
71
|
+
@@ALL.each do |plugin|
|
72
|
+
if plugin.plugin_name() == name
|
73
|
+
@@USED << plugin
|
74
|
+
break
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def Plugins.wiki_plugins()
|
81
|
+
return @@WIKI
|
82
|
+
end
|
83
|
+
|
84
|
+
def Plugins.wiki_names()
|
85
|
+
return @@WIKI.collect(){ |plugin| plugin.plugin_name() }
|
86
|
+
end
|
87
|
+
|
88
|
+
def Plugins.plugin_by_name( name )
|
89
|
+
@@ALL.each() do |plugin|
|
90
|
+
return plugin if plugin.plugin_name() == name
|
91
|
+
end
|
92
|
+
return nil
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,578 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$VERBOSE = nil
|
3
|
+
|
4
|
+
# Copyright (C) 2006-2008 by Sergio Pistone
|
5
|
+
# sergio_pistone@yahoo.com.ar
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program; if not, write to the
|
19
|
+
# Free Software Foundation, Inc.,
|
20
|
+
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
21
|
+
|
22
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/../utils/strings" )
|
23
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/../utils/xmlhash" )
|
24
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/../utils/logger" )
|
25
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/../utils/kde" )
|
26
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/../i18n/i18n" )
|
27
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/../gui/gui" )
|
28
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/../lyrics" )
|
29
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/amarok" )
|
30
|
+
require File.expand_path( File.dirname( __FILE__ ) + "/plugins" )
|
31
|
+
|
32
|
+
require "cgi"
|
33
|
+
require "thread"
|
34
|
+
|
35
|
+
$TOOLKIT_PRIORITY = ["qt3", "qt4", "gtk", "tk"]
|
36
|
+
$LOG_FILEPATH = "#{ENV["HOME"]}/.wikilyrics.log"
|
37
|
+
$LOG_TRUNCATE = 2000
|
38
|
+
|
39
|
+
def debug( message )
|
40
|
+
Amarok.popup( message.to_s() )
|
41
|
+
end
|
42
|
+
|
43
|
+
class Application
|
44
|
+
|
45
|
+
@@MENU_ENTRY_SEARCH_CURRENT = I18n.get( "amarok.application.search.current" )
|
46
|
+
@@MENU_ENTRY_SEARCH_SELECTED = I18n.get( "amarok.application.search.selected" )
|
47
|
+
@@MENU_ENTRY_CLEAR_LYRICS_CACHE = I18n.get( "amarok.application.clearlyricscache" )
|
48
|
+
|
49
|
+
@@SCRIPT_NAME = "Wiki-Lyrics"
|
50
|
+
@@CONFIG_FILE = "wikilyrics.xml"
|
51
|
+
|
52
|
+
def initialize()
|
53
|
+
self.logger = nil
|
54
|
+
self.cleanup_lyrics = true
|
55
|
+
self.single_threaded = false
|
56
|
+
end
|
57
|
+
|
58
|
+
def finalize()
|
59
|
+
@logger.finalize() if @logger
|
60
|
+
end
|
61
|
+
|
62
|
+
def log?()
|
63
|
+
return @logger != nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def logger=( logger )
|
67
|
+
@logger = logger
|
68
|
+
Plugins.all_plugins().each() { |plugin| plugin.logger = @logger }
|
69
|
+
end
|
70
|
+
|
71
|
+
def log( message, new_lines=1 )
|
72
|
+
@logger.log( message, new_lines ) if @logger
|
73
|
+
end
|
74
|
+
|
75
|
+
def cleanup_lyrics?()
|
76
|
+
return @cleanup_lyrics
|
77
|
+
end
|
78
|
+
|
79
|
+
def cleanup_lyrics=( cleanup_lyrics )
|
80
|
+
@cleanup_lyrics = cleanup_lyrics
|
81
|
+
Plugins.all_plugins().each() { |plugin| plugin.cleanup_lyrics = cleanup_lyrics }
|
82
|
+
end
|
83
|
+
|
84
|
+
def single_threaded?()
|
85
|
+
return @single_threaded
|
86
|
+
end
|
87
|
+
|
88
|
+
def single_threaded=( single_threaded )
|
89
|
+
@single_threaded = single_threaded
|
90
|
+
end
|
91
|
+
|
92
|
+
def notify( message )
|
93
|
+
Amarok.notify( "<b>[" + @@SCRIPT_NAME + "]</b> " + message.gsub( "\n", " " ) )
|
94
|
+
end
|
95
|
+
|
96
|
+
def popup( message )
|
97
|
+
Amarok.popup( "<b>[" + @@SCRIPT_NAME + "]</b><br/>" + message )
|
98
|
+
end
|
99
|
+
|
100
|
+
def add_custom_menu_item( menu_item )
|
101
|
+
Amarok.add_custom_menu_item( @@SCRIPT_NAME, menu_item )
|
102
|
+
end
|
103
|
+
|
104
|
+
def remove_custom_menu_item( menu_item )
|
105
|
+
Amarok.remove_custom_menu_item( @@SCRIPT_NAME, menu_item )
|
106
|
+
end
|
107
|
+
|
108
|
+
def read_config()
|
109
|
+
values = {
|
110
|
+
"cleanup_lyrics" => cleanup_lyrics?(),
|
111
|
+
"single_threaded" => single_threaded?(),
|
112
|
+
"write_log" => log?,
|
113
|
+
"used_plugins" => Plugins.used_names()
|
114
|
+
}
|
115
|
+
XMLHash.read( @@CONFIG_FILE, values )
|
116
|
+
self.logger = values["write_log"].to_s() == "true" ? Logger.new( $LOG_FILEPATH, $LOG_TRUNCATE ) : nil
|
117
|
+
self.cleanup_lyrics = values["cleanup_lyrics"].to_s() == "true"
|
118
|
+
self.single_threaded = values["single_threaded"].to_s() == "true"
|
119
|
+
Plugins.used_names = values["used_plugins"]
|
120
|
+
Plugins.all_plugins().each() { |plugin| plugin.read_config( @@CONFIG_FILE ) }
|
121
|
+
end
|
122
|
+
|
123
|
+
def write_config()
|
124
|
+
values = {
|
125
|
+
"cleanup_lyrics" => cleanup_lyrics?(),
|
126
|
+
"single_threaded" => single_threaded?(),
|
127
|
+
"write_log" => log?,
|
128
|
+
"used_plugins" => Plugins.used_names()
|
129
|
+
}
|
130
|
+
XMLHash.write( @@CONFIG_FILE, values )
|
131
|
+
Plugins.all_plugins().each() { |plugin| plugin.write_config( @@CONFIG_FILE ) }
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# EVENT HANDLERS
|
136
|
+
|
137
|
+
def on_start()
|
138
|
+
add_custom_menu_item( @@MENU_ENTRY_SEARCH_CURRENT )
|
139
|
+
add_custom_menu_item( @@MENU_ENTRY_SEARCH_SELECTED )
|
140
|
+
add_custom_menu_item( @@MENU_ENTRY_CLEAR_LYRICS_CACHE )
|
141
|
+
Plugins.all_plugins().each() { |plugin| plugin.on_start() }
|
142
|
+
end
|
143
|
+
|
144
|
+
def on_quit()
|
145
|
+
remove_custom_menu_item( @@MENU_ENTRY_SEARCH_CURRENT )
|
146
|
+
remove_custom_menu_item( @@MENU_ENTRY_SEARCH_SELECTED )
|
147
|
+
remove_custom_menu_item( @@MENU_ENTRY_CLEAR_LYRICS_CACHE )
|
148
|
+
Plugins.all_plugins().each() { |plugin| plugin.on_quit() }
|
149
|
+
end
|
150
|
+
|
151
|
+
def on_configure()
|
152
|
+
|
153
|
+
values = {
|
154
|
+
"cleanup_lyrics" => cleanup_lyrics?(),
|
155
|
+
"single_threaded" => single_threaded?(),
|
156
|
+
"write_log" => log?,
|
157
|
+
"used_plugins" => Plugins.used_names(),
|
158
|
+
"script_name" => @@SCRIPT_NAME,
|
159
|
+
"unused_plugins" => Plugins.all_names() - Plugins.used_names()
|
160
|
+
}
|
161
|
+
if GUI.show_plugins_manager_dialog( values )
|
162
|
+
self.logger = values["write_log"].to_s() == "true" ? Logger.new( $LOG_FILEPATH, $LOG_TRUNCATE ) : nil
|
163
|
+
self.cleanup_lyrics = values["cleanup_lyrics"].to_s() == "true"
|
164
|
+
self.single_threaded = values["single_threaded"].to_s() == "true"
|
165
|
+
Plugins.used_names = values["used_plugins"]
|
166
|
+
end
|
167
|
+
Plugins.all_plugins().each() { |plugin| plugin.configure() }
|
168
|
+
|
169
|
+
write_config()
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
def on_search_current_lyrics()
|
175
|
+
if Amarok.playing?()
|
176
|
+
song_data = Amarok.query_song_data( Amarok.get_current_path() )
|
177
|
+
if GUI.show_search_lyrics_dialog( song_data )
|
178
|
+
on_fetch_lyrics( Lyrics::Request.new(
|
179
|
+
song_data["artist"],
|
180
|
+
song_data["title"],
|
181
|
+
song_data["album"],
|
182
|
+
song_data["year"]
|
183
|
+
) )
|
184
|
+
end
|
185
|
+
else
|
186
|
+
notify( I18n.get( "amarok.application.search.current.nosongplaying" ) )
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def on_search_file_lyrics( file )
|
191
|
+
if (song_data = Amarok.query_song_data( file )).empty?
|
192
|
+
notify( I18n.get( "amarok.application.search.noinfofound" ) )
|
193
|
+
elsif GUI.show_search_lyrics_dialog( song_data )
|
194
|
+
request = Lyrics::Request.new( song_data["artist"], song_data["title"], song_data["album"], song_data["year"] )
|
195
|
+
response, plugin, suggestions = fetch_lyrics( request )
|
196
|
+
if response.lyrics
|
197
|
+
dialog_data = {
|
198
|
+
"artist" => response.artist,
|
199
|
+
"title" => response.title,
|
200
|
+
"lyrics" => response.lyrics,
|
201
|
+
"site_name" => plugin.site_name(),
|
202
|
+
}
|
203
|
+
GUI.show_lyrics_dialog( dialog_data )
|
204
|
+
else
|
205
|
+
notify( I18n.get( "amarok.application.search.nolyricsfound", song_data["title"], song_data["artist"] ) )
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def on_custom_menu_item_selected( menu, item, urls )
|
211
|
+
if menu == @@SCRIPT_NAME
|
212
|
+
if item == @@MENU_ENTRY_SEARCH_CURRENT
|
213
|
+
on_search_current_lyrics()
|
214
|
+
elsif item == @@MENU_ENTRY_SEARCH_SELECTED
|
215
|
+
url = URI.parse( urls[0] )
|
216
|
+
return if url.scheme != "file"
|
217
|
+
on_search_file_lyrics( URI.decode( url.path ) )
|
218
|
+
elsif item == @@MENU_ENTRY_CLEAR_LYRICS_CACHE
|
219
|
+
if GUI.show_confirmation_dialog( I18n.get( "amarok.application.clearlyricscache.confirm" ), @@SCRIPT_NAME )
|
220
|
+
Amarok.query( "DELETE FROM lyrics WHERE url <> ''" )
|
221
|
+
notify( I18n.get( "amarok.application.clearlyricscache.done" ) )
|
222
|
+
end
|
223
|
+
end
|
224
|
+
elsif plugin = Plugins.plugin_by_name( menu )
|
225
|
+
plugin.on_custom_menu_item_selected( menu, item, urls )
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def build_lyrics_data_hash( response, plugin=nil )
|
230
|
+
return {
|
231
|
+
"artist" => response.artist ? response.artist : response.request.artist,
|
232
|
+
"title" => response.title ? response.title : response.request.title,
|
233
|
+
"lyrics" => response.lyrics,
|
234
|
+
"url" => response.url,
|
235
|
+
"add_url" => plugin ? plugin.build_song_add_url( response.request ) : nil,
|
236
|
+
"site_name" => plugin ? plugin.site_name : nil,
|
237
|
+
"site_host" => plugin ? plugin.site_host : nil,
|
238
|
+
}
|
239
|
+
end
|
240
|
+
protected :build_lyrics_data_hash
|
241
|
+
|
242
|
+
def wikis_process_response( response, response_plugin, searched_wiki_plugins )
|
243
|
+
Plugins.wiki_plugins().each() do |plugin|
|
244
|
+
plugin.wiki_process_response( response, response_plugin, searched_wiki_plugins.include?( plugin ) )
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def fetch_lyrics( request )
|
249
|
+
|
250
|
+
used_plugins = Plugins.used_plugins()
|
251
|
+
|
252
|
+
response = nil
|
253
|
+
response_plugin = nil
|
254
|
+
suggestions = []
|
255
|
+
|
256
|
+
if used_plugins.empty?
|
257
|
+
popup( I18n.get( "amarok.application.error.nopluginsselected" ) )
|
258
|
+
response = Lyrics::Response.new( request )
|
259
|
+
else
|
260
|
+
searched_wiki_plugins = []
|
261
|
+
used_plugins.each() do |plugin|
|
262
|
+
begin
|
263
|
+
searched_wiki_plugins << plugin if plugin.is_a?( MediaWikiLyrics )
|
264
|
+
response = plugin.lyrics_direct_search( request )
|
265
|
+
if response.lyrics
|
266
|
+
response_plugin = plugin
|
267
|
+
break
|
268
|
+
end
|
269
|
+
response, suggs = plugin.lyrics_from_suggestions( request )
|
270
|
+
if suggs.size > 0
|
271
|
+
suggestions << plugin.plugin_name()
|
272
|
+
suggestions.concat( suggs )
|
273
|
+
end
|
274
|
+
if response.lyrics
|
275
|
+
response_plugin = plugin
|
276
|
+
break
|
277
|
+
end
|
278
|
+
rescue TimeoutError
|
279
|
+
notify( I18n.get( "amarok.application.search.plugintimeout", plugin.plugin_name(), plugin.site_host() ) )
|
280
|
+
end
|
281
|
+
end
|
282
|
+
wikis_process_response( response, response_plugin, searched_wiki_plugins )
|
283
|
+
end
|
284
|
+
|
285
|
+
return response, response_plugin, suggestions
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
def on_fetch_lyrics( request )
|
290
|
+
|
291
|
+
# NOTE: we must check that the current song doesn't change while we're fetching
|
292
|
+
# the lyrics, otherwise Amarok will associate the lyrics with the wrong song
|
293
|
+
prev_artist = Strings.normalize!( Amarok.get_current_artist().to_s() )
|
294
|
+
prev_title = Strings.normalize!( Amarok.get_current_title().to_s() )
|
295
|
+
|
296
|
+
response, plugin, suggestions = fetch_lyrics( request )
|
297
|
+
lyrics_data = build_lyrics_data_hash( response, plugin )
|
298
|
+
|
299
|
+
return if Strings.normalize!( Amarok.get_current_artist().to_s() ) != prev_artist ||
|
300
|
+
Strings.normalize!( Amarok.get_current_title().to_s() ) != prev_title
|
301
|
+
|
302
|
+
if lyrics_data["lyrics"]
|
303
|
+
Amarok.show_lyrics(
|
304
|
+
lyrics_data["artist"],
|
305
|
+
lyrics_data["title"],
|
306
|
+
lyrics_data["lyrics"],
|
307
|
+
lyrics_data["site_name"],
|
308
|
+
lyrics_data["site_host"],
|
309
|
+
lyrics_data["url"],
|
310
|
+
lyrics_data["add_url"]
|
311
|
+
)
|
312
|
+
elsif suggestions.size > 0
|
313
|
+
Amarok.show_suggestions(
|
314
|
+
lyrics_data["artist"],
|
315
|
+
lyrics_data["title"],
|
316
|
+
suggestions,
|
317
|
+
lyrics_data["add_url"]
|
318
|
+
)
|
319
|
+
else
|
320
|
+
Amarok.show_not_found(
|
321
|
+
lyrics_data["artist"],
|
322
|
+
lyrics_data["title"],
|
323
|
+
lyrics_data["add_url"]
|
324
|
+
)
|
325
|
+
end
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
def fetch_lyrics_from_url( request, url )
|
330
|
+
|
331
|
+
used_plugins = Plugins.used_plugins()
|
332
|
+
|
333
|
+
response = nil
|
334
|
+
response_plugin = nil
|
335
|
+
|
336
|
+
if used_plugins.empty?
|
337
|
+
popup( I18n.get( "amarok.application.error.nopluginsselected" ) )
|
338
|
+
response = Lyrics::Response.new( request )
|
339
|
+
else
|
340
|
+
searched_wiki_plugins = []
|
341
|
+
used_plugins.each() do |plugin|
|
342
|
+
begin
|
343
|
+
next if ! plugin.known_url?( url )
|
344
|
+
searched_wiki_plugins << plugin if plugin.is_a?( MediaWikiLyrics )
|
345
|
+
response = plugin.lyrics_from_url( request, url )
|
346
|
+
if response.lyrics
|
347
|
+
response_plugin = plugin
|
348
|
+
break
|
349
|
+
end
|
350
|
+
rescue TimeoutError
|
351
|
+
notify( I18n.get( "amarok.application.search.plugintimeout", plugin.plugin_name(), plugin.site_host() ) )
|
352
|
+
end
|
353
|
+
end
|
354
|
+
wikis_process_response( response, response_plugin, searched_wiki_plugins )
|
355
|
+
end
|
356
|
+
|
357
|
+
return response, response_plugin
|
358
|
+
end
|
359
|
+
|
360
|
+
def on_fetch_lyrics_from_url( request, url )
|
361
|
+
|
362
|
+
# NOTE: we must check that the current song doesn't change while we're fetching
|
363
|
+
# the lyrics, otherwise Amarok will associate the lyrics with the wrong song
|
364
|
+
prev_artist = Strings.normalize!( Amarok.get_current_artist().to_s() )
|
365
|
+
prev_title = Strings.normalize!( Amarok.get_current_title().to_s() )
|
366
|
+
|
367
|
+
response, plugin = fetch_lyrics_from_url( request, url )
|
368
|
+
lyrics_data = build_lyrics_data_hash( response, plugin )
|
369
|
+
|
370
|
+
return if Strings.normalize!( Amarok.get_current_artist().to_s() ) != prev_artist ||
|
371
|
+
Strings.normalize!( Amarok.get_current_title().to_s() ) != prev_title
|
372
|
+
|
373
|
+
if lyrics_data["lyrics"]
|
374
|
+
Amarok.show_lyrics(
|
375
|
+
lyrics_data["artist"],
|
376
|
+
lyrics_data["title"],
|
377
|
+
lyrics_data["lyrics"],
|
378
|
+
lyrics_data["site_name"],
|
379
|
+
lyrics_data["site_host"],
|
380
|
+
lyrics_data["url"],
|
381
|
+
lyrics_data["add_url"]
|
382
|
+
)
|
383
|
+
else
|
384
|
+
Amarok.show_not_found(
|
385
|
+
lyrics_data["artist"],
|
386
|
+
lyrics_data["title"],
|
387
|
+
lyrics_data["add_url"]
|
388
|
+
)
|
389
|
+
end
|
390
|
+
|
391
|
+
end
|
392
|
+
|
393
|
+
def exec()
|
394
|
+
|
395
|
+
@threads = []
|
396
|
+
@messages = []
|
397
|
+
|
398
|
+
read_config()
|
399
|
+
|
400
|
+
begin
|
401
|
+
|
402
|
+
on_start()
|
403
|
+
|
404
|
+
single_threaded = self.single_threaded?
|
405
|
+
|
406
|
+
GUI.set_run_out_of_process( ! single_threaded )
|
407
|
+
|
408
|
+
exec_messages_loop( single_threaded )
|
409
|
+
|
410
|
+
rescue Errno::ECONNREFUSED => e
|
411
|
+
popup( I18n.get( "amarok.application.error.connectionrefused" ) )
|
412
|
+
popup( e.backtrace().join( "<br/>" ) )
|
413
|
+
|
414
|
+
rescue SocketError, TimeoutError => e
|
415
|
+
popup( I18n.get( "amarok.application.error.connectiondown" ) )
|
416
|
+
|
417
|
+
rescue Exception => e # unexpected error
|
418
|
+
if ! e.is_a?( SystemExit ) || e.status != 0
|
419
|
+
$stderr << e.message() << "\n"
|
420
|
+
$stderr << e.backtrace().join( "\n" )
|
421
|
+
log( e.message() )
|
422
|
+
log( e.backtrace().join( "\n" ), 0 )
|
423
|
+
exit( 1 )
|
424
|
+
end
|
425
|
+
|
426
|
+
ensure
|
427
|
+
write_config()
|
428
|
+
on_quit()
|
429
|
+
|
430
|
+
end
|
431
|
+
|
432
|
+
end
|
433
|
+
|
434
|
+
def exec_messages_loop( single_threaded )
|
435
|
+
|
436
|
+
loop do
|
437
|
+
message = get_message()
|
438
|
+
break if message == nil
|
439
|
+
command = /[A-Za-z]*/.match( message ).to_s()
|
440
|
+
case command
|
441
|
+
when "configure"
|
442
|
+
on_configure()
|
443
|
+
when "fetchLyrics"
|
444
|
+
artist = Amarok.get_current_artist()
|
445
|
+
title = Amarok.get_current_title()
|
446
|
+
if artist && title
|
447
|
+
if single_threaded
|
448
|
+
on_fetch_lyrics( Lyrics::Request.new(
|
449
|
+
Strings.cleanup_artist( artist, title ),
|
450
|
+
Strings.cleanup_title( title ),
|
451
|
+
Amarok.get_current_album(),
|
452
|
+
Amarok.get_current_year()
|
453
|
+
) )
|
454
|
+
else
|
455
|
+
@threads << Thread.new() do
|
456
|
+
on_fetch_lyrics( Lyrics::Request.new(
|
457
|
+
Strings.cleanup_artist( artist, title ),
|
458
|
+
Strings.cleanup_title( title ),
|
459
|
+
Amarok.get_current_album(),
|
460
|
+
Amarok.get_current_year()
|
461
|
+
) )
|
462
|
+
end
|
463
|
+
end
|
464
|
+
else
|
465
|
+
Amarok.show_error()
|
466
|
+
end
|
467
|
+
when "fetchLyricsByUrl"
|
468
|
+
args = message.split()
|
469
|
+
if args.length < 2
|
470
|
+
Amarok.show_error()
|
471
|
+
else
|
472
|
+
artist = Amarok.get_current_artist().to_s()
|
473
|
+
title = Amarok.get_current_title().to_s()
|
474
|
+
if single_threaded
|
475
|
+
on_fetch_lyrics_from_url(
|
476
|
+
Lyrics::Request.new(
|
477
|
+
Strings.cleanup_artist( artist, title ),
|
478
|
+
Strings.cleanup_title( title ),
|
479
|
+
Amarok.get_current_album(),
|
480
|
+
Amarok.get_current_year()
|
481
|
+
),
|
482
|
+
args[1]
|
483
|
+
)
|
484
|
+
else
|
485
|
+
@threads << Thread.new() do
|
486
|
+
on_fetch_lyrics_from_url(
|
487
|
+
Lyrics::Request.new(
|
488
|
+
Strings.cleanup_artist( artist, title ),
|
489
|
+
Strings.cleanup_title( title ),
|
490
|
+
Amarok.get_current_album(),
|
491
|
+
Amarok.get_current_year()
|
492
|
+
),
|
493
|
+
args[1]
|
494
|
+
)
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
when "customMenuClicked"
|
499
|
+
urls_start = message.index( /([a-zA-Z]+:\/\/[^: ]+){1,}/ )
|
500
|
+
next if urls_start == nil # unexpected message
|
501
|
+
menu_id = message.slice( "customMenuClicked:".size+1..urls_start-2 )
|
502
|
+
menu, item = Amarok.get_custom_menu_item( menu_id )
|
503
|
+
if menu && item
|
504
|
+
urls = message.slice( urls_start..-1 ).split( " " )
|
505
|
+
if single_threaded
|
506
|
+
on_custom_menu_item_selected( menu, item, urls )
|
507
|
+
else
|
508
|
+
@threads << Thread.new() { on_custom_menu_item_selected( menu, item, urls ) }
|
509
|
+
end
|
510
|
+
end
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
protected :exec_messages_loop
|
515
|
+
|
516
|
+
def get_message()
|
517
|
+
begin
|
518
|
+
loop do
|
519
|
+
begin
|
520
|
+
messages = $stdin.read_nonblock( 2048 ) # we read all there is to read
|
521
|
+
messages.chomp().split( "\n" ).each() { |message| store_message( message ) }
|
522
|
+
rescue Errno::EAGAIN # there was nothing to read
|
523
|
+
rescue EOFError
|
524
|
+
return nil # stdin was closed
|
525
|
+
end
|
526
|
+
if @messages.empty?
|
527
|
+
message = $stdin.gets() # wait for something to be written to stdin
|
528
|
+
store_message( message )
|
529
|
+
begin
|
530
|
+
messages = $stdin.read_nonblock( 2048 ) # if something else was written, we read it too
|
531
|
+
messages.chomp().split( "\n" ).each() { |message| store_message( message ) }
|
532
|
+
rescue Errno::EAGAIN # there was nothing to read
|
533
|
+
rescue EOFError
|
534
|
+
return nil # stdin was closed
|
535
|
+
end
|
536
|
+
end
|
537
|
+
return @messages.shift() if ! @messages.empty?
|
538
|
+
end
|
539
|
+
rescue SignalException => e
|
540
|
+
return nil
|
541
|
+
end
|
542
|
+
|
543
|
+
end
|
544
|
+
protected :get_message
|
545
|
+
|
546
|
+
def store_message( message )
|
547
|
+
command = /[A-Za-z]*/.match( message ).to_s()
|
548
|
+
if command == "configure"
|
549
|
+
# prioritize configure messages:
|
550
|
+
@messages.insert( 0, "configure" ) if @messages[0] != "configure"
|
551
|
+
elsif ["fetchLyrics", "fetchLyricsByUrl", "customMenuClicked"].include?( command )
|
552
|
+
# we queue only two messages to try to stay in synch with Amarok current track
|
553
|
+
@messages[@messages.size < 2 ? @messages.size : 1 ] = message
|
554
|
+
end
|
555
|
+
end
|
556
|
+
protected :store_message
|
557
|
+
|
558
|
+
end
|
559
|
+
|
560
|
+
if $0 == __FILE__
|
561
|
+
|
562
|
+
if GUI.set_toolkit_priority( $TOOLKIT_PRIORITY ) == nil
|
563
|
+
Amarok.popup( I18n.get( "amarok.application.error.notoolkit" ) )
|
564
|
+
exit( 0 )
|
565
|
+
end
|
566
|
+
|
567
|
+
proxy_url, excluded_urls, reverse = KDE.get_proxy_settings()
|
568
|
+
HTTP.set_proxy_settings( proxy_url, excluded_urls, reverse )
|
569
|
+
|
570
|
+
app = Application.new()
|
571
|
+
|
572
|
+
begin
|
573
|
+
app.exec()
|
574
|
+
ensure
|
575
|
+
app.finalize()
|
576
|
+
end
|
577
|
+
|
578
|
+
end
|