kagu 0.3.3 → 0.4.0
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.
- checksums.yaml +4 -4
- data/README.mdown +29 -12
- data/VERSION +1 -1
- data/kagu.gemspec +2 -2
- data/lib/kagu/finder.rb +123 -0
- data/lib/kagu/library.rb +4 -0
- data/lib/kagu.rb +1 -0
- data/spec/kagu/finder_spec.rb +241 -0
- data/spec/kagu/library_spec.rb +12 -0
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc8ff8418f368b1c12f3d2f8b01d6af8e7d7a3a6
|
4
|
+
data.tar.gz: e7be4e6197998c38421f7208d0c84a898c83b6e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7a69aeed895d34f70b4cda33304f48cd284a81105b79d772c7c1e3e1fe3d472110aad768241edbe2c651486f494d851e7380d60cc5b7c70ad2e9ecabfbc8bdb
|
7
|
+
data.tar.gz: eb07e916b94813b67ed2872bc94897bacaf06873b25df46b71bdeddebcca8c586dc22d335833d71222e5c7b0678e375cd0dc445334ff8690a563965fe3479def
|
data/README.mdown
CHANGED
@@ -6,7 +6,9 @@ Ruby API to manage iTunes tracks and playlists.
|
|
6
6
|
|
7
7
|
Just add this into your `Gemfile`:
|
8
8
|
|
9
|
-
|
9
|
+
```ruby
|
10
|
+
gem 'kagu'
|
11
|
+
```
|
10
12
|
|
11
13
|
Then, just run `bundle install`.
|
12
14
|
|
@@ -14,26 +16,41 @@ Then, just run `bundle install`.
|
|
14
16
|
|
15
17
|
### Displaying all tracks artist
|
16
18
|
|
17
|
-
|
19
|
+
```ruby
|
20
|
+
library = Kagu::Library.new
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
+
library.tracks.each do |track|
|
23
|
+
puts track.artist
|
24
|
+
end
|
25
|
+
```
|
22
26
|
|
23
27
|
### Displaying all playlists and its tracks count
|
24
28
|
|
25
|
-
|
29
|
+
```ruby
|
30
|
+
library = Kagu::Library.new
|
26
31
|
|
27
|
-
|
28
|
-
|
29
|
-
|
32
|
+
library.playlists.each do |playlist|
|
33
|
+
puts "#{playlist.name}: #{playlist.tracks.count}"
|
34
|
+
end
|
35
|
+
```
|
30
36
|
|
31
37
|
### Creating a playlist
|
32
38
|
|
33
|
-
|
39
|
+
```ruby
|
40
|
+
library = Kagu::Library.new
|
34
41
|
|
35
|
-
|
36
|
-
|
42
|
+
tracks = library.tracks.select { |track| track.genre == 'Drum & Bass' && track.added_at > 1.week.ago }
|
43
|
+
library.playlists.create(name: 'Recent - D&B', tracks: tracks)
|
44
|
+
```
|
45
|
+
|
46
|
+
### Finding some tracks
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
library = Kagu::Library.new
|
50
|
+
library.finder.find(artist: 'Serial Killaz', title: 'Walk and Skank').each do
|
51
|
+
puts track.id
|
52
|
+
end
|
53
|
+
```
|
37
54
|
|
38
55
|
## Executing test suite
|
39
56
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/kagu.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.add_dependency 'applescript', '>= 1.0', '< 2.0'
|
21
21
|
s.add_dependency 'htmlentities', '>= 4.3.0', '< 4.4.0'
|
22
22
|
|
23
|
-
s.add_development_dependency 'byebug', '>= 3.2.0', '<
|
23
|
+
s.add_development_dependency 'byebug', '>= 3.2.0', '< 7.0.0'
|
24
24
|
s.add_development_dependency 'rake', '>= 10.3.0', '< 10.5.0'
|
25
|
-
s.add_development_dependency 'rspec', '>= 3.1.0', '< 3.
|
25
|
+
s.add_development_dependency 'rspec', '>= 3.1.0', '< 3.4.0'
|
26
26
|
end
|
data/lib/kagu/finder.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
module Kagu
|
2
|
+
|
3
|
+
class Finder
|
4
|
+
|
5
|
+
MANDATORY_ATTRIBUTES = []
|
6
|
+
|
7
|
+
attr_reader :library
|
8
|
+
|
9
|
+
delegate :replace, :transliterate, to: 'self.class'
|
10
|
+
|
11
|
+
def self.replace(value, replacements = {})
|
12
|
+
replaced = value.to_s.dup
|
13
|
+
replacements.each do |pattern, replacement|
|
14
|
+
replaced.gsub!(pattern, replacement)
|
15
|
+
end
|
16
|
+
replaced.presence
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.transliterate(value)
|
20
|
+
ActiveSupport::Inflector.transliterate(value.to_s).squish.downcase.presence
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(library, options = {})
|
24
|
+
raise ArgumentError.new("#{self.class}#library must be a library, #{library.inspect} given") unless library.is_a?(Library)
|
25
|
+
@library = library
|
26
|
+
reload(options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def find(attributes = {})
|
30
|
+
attributes.stringify_keys!
|
31
|
+
results = [].tap do |matches|
|
32
|
+
tracks_digests.each_with_index do |hash, digests_index|
|
33
|
+
digests(attributes).each_with_index do |digest, digest_index|
|
34
|
+
tracks = hash[digest].presence || next
|
35
|
+
tracks = tracks.select { |track| !matches.any? { |match| match.include?(track) } }
|
36
|
+
next if tracks.empty?
|
37
|
+
index = [digests_index, digest_index].max
|
38
|
+
matches[index] ||= []
|
39
|
+
matches[index].push(*tracks)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
results.compact!
|
44
|
+
replacements.any? ? results : results.flatten
|
45
|
+
end
|
46
|
+
|
47
|
+
def ignored
|
48
|
+
@ignored ||= []
|
49
|
+
end
|
50
|
+
|
51
|
+
def reload(options = {})
|
52
|
+
@ignored = nil
|
53
|
+
@replacements = nil
|
54
|
+
@tracks_digests = nil
|
55
|
+
options.each do |name, value|
|
56
|
+
send("#{name}=", value) if respond_to?("#{name}=", true)
|
57
|
+
end
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def replacements
|
62
|
+
@replacements ||= []
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def digests(attributes)
|
68
|
+
attributes.stringify_keys!
|
69
|
+
return [] if attributes['artist'].blank? || attributes['title'].blank?
|
70
|
+
digests = [transliterate("#{attributes['artist']} #{attributes['title']}")]
|
71
|
+
replacements.each do |item|
|
72
|
+
digests << replace(digests.last, item)
|
73
|
+
end
|
74
|
+
digests.uniq
|
75
|
+
end
|
76
|
+
|
77
|
+
def ignored=(values)
|
78
|
+
@ignored = [values].flatten.map do |value|
|
79
|
+
if value.is_a?(Hash)
|
80
|
+
value = value.stringify_keys
|
81
|
+
value = "#{value['artist']} #{value['title']}"
|
82
|
+
elsif value.is_a?(Track)
|
83
|
+
value = "#{value.artist} #{value.title}"
|
84
|
+
else
|
85
|
+
value = value.to_s
|
86
|
+
end
|
87
|
+
self.class.transliterate(value)
|
88
|
+
end.compact.uniq
|
89
|
+
end
|
90
|
+
|
91
|
+
def replacements=(value)
|
92
|
+
if value.nil?
|
93
|
+
@replacements = []
|
94
|
+
elsif value.is_a?(Hash)
|
95
|
+
@replacements = [value]
|
96
|
+
elsif value.is_a?(Array)
|
97
|
+
@replacements = value
|
98
|
+
else
|
99
|
+
raise("Replacements must be an array or a hash, #{value.inspect} given")
|
100
|
+
end
|
101
|
+
replacements.each do |item|
|
102
|
+
raise('Replacements must contain only hashes') unless item.is_a?(Hash)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def tracks_digests
|
107
|
+
@tracks_digests ||= begin
|
108
|
+
[].tap do |tracks_digests|
|
109
|
+
library.tracks.each do |track|
|
110
|
+
digests(artist: track.artist, title: track.title).each_with_index do |digest, index|
|
111
|
+
next if ignored.include?(digest)
|
112
|
+
tracks_digests[index] ||= {}
|
113
|
+
tracks_digests[index][digest] ||= []
|
114
|
+
tracks_digests[index][digest].push(track)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
data/lib/kagu/library.rb
CHANGED
data/lib/kagu.rb
CHANGED
@@ -0,0 +1,241 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kagu::Finder do
|
4
|
+
|
5
|
+
let(:finder) { Kagu::Finder.new(library) }
|
6
|
+
let(:library) { Kagu::Library.new }
|
7
|
+
|
8
|
+
describe '.replace' do
|
9
|
+
|
10
|
+
it 'replace given value with replacements' do
|
11
|
+
expect(Kagu::Finder.replace('Hello World!', 'World' => 'John', 'Hello' => 'Bye')).to eq('Bye John!')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'is case sensitive' do
|
15
|
+
expect(Kagu::Finder.replace('Hello World!', 'world' => 'John', 'Hello' => 'Bye')).to eq('Bye World!')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'replace given value with some regexp' do
|
19
|
+
expect(Kagu::Finder.replace('Hello World!', 'World' => 'John', /l+/ => 'i')).to eq('Heio John!')
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns nil if blank' do
|
23
|
+
expect(Kagu::Finder.replace(' ', 'world' => 'John', 'Hello' => 'Bye')).to be_nil
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '.transliterate' do
|
29
|
+
|
30
|
+
it 'removes accents' do
|
31
|
+
expect(Kagu::Finder.transliterate('éàlôrs')).to eq('ealors')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'removes consecutive white spaces' do
|
35
|
+
expect(Kagu::Finder.transliterate(" hello \t world\n ")).to eq('hello world')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'converts value to lower case' do
|
39
|
+
expect(Kagu::Finder.transliterate('Hello World')).to eq('hello world')
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'removes nil if blank' do
|
43
|
+
expect(Kagu::Finder.transliterate(' ')).to be_nil
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#find' do
|
49
|
+
|
50
|
+
it 'returns some tracks' do
|
51
|
+
tracks = finder.find(artist: 'korn', title: 'blind')
|
52
|
+
expect(tracks).to be_an(Array)
|
53
|
+
expect(tracks.first).to be_a(Kagu::Track)
|
54
|
+
expect(tracks.first.title).to match(/blind/i)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns nothing if artist is blank' do
|
58
|
+
expect(finder.find(title: 'blind')).to be_empty
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns nothing if title is blank' do
|
62
|
+
expect(finder.find(artist: 'korn')).to be_empty
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns nothing if artist match an artist and a track' do
|
66
|
+
expect(finder.find(artist: 'korn blind')).to be_empty
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'artist and title can be specified as string' do
|
70
|
+
expect(finder.find('artist' => 'KoRn', 'title' => 'Ball Tongue').first).to be_a(Kagu::Track)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'returns an array of array of tracks if there is some replacements' do
|
74
|
+
finder.reload(replacements: { 'ball tongue' => 'blind' })
|
75
|
+
results = finder.find(artist: 'korn', title: 'blind')
|
76
|
+
expect(results.size).to eq(2)
|
77
|
+
expect(results.first).to be_an(Array)
|
78
|
+
expect(results.first.first.title).to match(/blind/i)
|
79
|
+
expect(results.second.first.title).to match(/ball tongue/i)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'replacements are working with given attributes' do
|
83
|
+
finder.reload(replacements: { 'hello world' => 'blind' })
|
84
|
+
results = finder.find(artist: 'korn', title: 'hello world')
|
85
|
+
expect(results.size).to eq(1)
|
86
|
+
expect(results.first.first).to be_a(Kagu::Track)
|
87
|
+
expect(results.first.first.title).to match(/blind/i)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'put at first position the exact matches from given attributes' do
|
91
|
+
finder.reload(replacements: { 'ball tongue' => 'blind' })
|
92
|
+
results = finder.find(artist: 'korn', title: 'ball tongue')
|
93
|
+
expect(results.size).to eq(2)
|
94
|
+
|
95
|
+
expect(results.first).not_to be_empty
|
96
|
+
results.first.each do |track|
|
97
|
+
expect(track.title).to match(/ball tongue/i)
|
98
|
+
end
|
99
|
+
|
100
|
+
expect(results.second).not_to be_empty
|
101
|
+
results.second.each do |track|
|
102
|
+
expect(track.title).to match(/blind/i)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'does not include ignored tracks' do
|
107
|
+
expect {
|
108
|
+
finder.reload(ignored: 'korn blind')
|
109
|
+
}.to change { finder.find(artist: 'korn', title: 'blind').size }.to(0)
|
110
|
+
expect(finder.find(artist: 'korn', title: 'ball tongue')).not_to be_empty
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#ignored' do
|
116
|
+
|
117
|
+
it 'can be set as an array of string' do
|
118
|
+
expect {
|
119
|
+
finder.reload(ignored: ['test', 'foo'])
|
120
|
+
}.to change { finder.ignored }.from([]).to(['test', 'foo'])
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'can be set as a simple string' do
|
124
|
+
expect {
|
125
|
+
finder.reload(ignored: 'test')
|
126
|
+
}.to change { finder.ignored }.from([]).to(['test'])
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'is transliterated' do
|
130
|
+
expect {
|
131
|
+
finder.reload(ignored: ['testé HeLLo World', 'foo'])
|
132
|
+
}.to change { finder.ignored }.from([]).to(['teste hello world', 'foo'])
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'can be set from a track' do
|
136
|
+
expect {
|
137
|
+
finder.reload(ignored: [finder.find(artist: 'KoRn', title: 'Blind').first])
|
138
|
+
}.to change { finder.ignored }.from([]).to(['korn blind'])
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'can be set from an hash (as string keys)' do
|
142
|
+
expect {
|
143
|
+
finder.reload(ignored: { 'artist' => 'KoRn', 'title' => 'Blind' })
|
144
|
+
}.to change { finder.ignored }.from([]).to(['korn blind'])
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'can be set from an hash (with symbol keys)' do
|
148
|
+
expect {
|
149
|
+
finder.reload(ignored: { artist: 'KoRn', title: 'Blind' })
|
150
|
+
}.to change { finder.ignored }.from([]).to(['korn blind'])
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'removes duplicates' do
|
154
|
+
expect {
|
155
|
+
finder.reload(ignored: ['test', 'Foo ', 'foo', 'TEST'])
|
156
|
+
}.to change { finder.ignored }.from([]).to(['test', 'foo'])
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
describe '#library' do
|
162
|
+
|
163
|
+
it 'is library given at initialization' do
|
164
|
+
expect(finder.library).to be(library)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'raise an error if library is nil' do
|
168
|
+
expect {
|
169
|
+
Kagu::Finder.new(nil)
|
170
|
+
}.to raise_error(ArgumentError, 'Kagu::Finder#library must be a library, nil given')
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '#reload' do
|
176
|
+
|
177
|
+
it 'sets replacements' do
|
178
|
+
expect {
|
179
|
+
finder.reload(replacements: { 'foo' => 'bar' })
|
180
|
+
}.to change { finder.replacements }.from([]).to([{ 'foo' => 'bar' }])
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'removes replacements' do
|
184
|
+
finder.reload(replacements: { 'foo' => 'bar' })
|
185
|
+
expect {
|
186
|
+
finder.reload
|
187
|
+
}.to change { finder.replacements }.to([])
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'removes ignored' do
|
191
|
+
finder.reload(ignored: 'foo')
|
192
|
+
expect {
|
193
|
+
finder.reload
|
194
|
+
}.to change { finder.ignored }.to([])
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'returns finder' do
|
198
|
+
expect(finder.reload).to be(finder)
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'reload tracks' do
|
202
|
+
expect {
|
203
|
+
finder.reload(replacements: { /\./ => '' })
|
204
|
+
}.to change { finder.find(artist: 'korn', title: 'adidas').present? }.from(false).to(true)
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
describe '#replacements' do
|
210
|
+
|
211
|
+
it 'can be ommited' do
|
212
|
+
expect(finder.reload.replacements).to eq([])
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'can be specified with a string as key' do
|
216
|
+
expect(finder.reload('replacements' => { 'foo' => 'bar' }).replacements).to eq([{ 'foo' => 'bar' }])
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'can be specified as hash' do
|
220
|
+
expect(finder.reload(replacements: { 'foo' => 'bar' }).replacements).to eq([{ 'foo' => 'bar' }])
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'can be specified as array of hashes' do
|
224
|
+
expect(finder.reload(replacements: [{ 'foo' => 'bar' }, { 'titi' => 'toto' }]).replacements).to eq([{ 'foo' => 'bar' }, { 'titi' => 'toto' }])
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'raise an error if a string is given' do
|
228
|
+
expect {
|
229
|
+
finder.reload(replacements: 'foo')
|
230
|
+
}.to raise_error('Replacements must be an array or a hash, "foo" given')
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'raise an error if it contains something else than an hash' do
|
234
|
+
expect {
|
235
|
+
finder.reload(replacements: [{ 'foo' => 'bar' }, 'titi'])
|
236
|
+
}.to raise_error('Replacements must contain only hashes')
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
data/spec/kagu/library_spec.rb
CHANGED
@@ -24,6 +24,18 @@ describe Kagu::Library do
|
|
24
24
|
|
25
25
|
end
|
26
26
|
|
27
|
+
describe '#finder' do
|
28
|
+
|
29
|
+
it 'returns a Kagu::Finder instance' do
|
30
|
+
expect(library.finder).to be_a(Kagu::Finder)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'options can be specified' do
|
34
|
+
expect(library.finder(replacements: { 'foo' => 'bar' }).replacements).to eq([{ 'foo' => 'bar' }])
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
27
39
|
describe '#playlists' do
|
28
40
|
|
29
41
|
it 'returns a Playlists object' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kagu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexis Toulotte
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -79,7 +79,7 @@ dependencies:
|
|
79
79
|
version: 3.2.0
|
80
80
|
- - "<"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 7.0.0
|
83
83
|
type: :development
|
84
84
|
prerelease: false
|
85
85
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -89,7 +89,7 @@ dependencies:
|
|
89
89
|
version: 3.2.0
|
90
90
|
- - "<"
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version:
|
92
|
+
version: 7.0.0
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
94
|
name: rake
|
95
95
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,7 +119,7 @@ dependencies:
|
|
119
119
|
version: 3.1.0
|
120
120
|
- - "<"
|
121
121
|
- !ruby/object:Gem::Version
|
122
|
-
version: 3.
|
122
|
+
version: 3.4.0
|
123
123
|
type: :development
|
124
124
|
prerelease: false
|
125
125
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -129,7 +129,7 @@ dependencies:
|
|
129
129
|
version: 3.1.0
|
130
130
|
- - "<"
|
131
131
|
- !ruby/object:Gem::Version
|
132
|
-
version: 3.
|
132
|
+
version: 3.4.0
|
133
133
|
description: API to manage iTunes tracks and playlists
|
134
134
|
email: al@alweb.org
|
135
135
|
executables: []
|
@@ -147,12 +147,14 @@ files:
|
|
147
147
|
- lib/kagu.rb
|
148
148
|
- lib/kagu/attributes_initializer.rb
|
149
149
|
- lib/kagu/error.rb
|
150
|
+
- lib/kagu/finder.rb
|
150
151
|
- lib/kagu/library.rb
|
151
152
|
- lib/kagu/playlist.rb
|
152
153
|
- lib/kagu/playlists.rb
|
153
154
|
- lib/kagu/track.rb
|
154
155
|
- lib/kagu/tracks.rb
|
155
156
|
- spec/kagu/error_spec.rb
|
157
|
+
- spec/kagu/finder_spec.rb
|
156
158
|
- spec/kagu/library_spec.rb
|
157
159
|
- spec/kagu/playlist_spec.rb
|
158
160
|
- spec/kagu/playlists_spec.rb
|
@@ -185,6 +187,7 @@ specification_version: 4
|
|
185
187
|
summary: API for iTunes
|
186
188
|
test_files:
|
187
189
|
- spec/kagu/error_spec.rb
|
190
|
+
- spec/kagu/finder_spec.rb
|
188
191
|
- spec/kagu/library_spec.rb
|
189
192
|
- spec/kagu/playlist_spec.rb
|
190
193
|
- spec/kagu/playlists_spec.rb
|