lyricli 0.0.1
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/Gemfile +3 -0
- data/Gemfile.lock +63 -0
- data/README.md +69 -0
- data/bin/lrc +52 -0
- data/config/defaults.json +5 -0
- data/lib/lyricli/configuration.rb +90 -0
- data/lib/lyricli/exceptions/disable_source_error.rb +8 -0
- data/lib/lyricli/exceptions/enable_source_error.rb +8 -0
- data/lib/lyricli/exceptions/invalid_lyrics_error.rb +8 -0
- data/lib/lyricli/exceptions/lyrics_not_found_error.rb +8 -0
- data/lib/lyricli/exceptions/reset_source_error.rb +8 -0
- data/lib/lyricli/exceptions/source_configuration_error.rb +9 -0
- data/lib/lyricli/exceptions/start_source_error.rb +7 -0
- data/lib/lyricli/exceptions/unknown_source_error.rb +8 -0
- data/lib/lyricli/exceptions.rb +7 -0
- data/lib/lyricli/lyricli.rb +55 -0
- data/lib/lyricli/lyrics_engine.rb +41 -0
- data/lib/lyricli/source_manager.rb +136 -0
- data/lib/lyricli/sources/arguments.rb +39 -0
- data/lib/lyricli/sources/current_song.scpt +0 -0
- data/lib/lyricli/sources/itunes.rb +41 -0
- data/lib/lyricli/sources/rdio.rb +73 -0
- data/lib/lyricli/sources.rb +6 -0
- data/lib/lyricli/util.rb +36 -0
- data/lib/lyricli.rb +96 -0
- data/spec/bin/lrc_spec.rb +0 -0
- data/spec/lib/lyricli/configuration_spec.rb +0 -0
- data/spec/lib/lyricli/exceptions_spec.rb +0 -0
- data/spec/lib/lyricli/lyricli_spec.rb +0 -0
- data/spec/lib/lyricli/lyrics_engine_spec.rb +0 -0
- data/spec/lib/lyricli/source_manager_spec.rb +25 -0
- data/spec/lib/lyricli/sources/arguments.rb +0 -0
- data/spec/lib/lyricli/sources/itunes.rb +0 -0
- data/spec/lib/lyricli/sources/rdio.rb +0 -0
- data/spec/lib/lyricli/sources_spec.rb +0 -0
- data/spec/lib/lyricli/util_spec.rb +42 -0
- data/spec/lib/lyricli_spec.rb +0 -0
- metadata +212 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
lyricli (0.0.1)
|
|
5
|
+
launchy (~> 2.1.2)
|
|
6
|
+
multi_json (~> 1.3.6)
|
|
7
|
+
nokogiri (~> 1.5.5)
|
|
8
|
+
rdio (~> 0.1.0)
|
|
9
|
+
|
|
10
|
+
GEM
|
|
11
|
+
remote: http://rubygems.org/
|
|
12
|
+
specs:
|
|
13
|
+
addressable (2.3.2)
|
|
14
|
+
archive-tar-minitar (0.5.2)
|
|
15
|
+
columnize (0.3.6)
|
|
16
|
+
daemons (1.1.9)
|
|
17
|
+
diff-lcs (1.1.3)
|
|
18
|
+
eventmachine (1.0.0)
|
|
19
|
+
json (1.7.5)
|
|
20
|
+
launchy (2.1.2)
|
|
21
|
+
addressable (~> 2.3)
|
|
22
|
+
linecache19 (0.5.12)
|
|
23
|
+
ruby_core_source (>= 0.1.4)
|
|
24
|
+
multi_json (1.3.6)
|
|
25
|
+
nokogiri (1.5.5)
|
|
26
|
+
oauth (0.4.7)
|
|
27
|
+
rack (1.4.1)
|
|
28
|
+
rdio (0.1.0)
|
|
29
|
+
json
|
|
30
|
+
oauth (>= 0.3.0)
|
|
31
|
+
rspec (2.11.0)
|
|
32
|
+
rspec-core (~> 2.11.0)
|
|
33
|
+
rspec-expectations (~> 2.11.0)
|
|
34
|
+
rspec-mocks (~> 2.11.0)
|
|
35
|
+
rspec-core (2.11.1)
|
|
36
|
+
rspec-expectations (2.11.3)
|
|
37
|
+
diff-lcs (~> 1.1.3)
|
|
38
|
+
rspec-mocks (2.11.3)
|
|
39
|
+
ruby-debug-base19 (0.11.25)
|
|
40
|
+
columnize (>= 0.3.1)
|
|
41
|
+
linecache19 (>= 0.5.11)
|
|
42
|
+
ruby_core_source (>= 0.1.4)
|
|
43
|
+
ruby-debug19 (0.11.6)
|
|
44
|
+
columnize (>= 0.3.1)
|
|
45
|
+
linecache19 (>= 0.5.11)
|
|
46
|
+
ruby-debug-base19 (>= 0.11.19)
|
|
47
|
+
ruby_core_source (0.1.5)
|
|
48
|
+
archive-tar-minitar (>= 0.5.2)
|
|
49
|
+
thin (1.5.0)
|
|
50
|
+
daemons (>= 1.0.9)
|
|
51
|
+
eventmachine (>= 0.12.6)
|
|
52
|
+
rack (>= 1.0.0)
|
|
53
|
+
yard (0.8.2.1)
|
|
54
|
+
|
|
55
|
+
PLATFORMS
|
|
56
|
+
ruby
|
|
57
|
+
|
|
58
|
+
DEPENDENCIES
|
|
59
|
+
lyricli!
|
|
60
|
+
rspec (~> 2.11.0)
|
|
61
|
+
ruby-debug19 (~> 0.11.6)
|
|
62
|
+
thin (~> 1.5.0)
|
|
63
|
+
yard (~> 0.8.2.1)
|
data/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Lyricli #
|
|
2
|
+
## The command line client for lyrics ##
|
|
3
|
+
|
|
4
|
+
This is a quick introduction for Lyricli. Right now it's in really early
|
|
5
|
+
stages of development, so it's lacking in a lot of stuff (mainly tests
|
|
6
|
+
and documentation) ... But it generally works and here's a tutorial to
|
|
7
|
+
see how to get it working.
|
|
8
|
+
|
|
9
|
+
### Installing ###
|
|
10
|
+
|
|
11
|
+
1. Clone this Repo
|
|
12
|
+
2. `gem build lyricli.gemspec`
|
|
13
|
+
3. `gem install lyricli-0.0.1.gem`
|
|
14
|
+
4. Voila!
|
|
15
|
+
|
|
16
|
+
### Usage ###
|
|
17
|
+
|
|
18
|
+
Lyricli can be invoked with the command `lrc` and there are three basic
|
|
19
|
+
ways of using it:
|
|
20
|
+
|
|
21
|
+
`lrc`
|
|
22
|
+
|
|
23
|
+
When you run it without arguments, it will look in the available sources
|
|
24
|
+
to try to find a playing song and extract the lyrics.
|
|
25
|
+
|
|
26
|
+
`lrc artist song`
|
|
27
|
+
|
|
28
|
+
When you run it with arguments, it will use them to search for the
|
|
29
|
+
lyrics. This won't work if you manually disable the arguments source in
|
|
30
|
+
your configuration file.
|
|
31
|
+
|
|
32
|
+
#### Commands ####
|
|
33
|
+
|
|
34
|
+
The third way to use it is by passing it one of the following special
|
|
35
|
+
commands:
|
|
36
|
+
|
|
37
|
+
* `lrc -l` or `lrc --list-sources` lists the available sources.
|
|
38
|
+
* `lrc -e` or `lrc --enable SOURCE` enable a source from the list.
|
|
39
|
+
* `lrc -d` or `lrc --disable SOURCE` disable a source from the list.
|
|
40
|
+
* `lrc -r` or `lrc --reset SOURCE` reset all configuration for a source.
|
|
41
|
+
* `lrc -v` or `lrc --version` show the installed version of lyricli.
|
|
42
|
+
* `lrc -h` or `lrc --help` display some help
|
|
43
|
+
|
|
44
|
+
### Roadmap ###
|
|
45
|
+
|
|
46
|
+
There is not much defined right now as a roadmap, but this needs to be
|
|
47
|
+
done:
|
|
48
|
+
|
|
49
|
+
* Specs for all the components
|
|
50
|
+
* YARD documentation for all the components
|
|
51
|
+
|
|
52
|
+
And the first thing I want to work on after that is done is separating
|
|
53
|
+
the Lyrics Engines so we can add/remove lyrics engines in a similar way to how
|
|
54
|
+
we currently add/remove sources.
|
|
55
|
+
|
|
56
|
+
Also, I want to add the last song to the configuration, so you can check
|
|
57
|
+
that. This would let us "watch" lyricli without hammering the lyrics
|
|
58
|
+
wiki api
|
|
59
|
+
|
|
60
|
+
Also, during the enable phase, sources like iTunes should check for
|
|
61
|
+
proper OS and stop if they're not in their home turf.
|
|
62
|
+
|
|
63
|
+
### Leave Feedback Please! ###
|
|
64
|
+
|
|
65
|
+
If you decide to use or hack away at Lyricly, please don't forget to
|
|
66
|
+
post any issues you find.
|
|
67
|
+
|
|
68
|
+
### License ###
|
|
69
|
+
Licensed under 3-clause-BSD.
|
data/bin/lrc
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
require 'lyricli'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
options = {}
|
|
8
|
+
OptionParser.new do |opts|
|
|
9
|
+
opts.banner = %{Usage:
|
|
10
|
+
lrc [options]
|
|
11
|
+
lrc artist song
|
|
12
|
+
lrc You must enable other sources for this
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
opts.on("-e", "--enable SOURCE", "Enable SOURCE") do |source|
|
|
18
|
+
Lyricli.enable(source)
|
|
19
|
+
puts "#{source} has been enabled"
|
|
20
|
+
exit
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
opts.on("-l", "--list-sources", "List all available Sources") do
|
|
24
|
+
puts Lyricli.sources
|
|
25
|
+
exit
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
opts.on("-d", "--disable SOURCE", "Disable SOURCE") do |source|
|
|
29
|
+
Lyricli.disable(source)
|
|
30
|
+
puts "#{source} has been disabled"
|
|
31
|
+
exit
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
opts.on("-r", "--reset SOURCE", "Reset the configuration of SOURCE") do |source|
|
|
35
|
+
Lyricli.reset(source)
|
|
36
|
+
puts "#{source} has been disabled and all its configuration reset"
|
|
37
|
+
exit
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
opts.on("-h", "--help", "Shows this message") do
|
|
41
|
+
puts opts
|
|
42
|
+
exit
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
opts.on("-v", "--version", "Show version") do
|
|
46
|
+
puts Lyricli.version
|
|
47
|
+
exit
|
|
48
|
+
end
|
|
49
|
+
end.parse!
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
puts Lyricli.lyrics
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module Lyricli
|
|
2
|
+
|
|
3
|
+
# This class handles the configuration of Lyricli
|
|
4
|
+
class Configuration
|
|
5
|
+
|
|
6
|
+
# Defines the paths to the default and user configuration files
|
|
7
|
+
def initialize
|
|
8
|
+
@config_path = "~/.lyricli.conf"
|
|
9
|
+
@defaults_path = "defaults.json"
|
|
10
|
+
@config = nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
@@instance = Configuration.new
|
|
14
|
+
|
|
15
|
+
# Ensure this is only called once. Only use the instance class variable
|
|
16
|
+
# to access this method, as its constructor is private.
|
|
17
|
+
def self.instance
|
|
18
|
+
@@instance
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Access configuration properties, loads config if needed beforehand.
|
|
22
|
+
#
|
|
23
|
+
# @param [String] key the configuration key to access
|
|
24
|
+
# @return [String, Hash, Array] the value of the configuration key.
|
|
25
|
+
def [](key)
|
|
26
|
+
load_config unless @config
|
|
27
|
+
@config[key]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Assigns a new value to a configuration key, loads config if needed and
|
|
31
|
+
# saves it after updating.
|
|
32
|
+
#
|
|
33
|
+
# @param [String] key the configuration key to set
|
|
34
|
+
# @param [Object] value the value for the configuration key, can be any
|
|
35
|
+
# object as long as it can be converted to JSON
|
|
36
|
+
def []=(key, value)
|
|
37
|
+
load_config unless @config
|
|
38
|
+
@config[key] = value
|
|
39
|
+
save_config
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Deletes a key from the configuration, loads config if needed and saves
|
|
43
|
+
# it after deleting.
|
|
44
|
+
#
|
|
45
|
+
# @param [String] key the key to delete
|
|
46
|
+
def delete(key)
|
|
47
|
+
load_config unless @config
|
|
48
|
+
@config.delete(key)
|
|
49
|
+
save_config
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private_class_method :new
|
|
53
|
+
|
|
54
|
+
# Loads the configuration from the user file, attempts to create it from
|
|
55
|
+
# defaults if it's not present. sets the `@config` instance variable.
|
|
56
|
+
def load_config
|
|
57
|
+
path = File.expand_path(@config_path)
|
|
58
|
+
|
|
59
|
+
if File.exists?(path)
|
|
60
|
+
file = File.new(path, "r")
|
|
61
|
+
@config = MultiJson.decode(file.read)
|
|
62
|
+
else
|
|
63
|
+
load_default_config
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Serializes the `@config` Hash to JSON and saves it to a file.
|
|
68
|
+
def save_config
|
|
69
|
+
path = File.expand_path(@config_path)
|
|
70
|
+
file = File.new(path, "w")
|
|
71
|
+
file.print(MultiJson.encode(@config))
|
|
72
|
+
file.close
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
# Loads the default configuration from a JSON file
|
|
78
|
+
def load_default_config
|
|
79
|
+
# Load the default
|
|
80
|
+
path = File.join(::Lyricli.root, "config", @defaults_path)
|
|
81
|
+
|
|
82
|
+
if File.exists?(path)
|
|
83
|
+
file = File.new(path, "r")
|
|
84
|
+
@config = MultiJson.decode(file.read)
|
|
85
|
+
else
|
|
86
|
+
@config = {}
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Lyricli
|
|
2
|
+
|
|
3
|
+
# This class has the basic logic for extracting the lyrics and controlling the
|
|
4
|
+
# application
|
|
5
|
+
class Lyricli
|
|
6
|
+
|
|
7
|
+
# Constructor, initializes `@source_manager`
|
|
8
|
+
def initialize
|
|
9
|
+
@source_manager = SourceManager.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Raises an InvalidLyricsError which means we did not get any valid
|
|
13
|
+
# artist/song from any of the sources
|
|
14
|
+
#
|
|
15
|
+
# @raise [Lyricli::Exceptions::InvalidLyricsError] because we found nothing
|
|
16
|
+
def exit_with_error
|
|
17
|
+
raise Exceptions::InvalidLyricsError
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Extracts the current track, validates it and requests the lyrics from our
|
|
21
|
+
# LyricsEngine
|
|
22
|
+
#
|
|
23
|
+
# @return [String] the found lyrics, or a string indicating none were found
|
|
24
|
+
def get_lyrics
|
|
25
|
+
|
|
26
|
+
begin
|
|
27
|
+
set_current_track
|
|
28
|
+
check_params
|
|
29
|
+
rescue Exceptions::InvalidLyricsError
|
|
30
|
+
return "No Artist/Song could be found :("
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
engine = LyricsEngine.new(@current_track[:artist], @current_track[:song])
|
|
34
|
+
|
|
35
|
+
begin
|
|
36
|
+
return engine.get_lyrics
|
|
37
|
+
rescue Exceptions::LyricsNotFoundError
|
|
38
|
+
return "Lyrics not found :("
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Set the `@current_track` instance variable by asking the SourceManager for
|
|
43
|
+
# its current track
|
|
44
|
+
def set_current_track
|
|
45
|
+
@current_track = @source_manager.current_track
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Exits with error when there is an empty field from the current track.
|
|
49
|
+
def check_params
|
|
50
|
+
self.exit_with_error unless @current_track
|
|
51
|
+
self.exit_with_error if @current_track[:artist].nil? or @current_track[:artist].empty?
|
|
52
|
+
self.exit_with_error if @current_track[:song].nil? or @current_track[:song].empty?
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Lyricli
|
|
2
|
+
|
|
3
|
+
# This class gets the lyrics according to a given artist and song name.
|
|
4
|
+
class LyricsEngine
|
|
5
|
+
|
|
6
|
+
include Util
|
|
7
|
+
|
|
8
|
+
# Starts a new instance of LyricsEngine
|
|
9
|
+
#
|
|
10
|
+
# @param [String] artist the artist
|
|
11
|
+
# @param [String] song the song to look for
|
|
12
|
+
def initialize(artist, song)
|
|
13
|
+
@provider = URI("http://lyrics.wikia.com/api.php?artist=#{sanitize_param artist}&song=#{sanitize_param song}&fmt=realjson")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Asks Lyrics Wiki for the lyrics, also cleans up the output a little.
|
|
17
|
+
#
|
|
18
|
+
# @return [String] the lyrics
|
|
19
|
+
def get_lyrics
|
|
20
|
+
begin
|
|
21
|
+
response = Net::HTTP.get(@provider)
|
|
22
|
+
response = MultiJson.decode(response)
|
|
23
|
+
|
|
24
|
+
doc = Nokogiri::HTML(open(response['url']))
|
|
25
|
+
node = doc.search(".lyricbox").first
|
|
26
|
+
rescue
|
|
27
|
+
raise Exceptions::LyricsNotFoundError
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
node.search(".rtMatcher").each do |n|
|
|
31
|
+
n.remove
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
node.search("br").each do |br|
|
|
35
|
+
br.replace "\n"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
node.inner_text
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
module Lyricli
|
|
2
|
+
|
|
3
|
+
# Manages the different sources. SourceManager is in charge of enabling and
|
|
4
|
+
# disabling them, as well as getting the current track.
|
|
5
|
+
class SourceManager
|
|
6
|
+
|
|
7
|
+
include Util
|
|
8
|
+
|
|
9
|
+
# Creates a new instance of SourceManager
|
|
10
|
+
def initialize
|
|
11
|
+
@enabled_sources = []
|
|
12
|
+
@config = Configuration.instance
|
|
13
|
+
@config["enabled_sources"].each do |source|
|
|
14
|
+
if klass = parse_class(camelize(source))
|
|
15
|
+
current_source = klass.new
|
|
16
|
+
@enabled_sources << current_source
|
|
17
|
+
else
|
|
18
|
+
raise Exceptions::StartSourceError
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Enables a source. This runs the source's enable method and adds it to the
|
|
24
|
+
# `enabled_sources` configuration key. It will only enable sources that
|
|
25
|
+
# are "available" (see #available_sources)
|
|
26
|
+
#
|
|
27
|
+
# @param [String] source_name the name of the source to enable
|
|
28
|
+
def enable(source_name)
|
|
29
|
+
if available_sources.include?(source_name)
|
|
30
|
+
if klass = parse_class(camelize(source_name))
|
|
31
|
+
klass.enable
|
|
32
|
+
@config["enabled_sources"] << klass.name
|
|
33
|
+
@config["enabled_sources"].uniq!
|
|
34
|
+
@config.save_config
|
|
35
|
+
else
|
|
36
|
+
raise Exceptions::EnableSourceError
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
raise Exceptions::UnknownSourceError
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Disables a source. This only removes the source from the `enabled_sources`
|
|
44
|
+
# configuration key.
|
|
45
|
+
#
|
|
46
|
+
# @param [String] source_name the name of the source to disable
|
|
47
|
+
def disable(source_name)
|
|
48
|
+
if available_sources.include?(source_name)
|
|
49
|
+
if klass = parse_class(camelize(source_name))
|
|
50
|
+
@config["enabled_sources"].delete(klass.name)
|
|
51
|
+
@config.save_config
|
|
52
|
+
else
|
|
53
|
+
raise Exceptions::DisableSourceError
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
raise Exceptions::UnknownSourceError
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Resets a source. This runs the source's reset method. It will also disable
|
|
61
|
+
# them.
|
|
62
|
+
#
|
|
63
|
+
# @param [String] source_name the name of the source to reset.
|
|
64
|
+
def reset(source_name)
|
|
65
|
+
if available_sources.include?(source_name)
|
|
66
|
+
if klass = parse_class(camelize(source_name))
|
|
67
|
+
klass.reset
|
|
68
|
+
disable(source_name)
|
|
69
|
+
else
|
|
70
|
+
raise Exceptions::ResetSourceError
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
raise Exceptions::UnknownSourceError
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Iterates over every source to attempt to retrieve the current song.
|
|
78
|
+
#
|
|
79
|
+
# @return [Hash] the current track, has an `:artist` and `:song` key.
|
|
80
|
+
def current_track
|
|
81
|
+
track = nil
|
|
82
|
+
lock = false
|
|
83
|
+
@enabled_sources.each do |source|
|
|
84
|
+
begin
|
|
85
|
+
current_track = source.current_track
|
|
86
|
+
|
|
87
|
+
# This is a special thing for arguments. The thing is, they need to
|
|
88
|
+
# be inputted manually. So, if they are present they won't allow
|
|
89
|
+
# anyone else to give results. Makes sense, yet a bit hacky.
|
|
90
|
+
unless current_track[:artist].nil? || current_track[:artist].empty? || current_track[:song].nil? || current_track[:song].empty?
|
|
91
|
+
track = current_track unless lock
|
|
92
|
+
lock = true if source.class.name == "arguments"
|
|
93
|
+
end
|
|
94
|
+
rescue
|
|
95
|
+
raise Exceptions::SourceConfigurationError
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
track
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Returns an array with the available sources. Optionally formats the result
|
|
102
|
+
# so active sources are identified by an appended *
|
|
103
|
+
#
|
|
104
|
+
# @param [Boolean] format whether or not to render the stars for active
|
|
105
|
+
# sources.
|
|
106
|
+
# @return [Array] the names of the currently available sources.
|
|
107
|
+
def available_sources(format = false)
|
|
108
|
+
path_root = File.expand_path(File.dirname(__FILE__))
|
|
109
|
+
sources = Dir[path_root+"/sources/*.rb"].map{ |s|
|
|
110
|
+
name = s.split("/").last.gsub(/\.rb/, "")
|
|
111
|
+
name
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Remove arguments (Hack?) We don't want anybody to touch tihs one.
|
|
115
|
+
sources.delete("arguments")
|
|
116
|
+
if format
|
|
117
|
+
# Add a star to denote enabled sources
|
|
118
|
+
format_sources(sources)
|
|
119
|
+
else
|
|
120
|
+
sources
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Adds a star to all members of the array that correspond to an active
|
|
125
|
+
# source
|
|
126
|
+
#
|
|
127
|
+
# @param [Array] sources the array of sources to format
|
|
128
|
+
# @return [Array] the formatted array
|
|
129
|
+
def format_sources(sources)
|
|
130
|
+
sources.map{ |s|
|
|
131
|
+
s << "*" if @config["enabled_sources"].include?(s)
|
|
132
|
+
s
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Lyricli
|
|
2
|
+
module Sources
|
|
3
|
+
# The arguments source. This one is special since it expects two
|
|
4
|
+
# arguments. It is treated specially by the SourceManager.
|
|
5
|
+
class Arguments
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
attr_accessor :name
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
@name = "arguments"
|
|
12
|
+
|
|
13
|
+
# The enable method should run all of the tasks needed to validate
|
|
14
|
+
# the source. In the case of Rdio it has to authenticate with OAuth.
|
|
15
|
+
def self.enable
|
|
16
|
+
# Nothing to do.
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Instantiates everything it needs to run.
|
|
20
|
+
def initialize
|
|
21
|
+
# Nothing to do.
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The current_track method should return the name of the current
|
|
25
|
+
# artist and song.
|
|
26
|
+
# @return [Hash] A hash containing the current `:song` and `:artist`.
|
|
27
|
+
def current_track
|
|
28
|
+
artist = ARGV[0]
|
|
29
|
+
song = ARGV[1]
|
|
30
|
+
{:artist => artist, :song => song}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# The reset method resets any configurations it may have
|
|
34
|
+
def self.reset
|
|
35
|
+
# Reset Code
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
Binary file
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Lyricli
|
|
2
|
+
module Sources
|
|
3
|
+
# The source for iTunes
|
|
4
|
+
class Itunes
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
attr_accessor :name
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
@name = "itunes"
|
|
11
|
+
|
|
12
|
+
# The enable method should run all of the tasks needed to validate
|
|
13
|
+
# the source. In the case of Rdio it has to authenticate with OAuth.
|
|
14
|
+
def self.enable
|
|
15
|
+
# Nothing to do
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Instantiates everything it needs to run.
|
|
19
|
+
def initialize
|
|
20
|
+
@config = Configuration.instance
|
|
21
|
+
@script = "current_song.scpt"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The current_track method should return the name of the current
|
|
25
|
+
# artist and song.
|
|
26
|
+
# @return [Hash] A hash containing the current `:song` and `:artist`.
|
|
27
|
+
def current_track
|
|
28
|
+
path_root = File.expand_path(File.dirname(__FILE__))
|
|
29
|
+
path = File.join(path_root, @script)
|
|
30
|
+
current = `osascript #{path}`
|
|
31
|
+
current = current.split("<-SEP->")
|
|
32
|
+
{:artist => current[0], :song => current[1]}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# The reset method resets any configurations it may have
|
|
36
|
+
def self.reset
|
|
37
|
+
# Nothing to do
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module Lyricli
|
|
2
|
+
module Sources
|
|
3
|
+
|
|
4
|
+
# This is the Source for rdio
|
|
5
|
+
class Rdio
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
attr_accessor :name
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
@name = "rdio"
|
|
12
|
+
|
|
13
|
+
# The enable method should run all of the tasks needed to validate
|
|
14
|
+
# the source. In the case of Rdio it has to authenticate with OAuth.
|
|
15
|
+
def self.enable
|
|
16
|
+
# Validation Code
|
|
17
|
+
@config = Configuration.instance
|
|
18
|
+
unless @config["rdio_auth_token"] && !@config["rdio_auth_token"].empty?
|
|
19
|
+
create_auth_token
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
puts "***"
|
|
23
|
+
puts "Hello, rdio tends to be a bit aggressive and tends to have trouble with other sources. If you're having trouble, you can disable it temporarily. You will not have to reauthenticate."
|
|
24
|
+
puts "***"
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Instantiates everything it needs to run.
|
|
29
|
+
def initialize
|
|
30
|
+
@name = 'rdio'
|
|
31
|
+
@config = Configuration.instance
|
|
32
|
+
@rdio = ::Rdio::SimpleRdio.new([@config["rdio_key"], @config["rdio_secret"]], @config["rdio_auth_token"])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# The current_track method should return the name of the current
|
|
36
|
+
# artist and song.
|
|
37
|
+
#
|
|
38
|
+
# @return [Hash] A hash containing the current `:song` and `:artist`.
|
|
39
|
+
def current_track
|
|
40
|
+
response = @rdio.call('currentUser', {'extras' => 'lastSongPlayed'})
|
|
41
|
+
artist = response["result"]["lastSongPlayed"]["artist"]
|
|
42
|
+
song = response["result"]["lastSongPlayed"]["name"]
|
|
43
|
+
{:artist => artist, :song => song}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# The reset method resets any configurations it may have
|
|
47
|
+
def self.reset
|
|
48
|
+
@config = Configuration.instance
|
|
49
|
+
@config.delete("rdio_auth_token")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Signs in to rdio with our credentials and requests access for a new auth
|
|
53
|
+
# token.
|
|
54
|
+
def self.create_auth_token
|
|
55
|
+
rdio = ::Rdio::SimpleRdio.new([@config["rdio_key"], @config["rdio_secret"]], @config["rdio_auth_token"])
|
|
56
|
+
|
|
57
|
+
# Request Authorization
|
|
58
|
+
puts "Follow this URL to authorize lyricli:"
|
|
59
|
+
auth_url = rdio.begin_authentication('oob')
|
|
60
|
+
puts auth_url
|
|
61
|
+
::Launchy.open(auth_url)
|
|
62
|
+
|
|
63
|
+
# Request Code, Obtain Token
|
|
64
|
+
print "Please type the authorization code: "
|
|
65
|
+
auth_code = gets.chomp
|
|
66
|
+
token = rdio.complete_authentication(auth_code)
|
|
67
|
+
|
|
68
|
+
@config["rdio_auth_token"] = token
|
|
69
|
+
token
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/lyricli/util.rb
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Lyricli
|
|
2
|
+
# This module contains several utility functions.
|
|
3
|
+
module Util
|
|
4
|
+
|
|
5
|
+
# Transforms a string from snake_case to UpperCamelCase
|
|
6
|
+
#
|
|
7
|
+
# @param [String] str the string that will be Camelized
|
|
8
|
+
# @return [String] the Camelized string.
|
|
9
|
+
def camelize(str)
|
|
10
|
+
str.split('_').map {|w| w.capitalize}.join
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Takes a class name in snake_case and attempts to find the corresponding
|
|
14
|
+
# class from the sources.
|
|
15
|
+
#
|
|
16
|
+
# @param [String] class_name the snake_case name of the class to search for.
|
|
17
|
+
# @return [Class,nil] the found class or nil
|
|
18
|
+
def parse_class(class_name)
|
|
19
|
+
begin
|
|
20
|
+
path = "Sources::#{class_name}"
|
|
21
|
+
return eval(path)
|
|
22
|
+
rescue NameError
|
|
23
|
+
return nil
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Simply escapes a param and substitutes spaces and escaped plus signs for
|
|
28
|
+
# plus signs.
|
|
29
|
+
#
|
|
30
|
+
# @param [String] p the parameter to be sanitized
|
|
31
|
+
# @return [String] the sanitized parameter
|
|
32
|
+
def sanitize_param(p)
|
|
33
|
+
CGI.escape(p.gsub(/ /, "+")).gsub("%2B", "+")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/lyricli.rb
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'cgi'
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'multi_json'
|
|
5
|
+
require 'nokogiri'
|
|
6
|
+
require 'open-uri'
|
|
7
|
+
require 'launchy'
|
|
8
|
+
|
|
9
|
+
# This shit causes a lot of warnings. Quick Hack.
|
|
10
|
+
original_verbosity = $VERBOSE
|
|
11
|
+
$VERBOSE = nil
|
|
12
|
+
require 'rdio'
|
|
13
|
+
$VERBOSE = original_verbosity
|
|
14
|
+
|
|
15
|
+
# Local Dependencies
|
|
16
|
+
require "lyricli/util"
|
|
17
|
+
require "lyricli/configuration"
|
|
18
|
+
require "lyricli/lyricli"
|
|
19
|
+
require "lyricli/lyrics_engine"
|
|
20
|
+
require "lyricli/source_manager"
|
|
21
|
+
require "lyricli/sources"
|
|
22
|
+
require "lyricli/sources/arguments"
|
|
23
|
+
require "lyricli/sources/rdio"
|
|
24
|
+
require "lyricli/sources/itunes"
|
|
25
|
+
require "lyricli/exceptions"
|
|
26
|
+
require "lyricli/exceptions/disable_source_error"
|
|
27
|
+
require "lyricli/exceptions/enable_source_error"
|
|
28
|
+
require "lyricli/exceptions/invalid_lyrics_error"
|
|
29
|
+
require "lyricli/exceptions/lyrics_not_found_error"
|
|
30
|
+
require "lyricli/exceptions/reset_source_error"
|
|
31
|
+
require "lyricli/exceptions/source_configuration_error"
|
|
32
|
+
require "lyricli/exceptions/start_source_error"
|
|
33
|
+
require "lyricli/exceptions/unknown_source_error"
|
|
34
|
+
|
|
35
|
+
# The Lyricli module allows you to easily search for lyrics by looking for
|
|
36
|
+
# song and artist data from diverse sources.
|
|
37
|
+
module Lyricli
|
|
38
|
+
# Creates a new Lyricli instance and returns lyrics by going through the
|
|
39
|
+
# sources.
|
|
40
|
+
# @return [String] the fetched lyrics
|
|
41
|
+
def self.lyrics
|
|
42
|
+
@lyricli = Lyricli.new
|
|
43
|
+
@lyricli.get_lyrics
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns the version of the library
|
|
47
|
+
# @return [String] the version
|
|
48
|
+
def self.version
|
|
49
|
+
Gem.loaded_specs["lyricli"].version
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns a list of the available sources to enable or disable
|
|
53
|
+
# @return [String] the list of available sources. Enabled sources have
|
|
54
|
+
# a star appended.
|
|
55
|
+
def self.sources
|
|
56
|
+
source_manager = SourceManager.new
|
|
57
|
+
source_manager.available_sources(true).join(", ")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Enables a source via the Source Manager
|
|
61
|
+
def self.enable(source_name)
|
|
62
|
+
source_manager = SourceManager.new
|
|
63
|
+
begin
|
|
64
|
+
source_manager.enable(source_name)
|
|
65
|
+
rescue Exceptions::UnknownSourceError
|
|
66
|
+
"There is no such Source"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Disables a source via the Source Manager
|
|
71
|
+
def self.disable(source_name)
|
|
72
|
+
source_manager = SourceManager.new
|
|
73
|
+
begin
|
|
74
|
+
source_manager.disable(source_name)
|
|
75
|
+
rescue Exceptions::UnknownSourceError
|
|
76
|
+
"There is no such Source"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Resets all configuration for a source via the Source Manager
|
|
81
|
+
def self.reset(source_name)
|
|
82
|
+
source_manager = SourceManager.new
|
|
83
|
+
begin
|
|
84
|
+
source_manager.reset(source_name)
|
|
85
|
+
rescue Exceptions::UnknownSourceError
|
|
86
|
+
"There is no such Source"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Returns the root of the Gem.
|
|
91
|
+
#
|
|
92
|
+
# @return [String] the root path for this gem
|
|
93
|
+
def self.root
|
|
94
|
+
File.expand_path('../..',__FILE__)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require "rspec"
|
|
2
|
+
require "lyricli"
|
|
3
|
+
|
|
4
|
+
describe Lyricli::SourceManager do
|
|
5
|
+
before :each do
|
|
6
|
+
# Stub the configuration
|
|
7
|
+
@example_configuration = {"enabled_sources" => "test_class"}
|
|
8
|
+
Configuration.stub(:'[]').and_return(@example_configuration)
|
|
9
|
+
Configuration.stub(:delete)
|
|
10
|
+
|
|
11
|
+
# Stub the test class.
|
|
12
|
+
module Lyricli
|
|
13
|
+
module Sources
|
|
14
|
+
module TestClass
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
@example_artist = {:artist => "The Shins", :song => "Know Your Onion"}
|
|
20
|
+
|
|
21
|
+
Lyricli::Sources::TestClass.stub(:enable)
|
|
22
|
+
Lyricli::Sources::TestClass.stub(:reset)
|
|
23
|
+
Lyricli::Sources::TestClass.stub(:current_track).and_return(@example_artist)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require "rspec"
|
|
2
|
+
require "lyricli"
|
|
3
|
+
|
|
4
|
+
describe Lyricli::Util do
|
|
5
|
+
before :each do
|
|
6
|
+
class TestClass
|
|
7
|
+
include Lyricli::Util
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module Lyricli
|
|
11
|
+
module Sources
|
|
12
|
+
class ParsedClass
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
@c = TestClass.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#camelize" do
|
|
21
|
+
it "should convert snake_case to CamelCase" do
|
|
22
|
+
expect(@c.camelize("test_string")).to eq("TestString")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "#parse_class" do
|
|
27
|
+
it "should parse classes under the Source namespace" do
|
|
28
|
+
expect(@c.parse_class("ParsedClass")).to eq(Lyricli::Sources::ParsedClass)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should return nil for nonexistent classes" do
|
|
32
|
+
expect(@c.parse_class("non_existent_class")).to eq(nil)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe "#sanitize_param" do
|
|
37
|
+
it "should escape weird characters, but conserve the +" do
|
|
38
|
+
str = "one two+three /?&"
|
|
39
|
+
expect(@c.sanitize_param(str)).to eq("one+two+three+%2F%3F%26")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
File without changes
|
metadata
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lyricli
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Ben Beltran
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-03-13 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: nokogiri
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 1.5.5
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ~>
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: 1.5.5
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: multi_json
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ~>
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: 1.3.6
|
|
38
|
+
type: :runtime
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ~>
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: 1.3.6
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: rdio
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ~>
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 0.1.0
|
|
54
|
+
type: :runtime
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ~>
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 0.1.0
|
|
62
|
+
- !ruby/object:Gem::Dependency
|
|
63
|
+
name: launchy
|
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
|
65
|
+
none: false
|
|
66
|
+
requirements:
|
|
67
|
+
- - ~>
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: 2.1.2
|
|
70
|
+
type: :runtime
|
|
71
|
+
prerelease: false
|
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
73
|
+
none: false
|
|
74
|
+
requirements:
|
|
75
|
+
- - ~>
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: 2.1.2
|
|
78
|
+
- !ruby/object:Gem::Dependency
|
|
79
|
+
name: ruby-debug19
|
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
|
81
|
+
none: false
|
|
82
|
+
requirements:
|
|
83
|
+
- - ~>
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: 0.11.6
|
|
86
|
+
type: :development
|
|
87
|
+
prerelease: false
|
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
89
|
+
none: false
|
|
90
|
+
requirements:
|
|
91
|
+
- - ~>
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: 0.11.6
|
|
94
|
+
- !ruby/object:Gem::Dependency
|
|
95
|
+
name: yard
|
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
|
97
|
+
none: false
|
|
98
|
+
requirements:
|
|
99
|
+
- - ~>
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: 0.8.2.1
|
|
102
|
+
type: :development
|
|
103
|
+
prerelease: false
|
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
105
|
+
none: false
|
|
106
|
+
requirements:
|
|
107
|
+
- - ~>
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: 0.8.2.1
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: thin
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
none: false
|
|
114
|
+
requirements:
|
|
115
|
+
- - ~>
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: 1.5.0
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
none: false
|
|
122
|
+
requirements:
|
|
123
|
+
- - ~>
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: 1.5.0
|
|
126
|
+
- !ruby/object:Gem::Dependency
|
|
127
|
+
name: rspec
|
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
|
129
|
+
none: false
|
|
130
|
+
requirements:
|
|
131
|
+
- - ~>
|
|
132
|
+
- !ruby/object:Gem::Version
|
|
133
|
+
version: 2.11.0
|
|
134
|
+
type: :development
|
|
135
|
+
prerelease: false
|
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
137
|
+
none: false
|
|
138
|
+
requirements:
|
|
139
|
+
- - ~>
|
|
140
|
+
- !ruby/object:Gem::Version
|
|
141
|
+
version: 2.11.0
|
|
142
|
+
description: Lyricli is an awesome CLI tool to read the lyrics of your currently playing
|
|
143
|
+
song right in the command line
|
|
144
|
+
email: ben@nsovocal.com
|
|
145
|
+
executables:
|
|
146
|
+
- lrc
|
|
147
|
+
extensions: []
|
|
148
|
+
extra_rdoc_files: []
|
|
149
|
+
files:
|
|
150
|
+
- lib/lyricli/configuration.rb
|
|
151
|
+
- lib/lyricli/exceptions/disable_source_error.rb
|
|
152
|
+
- lib/lyricli/exceptions/enable_source_error.rb
|
|
153
|
+
- lib/lyricli/exceptions/invalid_lyrics_error.rb
|
|
154
|
+
- lib/lyricli/exceptions/lyrics_not_found_error.rb
|
|
155
|
+
- lib/lyricli/exceptions/reset_source_error.rb
|
|
156
|
+
- lib/lyricli/exceptions/source_configuration_error.rb
|
|
157
|
+
- lib/lyricli/exceptions/start_source_error.rb
|
|
158
|
+
- lib/lyricli/exceptions/unknown_source_error.rb
|
|
159
|
+
- lib/lyricli/exceptions.rb
|
|
160
|
+
- lib/lyricli/lyricli.rb
|
|
161
|
+
- lib/lyricli/lyrics_engine.rb
|
|
162
|
+
- lib/lyricli/source_manager.rb
|
|
163
|
+
- lib/lyricli/sources/arguments.rb
|
|
164
|
+
- lib/lyricli/sources/itunes.rb
|
|
165
|
+
- lib/lyricli/sources/rdio.rb
|
|
166
|
+
- lib/lyricli/sources.rb
|
|
167
|
+
- lib/lyricli/util.rb
|
|
168
|
+
- lib/lyricli.rb
|
|
169
|
+
- bin/lrc
|
|
170
|
+
- Gemfile
|
|
171
|
+
- Gemfile.lock
|
|
172
|
+
- README.md
|
|
173
|
+
- spec/bin/lrc_spec.rb
|
|
174
|
+
- spec/lib/lyricli/configuration_spec.rb
|
|
175
|
+
- spec/lib/lyricli/exceptions_spec.rb
|
|
176
|
+
- spec/lib/lyricli/lyricli_spec.rb
|
|
177
|
+
- spec/lib/lyricli/lyrics_engine_spec.rb
|
|
178
|
+
- spec/lib/lyricli/source_manager_spec.rb
|
|
179
|
+
- spec/lib/lyricli/sources/arguments.rb
|
|
180
|
+
- spec/lib/lyricli/sources/itunes.rb
|
|
181
|
+
- spec/lib/lyricli/sources/rdio.rb
|
|
182
|
+
- spec/lib/lyricli/sources_spec.rb
|
|
183
|
+
- spec/lib/lyricli/util_spec.rb
|
|
184
|
+
- spec/lib/lyricli_spec.rb
|
|
185
|
+
- config/defaults.json
|
|
186
|
+
- lib/lyricli/sources/current_song.scpt
|
|
187
|
+
homepage: http://nsovocal.com/lyricli
|
|
188
|
+
licenses: []
|
|
189
|
+
post_install_message:
|
|
190
|
+
rdoc_options: []
|
|
191
|
+
require_paths:
|
|
192
|
+
- lib
|
|
193
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
194
|
+
none: false
|
|
195
|
+
requirements:
|
|
196
|
+
- - ! '>='
|
|
197
|
+
- !ruby/object:Gem::Version
|
|
198
|
+
version: '0'
|
|
199
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
|
+
none: false
|
|
201
|
+
requirements:
|
|
202
|
+
- - ! '>='
|
|
203
|
+
- !ruby/object:Gem::Version
|
|
204
|
+
version: '0'
|
|
205
|
+
requirements: []
|
|
206
|
+
rubyforge_project:
|
|
207
|
+
rubygems_version: 1.8.24
|
|
208
|
+
signing_key:
|
|
209
|
+
specification_version: 3
|
|
210
|
+
summary: Lyricli is an awesome lyric client for your Command Line
|
|
211
|
+
test_files: []
|
|
212
|
+
has_rdoc:
|