LOLastfm 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LOLastfm.gemspec +0 -1
- data/README.md +51 -2
- data/bin/LOLastfm +1 -1
- data/bin/LOLastfm-cmus +1 -1
- data/bin/LOLastfm-lyrics +22 -0
- data/bin/LOLastfm-now-playing +14 -0
- data/bin/{LOLastfm-do → LOLastfm-send} +20 -6
- data/lib/LOLastfm.rb +48 -17
- data/lib/LOLastfm/checker.rb +8 -4
- data/lib/LOLastfm/checkers/cmus.rb +19 -9
- data/lib/LOLastfm/checkers/moc.rb +60 -34
- data/lib/LOLastfm/commands/glyr.rb +21 -6
- data/lib/LOLastfm/connection.rb +5 -1
- data/lib/LOLastfm/song.rb +2 -0
- data/lib/LOLastfm/version.rb +1 -1
- metadata +8 -20
data/LOLastfm.gemspec
CHANGED
data/README.md
CHANGED
@@ -1,2 +1,51 @@
|
|
1
|
-
LOLastfm -
|
2
|
-
|
1
|
+
LOLastfm - LOL a scrobbler
|
2
|
+
==========================
|
3
|
+
LOLastfm is a modular and extensible last.fm scrobbler.
|
4
|
+
|
5
|
+
It supports a virtually infinite array of music players and has a cool server-client
|
6
|
+
interface that lets you manage music related features seamlessly.
|
7
|
+
|
8
|
+
For instance, you can ask it the current playing song without having to relay on client specific
|
9
|
+
shims, or by including the glyr extension you can ask it to give you the lyrics of the currently
|
10
|
+
playing song.
|
11
|
+
|
12
|
+
How to configure
|
13
|
+
----------------
|
14
|
+
Before being able to use LOLastfm you have to allow access to it on last.fm, just run `LOLastfm -a`
|
15
|
+
and follow what it says, then create a file at `~/.LOLastfm/config` and put the session id it gave you
|
16
|
+
back.
|
17
|
+
|
18
|
+
You have to then tell LOLastfm what music player you want to be used, you can do it dynamically with
|
19
|
+
`LOLastfm-do --use player:path'.
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
session 'heregoesthesession'
|
23
|
+
|
24
|
+
use :moc
|
25
|
+
```
|
26
|
+
|
27
|
+
The example above is if you're using moc.
|
28
|
+
|
29
|
+
You can also hook to certain events to, for example, change the attributes of a song before it's sent.
|
30
|
+
|
31
|
+
This allows for some neat features, like easily scrobbling from a radio, the following example shows
|
32
|
+
how to scrobble songs from trance.fm.
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
%w(listened love now_playing).each {|name|
|
36
|
+
on name do |song|
|
37
|
+
next if song.artist || !song.stream?
|
38
|
+
|
39
|
+
if song.comment && song.comment.include?('trance.fm')
|
40
|
+
next :stop if song.title.include?('trance.fm') || song.title.start_with?('Trance - FM-')
|
41
|
+
|
42
|
+
song.artist, song.title = song.title.split(/ - /, 2)
|
43
|
+
song.length = 60 * 1337
|
44
|
+
|
45
|
+
next
|
46
|
+
end
|
47
|
+
|
48
|
+
:stop
|
49
|
+
end
|
50
|
+
}
|
51
|
+
```
|
data/bin/LOLastfm
CHANGED
data/bin/LOLastfm-cmus
CHANGED
@@ -4,7 +4,7 @@ require 'json'
|
|
4
4
|
|
5
5
|
args = Hash[*ARGV]
|
6
6
|
|
7
|
-
UNIXSocket.new(File.expand_path('~/.LOLastfm
|
7
|
+
UNIXSocket.new(File.expand_path('~/.LOLastfm/socket')).tap {|socket|
|
8
8
|
if args['url']
|
9
9
|
socket.puts [:hint, [:stream, args['title'], args['comment']]].to_json
|
10
10
|
end
|
data/bin/LOLastfm-lyrics
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'json'
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
socket = UNIXSocket.new(File.expand_path(ARGV.empty? ? '~/.LOLastfm/socket' : ARGV.first))
|
6
|
+
socket.puts [:commands, :glyr].to_json
|
7
|
+
|
8
|
+
if STDOUT.tty?
|
9
|
+
require 'ncursesw'
|
10
|
+
|
11
|
+
abort 'ncurses UI not implemented yet, redirect the output to something'
|
12
|
+
else
|
13
|
+
socket.puts [:lyrics?].to_json
|
14
|
+
|
15
|
+
response = JSON.parse(socket.readline)
|
16
|
+
|
17
|
+
if response.first
|
18
|
+
puts response.first['data']
|
19
|
+
else
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'json'
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
socket = UNIXSocket.new(File.expand_path(ARGV.empty? ? '~/.LOLastfm/socket' : ARGV.first))
|
6
|
+
socket.puts [:now_playing?].to_json
|
7
|
+
|
8
|
+
response = JSON.parse(?[ + socket.readline + ?]).first
|
9
|
+
|
10
|
+
exit 1 if response.nil?
|
11
|
+
|
12
|
+
%w[track title artist album].each {|name|
|
13
|
+
puts "#{name} #{response[name]}" if response[name]
|
14
|
+
}
|
@@ -6,7 +6,7 @@ require 'json'
|
|
6
6
|
options = {}
|
7
7
|
|
8
8
|
OptionParser.new do |o|
|
9
|
-
options[:socket] = '~/.LOLastfm
|
9
|
+
options[:socket] = '~/.LOLastfm/socket'
|
10
10
|
options[:song] = {}
|
11
11
|
|
12
12
|
o.on '--listened', 'enable listened sending' do
|
@@ -48,6 +48,14 @@ OptionParser.new do |o|
|
|
48
48
|
o.on '-i', '--id ID', 'the MusicBrainz id of the song' do |value|
|
49
49
|
options[:song][:id] = value
|
50
50
|
end
|
51
|
+
|
52
|
+
o.on '-u', '--use USE', 'the string for the checker' do |value|
|
53
|
+
options[:use] = value
|
54
|
+
end
|
55
|
+
|
56
|
+
o.on '-u', '--commands COMMANDS', 'the string for the command library' do |value|
|
57
|
+
options[:commands] = value
|
58
|
+
end
|
51
59
|
end.parse!
|
52
60
|
|
53
61
|
if ARGV.first
|
@@ -56,12 +64,18 @@ end
|
|
56
64
|
|
57
65
|
socket = UNIXSocket.new(File.expand_path(options[:socket]))
|
58
66
|
|
59
|
-
if options[:
|
60
|
-
socket.puts [:
|
61
|
-
elsif options[:
|
62
|
-
socket.puts [:
|
67
|
+
if options[:use]
|
68
|
+
socket.puts [:use, options[:use].split(':')].to_json
|
69
|
+
elsif options[:commands]
|
70
|
+
socket.puts [:commands, options[:commands].split(':')].to_json
|
63
71
|
else
|
64
|
-
|
72
|
+
if options[:now_playing]
|
73
|
+
socket.puts [:now_playing, options[:song]].to_json
|
74
|
+
elsif options[:love]
|
75
|
+
socket.puts [:love, options[:song].empty? ? nil : options[:song]].to_json
|
76
|
+
else
|
77
|
+
socket.puts [:listened, options[:song]].to_json
|
78
|
+
end
|
65
79
|
end
|
66
80
|
|
67
81
|
socket.flush
|
data/lib/LOLastfm.rb
CHANGED
@@ -10,7 +10,6 @@
|
|
10
10
|
|
11
11
|
require 'eventmachine'
|
12
12
|
require 'lastfm'
|
13
|
-
require 'call-me/memoize'
|
14
13
|
|
15
14
|
class LOLastfm
|
16
15
|
def self.load (path)
|
@@ -33,31 +32,45 @@ class LOLastfm
|
|
33
32
|
commands[name.to_sym.downcase] = block
|
34
33
|
end
|
35
34
|
|
36
|
-
attr_reader :cache
|
35
|
+
attr_reader :path, :host, :port, :cache
|
37
36
|
|
38
37
|
def initialize
|
39
38
|
@session = Lastfm.new('5f7b134ba19b20536a5e29bc86ae64c9', '3b50e74d989795c3f4b3667c5a1c8e67')
|
40
39
|
@cache = Cache.new(self)
|
41
40
|
@events = Hash.new { |h, k| h[k] = [] }
|
42
41
|
|
43
|
-
cache_at '~/.LOLastfm
|
42
|
+
cache_at '~/.LOLastfm/cache'
|
44
43
|
end
|
45
44
|
|
46
45
|
def load (path)
|
47
46
|
instance_eval File.read(File.expand_path(path)), path
|
48
47
|
end
|
49
48
|
|
49
|
+
def started?; !!@started; end
|
50
|
+
|
50
51
|
def start
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
return if started?
|
53
|
+
|
54
|
+
@server = if @host && @port
|
55
|
+
EM.start_server(host, port, LOLastfm::Connection) {|conn|
|
56
|
+
conn.fm = self
|
57
|
+
}
|
58
|
+
else
|
59
|
+
EM.start_unix_domain_server(path || File.expand_path('~/.LOLastfm/socket'), LOLastfm::Connection) {|conn|
|
60
|
+
conn.fm = self
|
61
|
+
}
|
62
|
+
end
|
54
63
|
|
55
64
|
@timer = EM.add_periodic_timer 360 do
|
56
65
|
save
|
57
66
|
end
|
67
|
+
|
68
|
+
@checker.start
|
58
69
|
end
|
59
70
|
|
60
71
|
def stop
|
72
|
+
return unless started?
|
73
|
+
|
61
74
|
EM.stop_server @server
|
62
75
|
EM.cancel_timer @timer
|
63
76
|
|
@@ -82,8 +95,13 @@ class LOLastfm
|
|
82
95
|
end
|
83
96
|
end
|
84
97
|
|
85
|
-
def
|
86
|
-
|
98
|
+
def server_at (host, port = nil)
|
99
|
+
if port
|
100
|
+
@host = host
|
101
|
+
@port = port
|
102
|
+
else
|
103
|
+
@path = host
|
104
|
+
end
|
87
105
|
end
|
88
106
|
|
89
107
|
def session (key)
|
@@ -96,6 +114,7 @@ class LOLastfm
|
|
96
114
|
|
97
115
|
def now_playing (song)
|
98
116
|
song = Song.new(song) unless song.is_a?(Song)
|
117
|
+
song = song.dup
|
99
118
|
|
100
119
|
return false unless fire :now_playing, song
|
101
120
|
|
@@ -112,6 +131,7 @@ class LOLastfm
|
|
112
131
|
|
113
132
|
def listened (song)
|
114
133
|
song = Song.new(song) unless song.is_a?(Song)
|
134
|
+
song = song.dup
|
115
135
|
|
116
136
|
return false unless fire :listened, song
|
117
137
|
|
@@ -138,6 +158,7 @@ class LOLastfm
|
|
138
158
|
def love (song = nil)
|
139
159
|
song = @last_played or return unless song
|
140
160
|
song = Song.new(song) unless song.is_a? Song
|
161
|
+
song = song.dup
|
141
162
|
|
142
163
|
return false unless fire :love, song
|
143
164
|
|
@@ -168,16 +189,26 @@ class LOLastfm
|
|
168
189
|
@last_played
|
169
190
|
end
|
170
191
|
|
171
|
-
def
|
172
|
-
|
173
|
-
|
192
|
+
def commands (name)
|
193
|
+
begin
|
194
|
+
require "LOLastfm/commands/#{name}"
|
195
|
+
rescue LoadError
|
196
|
+
require name.to_s
|
174
197
|
end
|
198
|
+
end
|
175
199
|
|
176
|
-
|
200
|
+
def use (*args, &block)
|
201
|
+
return if args.empty? && !block
|
202
|
+
|
203
|
+
unless args.first.respond_to?(:to_hash) || block
|
177
204
|
name = args.shift.to_sym
|
178
205
|
|
179
|
-
if args.first.is_a?
|
180
|
-
require args.
|
206
|
+
if args.first.is_a? String
|
207
|
+
require args.pop
|
208
|
+
elsif !self.class.checkers[name]
|
209
|
+
begin
|
210
|
+
require "LOLastfm/checkers/#{name}"
|
211
|
+
rescue LoadError; end
|
181
212
|
end
|
182
213
|
|
183
214
|
block = self.class.checkers[name]
|
@@ -187,9 +218,9 @@ class LOLastfm
|
|
187
218
|
@checker.stop
|
188
219
|
end
|
189
220
|
|
190
|
-
@checker = Checker.new(self, name, args.shift, &block)
|
191
|
-
|
192
|
-
|
221
|
+
@checker = Checker.new(self, name, args.shift, &block).tap {|c|
|
222
|
+
c.start if started?
|
223
|
+
}
|
193
224
|
end
|
194
225
|
|
195
226
|
def hint (*args)
|
data/lib/LOLastfm/checker.rb
CHANGED
@@ -62,17 +62,21 @@ class Checker
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def stop (&block)
|
65
|
-
@timers.each {|timer|
|
66
|
-
clear_timeout(timer)
|
67
|
-
}
|
68
|
-
|
69
65
|
if block
|
70
66
|
@stop_block = block
|
71
67
|
else
|
68
|
+
@stopped = true
|
69
|
+
|
70
|
+
@timers.each {|timer|
|
71
|
+
clear_timeout(timer)
|
72
|
+
}
|
73
|
+
|
72
74
|
@stop_block.call if @stop_block
|
73
75
|
end
|
74
76
|
end
|
75
77
|
|
78
|
+
def stopped?; !!@stopped; end
|
79
|
+
|
76
80
|
def hint (*args, &block)
|
77
81
|
if block
|
78
82
|
@hint_block = block
|
@@ -11,7 +11,6 @@
|
|
11
11
|
require 'cmus'
|
12
12
|
|
13
13
|
class Cmus::Controller::Status
|
14
|
-
memoize
|
15
14
|
def to_song
|
16
15
|
return unless song
|
17
16
|
|
@@ -33,26 +32,37 @@ LOLastfm.define_checker :cmus do
|
|
33
32
|
settings.default[:every] = 5
|
34
33
|
settings.default[:timeout] = 0.005
|
35
34
|
|
36
|
-
@cmus = Cmus::Controller.new(settings[:socket], settings[:timeout])
|
37
|
-
|
35
|
+
if @cmus = Cmus::Controller.new(settings[:socket], settings[:timeout]) rescue false
|
36
|
+
@last = @cmus.status
|
38
37
|
|
39
|
-
|
40
|
-
|
38
|
+
if @last == :play
|
39
|
+
now_playing @last.to_song
|
40
|
+
end
|
41
41
|
end
|
42
42
|
|
43
43
|
set_interval settings[:every] do
|
44
|
+
unless @cmus
|
45
|
+
@cmus = Cmus::Controller.new(settings[:socket], settings[:timeout]) rescue next
|
46
|
+
@last = @cmus.status
|
47
|
+
end
|
48
|
+
|
49
|
+
unless status = @cmus.status rescue nil
|
50
|
+
@cmus = nil
|
51
|
+
next
|
52
|
+
end
|
53
|
+
|
44
54
|
status = @cmus.status
|
45
55
|
|
46
56
|
if status == :stop
|
47
|
-
if @last != :stop && LOLastfm::Song.is_scrobblable?(@last.song.position, @last.song.duration)
|
57
|
+
if @last != :stop && (@last.to_song.stream? || LOLastfm::Song.is_scrobblable?(@last.song.position, @last.song.duration))
|
48
58
|
listened @last.to_song
|
49
|
-
else
|
50
|
-
stopped_playing!
|
51
59
|
end
|
60
|
+
|
61
|
+
stopped_playing!
|
52
62
|
elsif status == :pause
|
53
63
|
stopped_playing!
|
54
64
|
else
|
55
|
-
if @last != :stop && (@last.to_song != status.to_song || @last.song.position > status.song.position) && LOLastfm::Song.is_scrobblable?(@last.song.position, @last.song.duration)
|
65
|
+
if @last != :stop && (@last.to_song != status.to_song || @last.song.position > status.song.position + 30) && (@last.to_song.stream? || LOLastfm::Song.is_scrobblable?(@last.song.position, @last.song.duration))
|
56
66
|
listened @last.to_song
|
57
67
|
end
|
58
68
|
|
@@ -10,23 +10,25 @@
|
|
10
10
|
|
11
11
|
require 'moc'
|
12
12
|
|
13
|
-
class Moc::Controller::Status
|
14
|
-
memoize
|
13
|
+
class Moc::Controller::Status::Live
|
15
14
|
def to_song
|
16
15
|
return unless song
|
17
16
|
|
18
|
-
|
19
|
-
|
17
|
+
file = song.file
|
18
|
+
tags = song.tags
|
19
|
+
|
20
|
+
if file.start_with?('http://') || file.start_with?('ftp://')
|
21
|
+
comment = file
|
20
22
|
else
|
21
|
-
path =
|
23
|
+
path = file
|
22
24
|
end
|
23
25
|
|
24
26
|
LOLastfm::Song.new(true,
|
25
|
-
track:
|
26
|
-
title:
|
27
|
-
artist:
|
28
|
-
album:
|
29
|
-
length:
|
27
|
+
track: tags.track,
|
28
|
+
title: tags.title,
|
29
|
+
artist: tags.artist,
|
30
|
+
album: tags.album,
|
31
|
+
length: tags.time,
|
30
32
|
comment: comment,
|
31
33
|
path: path,
|
32
34
|
stream: !!comment
|
@@ -38,34 +40,58 @@ LOLastfm.define_checker :moc do
|
|
38
40
|
settings.default[:socket] = '~/.moc/socket2'
|
39
41
|
settings.default[:every] = 5
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
+
create = proc {
|
44
|
+
unless moc = Moc::Controller.new(settings[:socket]) rescue false
|
45
|
+
set_timeout settings[:every], &create unless stopped?
|
46
|
+
end
|
43
47
|
|
44
|
-
|
45
|
-
|
46
|
-
end
|
48
|
+
Thread.new {
|
49
|
+
song, position = nil
|
47
50
|
|
48
|
-
|
49
|
-
|
51
|
+
begin
|
52
|
+
moc.loop {|e|
|
53
|
+
if e == :audio_stop
|
54
|
+
next unless song
|
50
55
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
if song.stream?
|
57
|
+
listened song
|
58
|
+
else
|
59
|
+
if LOLastfm::Song.is_scrobblable?(position, song.length)
|
60
|
+
listened song
|
61
|
+
else
|
62
|
+
stopped_playing!
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
song = nil
|
67
|
+
elsif e == :tags
|
68
|
+
elsif e == :audio_start
|
69
|
+
now_playing song = moc.status(true).to_song
|
70
|
+
elsif e == :state && moc.status(true) == :paused
|
71
|
+
stopped_playing!
|
72
|
+
elsif e == :ctime
|
73
|
+
unless song
|
74
|
+
now_playing song = moc.status(true).to_song
|
75
|
+
end
|
63
76
|
|
64
|
-
|
65
|
-
|
77
|
+
if song.stream?
|
78
|
+
if moc.status(true).song.title != song.title
|
79
|
+
listened song
|
80
|
+
now_playing song = moc.status(true).to_song
|
81
|
+
end
|
82
|
+
else
|
83
|
+
position = moc.status(true).song.position
|
84
|
+
end
|
85
|
+
end
|
86
|
+
}
|
87
|
+
rescue Exception => e
|
88
|
+
$stderr.puts e.message
|
89
|
+
$stderr.puts e.backtrace
|
66
90
|
end
|
67
|
-
end
|
68
91
|
|
69
|
-
|
70
|
-
|
92
|
+
set_timeout settings[:every], &create unless stopped?
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
create.call
|
71
97
|
end
|
@@ -9,19 +9,34 @@
|
|
9
9
|
#++
|
10
10
|
|
11
11
|
require 'glyr'
|
12
|
+
require 'tmpdir'
|
13
|
+
require 'fileutils'
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
module Glyr
|
16
|
+
class Source
|
17
|
+
def to_hash
|
18
|
+
{ name: name, quality: quality, speed: speed, language_aware: language_aware? }
|
19
|
+
end
|
16
20
|
end
|
21
|
+
|
22
|
+
class Result
|
23
|
+
def to_hash
|
24
|
+
{ source: source, url: url, data: data }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
File.join(Dir.tmpdir, rand.to_s).tap {|path|
|
29
|
+
FileUtils.mkpath(path)
|
30
|
+
cache_at path
|
31
|
+
}
|
17
32
|
end
|
18
33
|
|
19
34
|
LOLastfm.define_command :lyrics? do
|
20
35
|
song = now_playing?
|
21
36
|
|
22
37
|
EM.defer -> {
|
23
|
-
Glyr.query
|
24
|
-
}, ->
|
25
|
-
send_line
|
38
|
+
Glyr.query(title: song.title, artist: song.artist, album: song.album).lyrics
|
39
|
+
}, -> results {
|
40
|
+
send_line results.map(&:to_hash).to_json
|
26
41
|
}
|
27
42
|
end
|
data/lib/LOLastfm/connection.rb
CHANGED
@@ -16,6 +16,10 @@ define_command :use do |*args|
|
|
16
16
|
use *args
|
17
17
|
end
|
18
18
|
|
19
|
+
define_command :commands do |*args|
|
20
|
+
commands *args
|
21
|
+
end
|
22
|
+
|
19
23
|
define_command :listened do |song|
|
20
24
|
listened song
|
21
25
|
end
|
@@ -55,7 +59,7 @@ class Connection < EventMachine::Protocols::LineAndTextProtocol
|
|
55
59
|
command, arguments = JSON.parse(line)
|
56
60
|
|
57
61
|
if block = LOLastfm.commands[command.to_sym.downcase]
|
58
|
-
|
62
|
+
instance_exec *arguments, &block
|
59
63
|
end
|
60
64
|
rescue => e
|
61
65
|
$stderr.puts e.to_s
|
data/lib/LOLastfm/song.rb
CHANGED
data/lib/LOLastfm/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: LOLastfm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: lastfm
|
@@ -43,28 +43,14 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
-
- !ruby/object:Gem::Dependency
|
47
|
-
name: call-me
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
|
-
requirements:
|
51
|
-
- - ! '>='
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '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'
|
62
46
|
description:
|
63
47
|
email: meh@paranoici.org
|
64
48
|
executables:
|
65
49
|
- LOLastfm
|
66
50
|
- LOLastfm-cmus
|
67
|
-
- LOLastfm-
|
51
|
+
- LOLastfm-lyrics
|
52
|
+
- LOLastfm-now-playing
|
53
|
+
- LOLastfm-send
|
68
54
|
extensions: []
|
69
55
|
extra_rdoc_files: []
|
70
56
|
files:
|
@@ -72,7 +58,9 @@ files:
|
|
72
58
|
- README.md
|
73
59
|
- bin/LOLastfm
|
74
60
|
- bin/LOLastfm-cmus
|
75
|
-
- bin/LOLastfm-
|
61
|
+
- bin/LOLastfm-lyrics
|
62
|
+
- bin/LOLastfm-now-playing
|
63
|
+
- bin/LOLastfm-send
|
76
64
|
- lib/LOLastfm.rb
|
77
65
|
- lib/LOLastfm/cache.rb
|
78
66
|
- lib/LOLastfm/checker.rb
|