metal_archives 2.1.1 → 2.2.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/.rubocop.yml +3 -0
- data/lib/metal_archives.rb +2 -0
- data/lib/metal_archives/models/band.rb +3 -3
- data/lib/metal_archives/models/release.rb +353 -0
- data/lib/metal_archives/parsers/release.rb +233 -0
- data/lib/metal_archives/version.rb +1 -1
- data/spec/models/release_spec.rb +133 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d67ee1fe72c3fb58bf95f48ee68bda41232857e
|
4
|
+
data.tar.gz: cfa4704bb7020f4176ad6a14de0b979249e11976
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be9295ee982e7600ad2aba6f5a9ae60fdcdcb5db1039e51a76c18a2fedc53e7899e3ee3c068763c171a3a7a232cbca325d3885d07f1598c4852f73ba7c4b5e17
|
7
|
+
data.tar.gz: 7a121ab78954206854de8d73d1131030684864dccc68c53429ddc2054cb6cc836b7014b5f8044778992bcd27317caa2f8da0f6c020c4a7f72ae848fd1b84aa39
|
data/.rubocop.yml
CHANGED
data/lib/metal_archives.rb
CHANGED
@@ -20,11 +20,13 @@ require 'metal_archives/models/base_model'
|
|
20
20
|
require 'metal_archives/models/label'
|
21
21
|
require 'metal_archives/models/artist'
|
22
22
|
require 'metal_archives/models/band'
|
23
|
+
require 'metal_archives/models/release'
|
23
24
|
|
24
25
|
require 'metal_archives/parsers/parser'
|
25
26
|
require 'metal_archives/parsers/label'
|
26
27
|
require 'metal_archives/parsers/artist'
|
27
28
|
require 'metal_archives/parsers/band'
|
29
|
+
require 'metal_archives/parsers/release'
|
28
30
|
|
29
31
|
require 'metal_archives/http_client'
|
30
32
|
|
@@ -291,7 +291,7 @@ module MetalArchives
|
|
291
291
|
# - +:name+: +String+
|
292
292
|
# - +:exact+: +Boolean+
|
293
293
|
# - +:genre+: +String+
|
294
|
-
# - +:country+: +
|
294
|
+
# - +:country+: +ISO3166::Country+
|
295
295
|
# - +:year_formation+: rdoc-ref:Range of rdoc-ref:NilDate
|
296
296
|
# - +:comment+: +String+
|
297
297
|
# - +:status+: see rdoc-ref:Band.status
|
@@ -331,7 +331,7 @@ module MetalArchives
|
|
331
331
|
# - +:name+: +String+
|
332
332
|
# - +:exact+: +Boolean+
|
333
333
|
# - +:genre+: +String+
|
334
|
-
# - +:country+: +
|
334
|
+
# - +:country+: +ISO3166::Country+
|
335
335
|
# - +:year_formation+: rdoc-ref:Range of +Date+
|
336
336
|
# - +:comment+: +String+
|
337
337
|
# - +:status+: see rdoc-ref:Band.status
|
@@ -363,7 +363,7 @@ module MetalArchives
|
|
363
363
|
# - +:name+: +String+
|
364
364
|
# - +:exact+: +Boolean+
|
365
365
|
# - +:genre+: +String+
|
366
|
-
# - +:country+: +
|
366
|
+
# - +:country+: +ISO3166::Country+
|
367
367
|
# - +:year_formation+: rdoc-ref:Range of +Date+
|
368
368
|
# - +:comment+: +String+
|
369
369
|
# - +:status+: see rdoc-ref:Band.status
|
@@ -0,0 +1,353 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
module MetalArchives
|
6
|
+
##
|
7
|
+
# Represents a release
|
8
|
+
#
|
9
|
+
class Release < MetalArchives::BaseModel
|
10
|
+
##
|
11
|
+
# :attr_reader: id
|
12
|
+
#
|
13
|
+
# Returns +Integer+
|
14
|
+
#
|
15
|
+
property :id, :type => Integer
|
16
|
+
|
17
|
+
##
|
18
|
+
# :attr_reader: title
|
19
|
+
#
|
20
|
+
# Returns +String+
|
21
|
+
#
|
22
|
+
# [Raises]
|
23
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
24
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
25
|
+
#
|
26
|
+
property :title
|
27
|
+
|
28
|
+
# TODO: band
|
29
|
+
|
30
|
+
##
|
31
|
+
# :attr_reader: type
|
32
|
+
#
|
33
|
+
# Returns +:full_length+, +:live+, +:demo+, +:single+, +:ep+, +:video+, +:boxed_set+, +:split+, +:compilation+, +:split_video+, +:collaboration+
|
34
|
+
#
|
35
|
+
# [Raises]
|
36
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
37
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
38
|
+
#
|
39
|
+
enum :type, :values => %i[full_length live demo single ep video boxed_set split compilation split_video collaboration]
|
40
|
+
|
41
|
+
##
|
42
|
+
# :attr_reader: date_released
|
43
|
+
#
|
44
|
+
# Returns rdoc-ref:NilDate
|
45
|
+
#
|
46
|
+
# [Raises]
|
47
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
48
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
49
|
+
#
|
50
|
+
property :date_released, :type => NilDate
|
51
|
+
|
52
|
+
##
|
53
|
+
# :attr_reader_: catalog_id
|
54
|
+
#
|
55
|
+
# Return +String+
|
56
|
+
#
|
57
|
+
# [Raises]
|
58
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
59
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
60
|
+
#
|
61
|
+
property :catalog_id
|
62
|
+
|
63
|
+
##
|
64
|
+
# :attr_reader_: version_description
|
65
|
+
#
|
66
|
+
# Return +String+
|
67
|
+
#
|
68
|
+
# [Raises]
|
69
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
70
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
71
|
+
#
|
72
|
+
property :version_description
|
73
|
+
|
74
|
+
# TODO: label
|
75
|
+
|
76
|
+
##
|
77
|
+
# :attr_reader: format
|
78
|
+
#
|
79
|
+
# Returns +:cd+, +:cassette+, +:vinyl+, +:vhs+, +:dvd+, +:digital+, +:blu_ray+, +:other+
|
80
|
+
#
|
81
|
+
# [Raises]
|
82
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
83
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
84
|
+
#
|
85
|
+
property :format
|
86
|
+
|
87
|
+
##
|
88
|
+
# :attr_reader: limitation
|
89
|
+
#
|
90
|
+
# Returns +Integer+
|
91
|
+
#
|
92
|
+
# [Raises]
|
93
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
94
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
95
|
+
#
|
96
|
+
property :limitation
|
97
|
+
|
98
|
+
# TODO: reviews
|
99
|
+
# TODO: songs
|
100
|
+
# TODO: lineup
|
101
|
+
# TODO: other versions
|
102
|
+
# TODO: links
|
103
|
+
|
104
|
+
##
|
105
|
+
# :attr_reader: notes
|
106
|
+
#
|
107
|
+
# Returns raw HTML +String+
|
108
|
+
#
|
109
|
+
# [Raises]
|
110
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
111
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
112
|
+
#
|
113
|
+
property :notes
|
114
|
+
|
115
|
+
protected
|
116
|
+
|
117
|
+
##
|
118
|
+
# Fetch the data and assemble the model
|
119
|
+
#
|
120
|
+
# [Raises]
|
121
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when receiving a status code == 404
|
122
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
123
|
+
#
|
124
|
+
def assemble # :nodoc:
|
125
|
+
## Base attributes
|
126
|
+
url = "#{MetalArchives.config.default_endpoint}albums/view/id/#{id}"
|
127
|
+
response = HTTPClient.get url
|
128
|
+
|
129
|
+
properties = Parsers::Release.parse_html response.body
|
130
|
+
|
131
|
+
properties
|
132
|
+
end
|
133
|
+
|
134
|
+
class << self
|
135
|
+
##
|
136
|
+
# Find by ID
|
137
|
+
#
|
138
|
+
# Returns rdoc-ref:Release, even when ID is invalid (because the data is lazily fetched)
|
139
|
+
#
|
140
|
+
# [+id+]
|
141
|
+
# +Integer+
|
142
|
+
#
|
143
|
+
def find(id)
|
144
|
+
return cache[id] if cache.include? id
|
145
|
+
|
146
|
+
Release.new :id => id
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Find by ID (no lazy loading)
|
151
|
+
#
|
152
|
+
# Returns rdoc-ref:Release
|
153
|
+
#
|
154
|
+
# [Raises]
|
155
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
156
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
157
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
158
|
+
#
|
159
|
+
# [+id+]
|
160
|
+
# +Integer+
|
161
|
+
#
|
162
|
+
def find!(id)
|
163
|
+
obj = find id
|
164
|
+
obj.load! if obj && !obj.loaded?
|
165
|
+
|
166
|
+
obj
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Find by attributes
|
171
|
+
#
|
172
|
+
# Refer to {MA's FAQ}[http://www.metal-archives.com/content/help?index=3#tab_db] for search tips.
|
173
|
+
#
|
174
|
+
# Returns rdoc-ref:Release or nil when no results
|
175
|
+
#
|
176
|
+
# [Raises]
|
177
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400
|
178
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
179
|
+
#
|
180
|
+
# [+query+]
|
181
|
+
# Hash containing one or more of the following keys:
|
182
|
+
# - +:band_name+: +String+
|
183
|
+
# - +:title+: +String+
|
184
|
+
# - +:from_year+: +Integer+
|
185
|
+
# - +:from_month+: +Integer+
|
186
|
+
# - +:to_year+: +Integer+
|
187
|
+
# - +:to_month+: +Integer+
|
188
|
+
# - +:country+: +ISO3166::Country+ or +Array+ of ISO3166::Country
|
189
|
+
# - +:location+: +String+
|
190
|
+
# - +:label_name+: +String+
|
191
|
+
# - +:indie+: +Boolean+
|
192
|
+
# - +:catalog_id+: +String+
|
193
|
+
# - +:identifier+: +String+, identifier (barcode, matrix, etc.)
|
194
|
+
# - +:recording_info+: +String+, recording information (studio, city, etc.)
|
195
|
+
# - +:version_description+: +String+, version description (country, digipak, etc.)
|
196
|
+
# - +:notes+: +String+
|
197
|
+
# - +:genre+: +String+
|
198
|
+
# - +:types+: +Array+ of +Symbol+, see rdoc-ref:Release.type
|
199
|
+
# - +:formats+: +Array+ of +Symbol+, see rdoc-ref:Release.format
|
200
|
+
#
|
201
|
+
def find_by(query)
|
202
|
+
url = "#{MetalArchives.config.default_endpoint}search/ajax-advanced/searching/albums"
|
203
|
+
params = Parsers::Release.map_params query
|
204
|
+
|
205
|
+
response = HTTPClient.get url, params
|
206
|
+
json = JSON.parse response.body
|
207
|
+
|
208
|
+
return nil if json['aaData'].empty?
|
209
|
+
|
210
|
+
data = json['aaData'].first
|
211
|
+
id = Nokogiri::HTML(data[1]).xpath('//a/@href').first.value.delete('\\').split('/').last.gsub(/\D/, '').to_i
|
212
|
+
|
213
|
+
find id
|
214
|
+
end
|
215
|
+
|
216
|
+
##
|
217
|
+
# Find by attributes (no lazy loading)
|
218
|
+
#
|
219
|
+
# Refer to {MA's FAQ}[http://www.metal-archives.com/content/help?index=3#tab_db] for search tips.
|
220
|
+
#
|
221
|
+
# Returns rdoc-ref:Release or nil when no results
|
222
|
+
#
|
223
|
+
# [Raises]
|
224
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400
|
225
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
226
|
+
#
|
227
|
+
# [+query+]
|
228
|
+
# Hash containing one or more of the following keys:
|
229
|
+
# - +:band_name+: +String+
|
230
|
+
# - +:title+: +String+
|
231
|
+
# - +:from_year+: +Integer+
|
232
|
+
# - +:from_month+: +Integer+
|
233
|
+
# - +:to_year+: +Integer+
|
234
|
+
# - +:to_month+: +Integer+
|
235
|
+
# - +:country+: +ISO3166::Country+ or +Array+ of ISO3166::Country
|
236
|
+
# - +:location+: +String+
|
237
|
+
# - +:label_name+: +String+
|
238
|
+
# - +:indie+: +Boolean+
|
239
|
+
# - +:catalog_id+: +String+
|
240
|
+
# - +:identifier+: +String+, identifier (barcode, matrix, etc.)
|
241
|
+
# - +:recording_info+: +String+, recording information (studio, city, etc.)
|
242
|
+
# - +:version_description+: +String+, version description (country, digipak, etc.)
|
243
|
+
# - +:notes+: +String+
|
244
|
+
# - +:genre+: +String+
|
245
|
+
# - +:types+: +Array+ of +Symbol+, see rdoc-ref:Release.type
|
246
|
+
# - +:formats+: +Array+ of +Symbol+, see rdoc-ref:Release.format
|
247
|
+
#
|
248
|
+
def find_by!(query)
|
249
|
+
obj = find_by query
|
250
|
+
obj.load! if obj && !obj.loaded?
|
251
|
+
|
252
|
+
obj
|
253
|
+
end
|
254
|
+
|
255
|
+
##
|
256
|
+
# Search by attributes
|
257
|
+
#
|
258
|
+
# Refer to {MA's FAQ}[http://www.metal-archives.com/content/help?index=3#tab_db] for search tips.
|
259
|
+
#
|
260
|
+
# Returns rdoc-ref:Collection of rdoc-ref:Release
|
261
|
+
#
|
262
|
+
# [Raises]
|
263
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400
|
264
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
265
|
+
#
|
266
|
+
# [+query+]
|
267
|
+
# Hash containing one or more of the following keys:
|
268
|
+
# - +:band_name+: +String+
|
269
|
+
# - +:title+: +String+
|
270
|
+
# - +:from_year+: +Integer+
|
271
|
+
# - +:from_month+: +Integer+
|
272
|
+
# - +:to_year+: +Integer+
|
273
|
+
# - +:to_month+: +Integer+
|
274
|
+
# - +:country+: +ISO3166::Country+ or +Array+ of ISO3166::Country
|
275
|
+
# - +:location+: +String+
|
276
|
+
# - +:label_name+: +String+
|
277
|
+
# - +:indie+: +Boolean+
|
278
|
+
# - +:catalog_id+: +String+
|
279
|
+
# - +:identifier+: +String+, identifier (barcode, matrix, etc.)
|
280
|
+
# - +:recording_info+: +String+, recording information (studio, city, etc.)
|
281
|
+
# - +:version_description+: +String+, version description (country, digipak, etc.)
|
282
|
+
# - +:notes+: +String+
|
283
|
+
# - +:genre+: +String+
|
284
|
+
# - +:types+: +Array+ of +Symbol+, see rdoc-ref:Release.type
|
285
|
+
# - +:formats+: +Array+ of +Symbol+, see rdoc-ref:Release.format
|
286
|
+
#
|
287
|
+
def search_by(query)
|
288
|
+
url = "#{MetalArchives.config.default_endpoint}search/ajax-advanced/searching/albums"
|
289
|
+
|
290
|
+
params = Parsers::Release.map_params query
|
291
|
+
|
292
|
+
l = lambda do
|
293
|
+
@start ||= 0
|
294
|
+
|
295
|
+
if @max_items && @start >= @max_items
|
296
|
+
[]
|
297
|
+
else
|
298
|
+
response = HTTPClient.get url, params.merge(:iDisplayStart => @start)
|
299
|
+
json = JSON.parse response.body
|
300
|
+
|
301
|
+
@max_items = json['iTotalRecords']
|
302
|
+
|
303
|
+
objects = []
|
304
|
+
|
305
|
+
json['aaData'].each do |data|
|
306
|
+
# Create Release object for every ID in the results list
|
307
|
+
id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.delete('\\').split('/').last.gsub(/\D/, '').to_i
|
308
|
+
objects << Release.find(id)
|
309
|
+
end
|
310
|
+
|
311
|
+
@start += 200
|
312
|
+
|
313
|
+
objects
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
MetalArchives::Collection.new l
|
318
|
+
end
|
319
|
+
|
320
|
+
##
|
321
|
+
# Search by title, resolves to rdoc-ref:Release.search_by <tt>(:title => title)</tt>
|
322
|
+
#
|
323
|
+
# Refer to {MA's FAQ}[http://www.metal-archives.com/content/help?index=3#tab_db] for search tips.
|
324
|
+
#
|
325
|
+
# Returns (possibly empty) +Array+ of rdoc-ref:Release
|
326
|
+
#
|
327
|
+
# [Raises]
|
328
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400
|
329
|
+
# - rdoc-ref:MetalArchives::Errors::ArgumentError when +title+ isn't a +String+
|
330
|
+
#
|
331
|
+
# [+title+]
|
332
|
+
# +String+
|
333
|
+
#
|
334
|
+
def search(title)
|
335
|
+
raise MetalArchives::Errors::ArgumentError unless title.is_a? String
|
336
|
+
search_by :title => title
|
337
|
+
end
|
338
|
+
|
339
|
+
##
|
340
|
+
# Get all releases
|
341
|
+
#
|
342
|
+
# Returns rdoc-ref:Collection of rdoc-ref:Release
|
343
|
+
#
|
344
|
+
# [Raises]
|
345
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400
|
346
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
347
|
+
#
|
348
|
+
def all
|
349
|
+
search ''
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
module MetalArchives
|
7
|
+
module Parsers
|
8
|
+
##
|
9
|
+
# Release parser
|
10
|
+
#
|
11
|
+
class Release < Parser # :nodoc:
|
12
|
+
class << self
|
13
|
+
TYPE_TO_QUERY = {
|
14
|
+
:full_length => 1,
|
15
|
+
:live => 2,
|
16
|
+
:demo => 3,
|
17
|
+
:single => 4,
|
18
|
+
:ep => 5,
|
19
|
+
:video => 6,
|
20
|
+
:boxed_set => 7,
|
21
|
+
:split => 8,
|
22
|
+
:compilation => 10,
|
23
|
+
:split_video => 12,
|
24
|
+
:collaboration => 13
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
TYPE_TO_SYM = {
|
28
|
+
'Full-length' => :full_length,
|
29
|
+
'Live album' => :live,
|
30
|
+
'Demo' => :demo,
|
31
|
+
'Single' => :single,
|
32
|
+
'EP' => :ep,
|
33
|
+
'Video' => :video,
|
34
|
+
'Boxed set' => :boxed_set,
|
35
|
+
'Split' => :split,
|
36
|
+
'Compilation' => :compilation,
|
37
|
+
'Split video' => :split_video,
|
38
|
+
'Collaboration' => :collaboration
|
39
|
+
}.freeze
|
40
|
+
|
41
|
+
FORMAT_TO_QUERY = {
|
42
|
+
:cd => 'CD',
|
43
|
+
:cassette => 'Cassette',
|
44
|
+
:vinyl => 'Vinyl*',
|
45
|
+
:vhs => 'VHS',
|
46
|
+
:dvd => 'DVD',
|
47
|
+
:digital => 'Digital',
|
48
|
+
:blu_ray => 'Blu-ray*',
|
49
|
+
:other => 'Other'
|
50
|
+
}.freeze
|
51
|
+
|
52
|
+
FORMAT_TO_SYM = {
|
53
|
+
'CD' => :cd,
|
54
|
+
'Cassette' => :cassette,
|
55
|
+
'VHS' => :vhs,
|
56
|
+
'DVD' => :dvd,
|
57
|
+
'Digital' => :digital,
|
58
|
+
'Other' => :other
|
59
|
+
}
|
60
|
+
|
61
|
+
##
|
62
|
+
# Map attributes to MA attributes
|
63
|
+
#
|
64
|
+
# Returns +Hash+
|
65
|
+
#
|
66
|
+
# [+params+]
|
67
|
+
# +Hash+
|
68
|
+
#
|
69
|
+
def map_params(query)
|
70
|
+
params = {
|
71
|
+
:bandName => query[:band_name] || '',
|
72
|
+
:releaseTitle => query[:title] || '',
|
73
|
+
:releaseYearFrom => query[:from_year] || '',
|
74
|
+
:releaseMonthFrom => query[:from_month] || '',
|
75
|
+
:releaseYearTo => query[:to_year] || '',
|
76
|
+
:releaseMonthTo => query[:to_month] || '',
|
77
|
+
:country => map_countries(query[:country]) || '',
|
78
|
+
:location => query[:location] || '',
|
79
|
+
:releaseLabelName => query[:label_name] || '',
|
80
|
+
:releaseCatalogNumber => query[:catalog_id] || '',
|
81
|
+
:releaseIdentifiers => query[:identifier] || '',
|
82
|
+
:releaseRecordingInfo => query[:recording_info] || '',
|
83
|
+
:releaseDescription => query[:version_description] || '',
|
84
|
+
:releaseNotes => query[:notes] || '',
|
85
|
+
:genre => query[:genre] || '',
|
86
|
+
:releaseType => map_types(query[:types]),
|
87
|
+
:releaseFormat => map_formats(query[:formats])
|
88
|
+
}
|
89
|
+
|
90
|
+
params
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Parse main HTML page
|
95
|
+
#
|
96
|
+
# Returns +Hash+
|
97
|
+
#
|
98
|
+
# [Raises]
|
99
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
100
|
+
#
|
101
|
+
def parse_html(response)
|
102
|
+
props = {}
|
103
|
+
doc = Nokogiri::HTML response
|
104
|
+
|
105
|
+
props[:title] = sanitize doc.css('#album_info .album_name a').first.content
|
106
|
+
|
107
|
+
doc.css('#album_info dl').each do |dl|
|
108
|
+
dl.search('dt').each do |dt|
|
109
|
+
content = sanitize dt.next_element.content
|
110
|
+
|
111
|
+
next if content == 'N/A'
|
112
|
+
|
113
|
+
case sanitize(dt.content)
|
114
|
+
when 'Type:'
|
115
|
+
props[:type] = map_type content
|
116
|
+
when 'Release date:'
|
117
|
+
begin
|
118
|
+
props[:date_released] = NilDate.parse content
|
119
|
+
rescue MetalArchives::Errors::ArgumentError => e
|
120
|
+
dr = Date.parse content
|
121
|
+
props[:date_released] = NilDate.new dr.year, dr.month, dr.day
|
122
|
+
end
|
123
|
+
when 'Catalog ID:'
|
124
|
+
props[:catalog_id] = content
|
125
|
+
when 'Identifier:'
|
126
|
+
props[:identifier] = content
|
127
|
+
when 'Version desc.:'
|
128
|
+
props[:version_description] = content
|
129
|
+
when 'Label:'
|
130
|
+
# TODO: label
|
131
|
+
when 'Format:'
|
132
|
+
props[:format] = map_format content
|
133
|
+
when 'Limitation:'
|
134
|
+
props[:limitation] = content.to_i
|
135
|
+
when 'Reviews:'
|
136
|
+
next if content == 'None yet'
|
137
|
+
# TODO: reviews
|
138
|
+
else
|
139
|
+
raise MetalArchives::Errors::ParserError, "Unknown token: #{dt.content}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
props
|
145
|
+
rescue => e
|
146
|
+
e.backtrace.each { |b| MetalArchives.config.logger.error b }
|
147
|
+
raise Errors::ParserError, e
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
##
|
153
|
+
# Map MA countries to query parameters
|
154
|
+
#
|
155
|
+
# Returns +Array+ of +ISO3166::Country+
|
156
|
+
#
|
157
|
+
# [+types+]
|
158
|
+
# +Array+ containing one or more +String+s
|
159
|
+
#
|
160
|
+
def map_countries(countries)
|
161
|
+
countries && countries.map { |c| c.alpha2 }
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Map MA release type to query parameters
|
166
|
+
#
|
167
|
+
# Returns +Array+ of +Integer+
|
168
|
+
#
|
169
|
+
# [+types+]
|
170
|
+
# +Array+ containing one or more +Symbol+, see rdoc-ref:Release.type
|
171
|
+
#
|
172
|
+
def map_types(type_syms)
|
173
|
+
return unless type_syms
|
174
|
+
|
175
|
+
types = []
|
176
|
+
type_syms.each do |type|
|
177
|
+
raise MetalArchives::Errors::ParserError, "Unknown type: #{type}" unless TYPE_TO_QUERY[type]
|
178
|
+
|
179
|
+
types << TYPE_TO_QUERY[type]
|
180
|
+
end
|
181
|
+
|
182
|
+
types
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Map MA release type to +Symbol+
|
187
|
+
#
|
188
|
+
# Returns +Symbol+, see rdoc-ref:Release.type
|
189
|
+
#
|
190
|
+
def map_type(type)
|
191
|
+
raise MetalArchives::Errors::ParserError, "Unknown type: #{type}" unless TYPE_TO_SYM[type]
|
192
|
+
|
193
|
+
TYPE_TO_SYM[type]
|
194
|
+
end
|
195
|
+
|
196
|
+
##
|
197
|
+
# Map MA release format to query parameters
|
198
|
+
#
|
199
|
+
# Returns +Array+ of +Integer+
|
200
|
+
#
|
201
|
+
# [+types+]
|
202
|
+
# +Array+ containing one or more +Symbol+, see rdoc-ref:Release.type
|
203
|
+
#
|
204
|
+
def map_formats(format_syms)
|
205
|
+
return unless format_syms
|
206
|
+
|
207
|
+
formats = []
|
208
|
+
format_syms.each do |format|
|
209
|
+
raise MetalArchives::Errors::ParserError, "Unknown format: #{format}" unless FORMAT_TO_QUERY[format]
|
210
|
+
|
211
|
+
formats << FORMAT_TO_QUERY[format]
|
212
|
+
end
|
213
|
+
|
214
|
+
formats
|
215
|
+
end
|
216
|
+
|
217
|
+
##
|
218
|
+
# Map MA release format to +Symbol+
|
219
|
+
#
|
220
|
+
# Returns +Symbol+, see rdoc-ref:Release.format
|
221
|
+
#
|
222
|
+
def map_format(format)
|
223
|
+
return :vinyl if format =~ /[Vv]inyl/
|
224
|
+
return :blu_ray if format =~ /[Bb]lu.?[Rr]ay/
|
225
|
+
|
226
|
+
raise MetalArchives::Errors::ParserError, "Unknown format: #{format}" unless FORMAT_TO_SYM[format]
|
227
|
+
|
228
|
+
FORMAT_TO_SYM[format]
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe MetalArchives::Release do
|
4
|
+
describe 'properties' do
|
5
|
+
it 'Tales of Ancient Prophecies has properties' do
|
6
|
+
release = MetalArchives::Release.find 416934
|
7
|
+
|
8
|
+
expect(release).to be_instance_of MetalArchives::Release
|
9
|
+
expect(release.id).to eq 416934
|
10
|
+
expect(release.title).to eq 'Tales of Ancient Prophecies'
|
11
|
+
expect(release.type).to eq :full_length
|
12
|
+
expect(release.date_released).to eq MetalArchives::NilDate.new(2014, 6, 4)
|
13
|
+
expect(release.catalog_id).to eq 'BLOD091CD'
|
14
|
+
expect(release.version_description).to be_nil
|
15
|
+
expect(release.format).to eq :cd
|
16
|
+
expect(release.limitation).to be_nil
|
17
|
+
expect(release.notes).to be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it '...And Oceans has properties' do
|
21
|
+
release = MetalArchives::Release.find 123563
|
22
|
+
|
23
|
+
expect(release).to be_instance_of MetalArchives::Release
|
24
|
+
expect(release.id).to eq 123563
|
25
|
+
expect(release.title).to eq '...and Oceans'
|
26
|
+
expect(release.type).to eq :compilation
|
27
|
+
expect(release.date_released).to eq MetalArchives::NilDate.new(2000)
|
28
|
+
expect(release.catalog_id).to eq 'NMLP 025'
|
29
|
+
expect(release.version_description).to be_nil
|
30
|
+
expect(release.format).to eq :vinyl
|
31
|
+
expect(release.limitation).to be_nil
|
32
|
+
expect(release.notes).to be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'uses NilDate' do
|
36
|
+
release = MetalArchives::Release.find 123563
|
37
|
+
|
38
|
+
expect(release.title).to eq '...and Oceans'
|
39
|
+
expect(release.date_released).to be_instance_of MetalArchives::NilDate
|
40
|
+
expect(release.date_released).to eq MetalArchives::NilDate.new(2000, nil, nil)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'methods' do
|
45
|
+
describe 'find' do
|
46
|
+
it 'finds a release' do
|
47
|
+
release = MetalArchives::Release.find 416934
|
48
|
+
|
49
|
+
expect(release).not_to be_nil
|
50
|
+
expect(release).to be_instance_of MetalArchives::Release
|
51
|
+
expect(release.id).to eq 416934
|
52
|
+
expect(release.title).to eq 'Tales of Ancient Prophecies'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'lazily loads' do
|
56
|
+
release = MetalArchives::Release.find -1
|
57
|
+
|
58
|
+
expect(release).to be_instance_of MetalArchives::Release
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'find!' do
|
63
|
+
it 'finds a release' do
|
64
|
+
release = MetalArchives::Release.find! 416934
|
65
|
+
|
66
|
+
expect(release).to be_instance_of MetalArchives::Release
|
67
|
+
expect(release.title).to eq 'Tales of Ancient Prophecies'
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'raises on invalid id' do
|
71
|
+
expect(-> { MetalArchives::Release.find! -1 }).to raise_error MetalArchives::Errors::APIError
|
72
|
+
expect(-> { MetalArchives::Release.find! 0 }).to raise_error MetalArchives::Errors::InvalidIDError
|
73
|
+
expect(-> { MetalArchives::Release.find! nil }).to raise_error MetalArchives::Errors::InvalidIDError
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'find_by' do
|
78
|
+
it 'finds a release by title' do
|
79
|
+
release = MetalArchives::Release.find_by :title => 'Tales of Ancient Prophecies'
|
80
|
+
|
81
|
+
expect(release).to be_instance_of MetalArchives::Release
|
82
|
+
expect(release.id).to eq 416934
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'returns nil on invalid id' do
|
86
|
+
release = MetalArchives::Release.find_by :title => 'SomeNonExistantName'
|
87
|
+
|
88
|
+
expect(release).to be_nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe 'find_by!' do
|
93
|
+
it 'finds a release' do
|
94
|
+
release = MetalArchives::Release.find_by! :title => 'Tales of Ancient Prophecies'
|
95
|
+
|
96
|
+
expect(release).to be_instance_of MetalArchives::Release
|
97
|
+
expect(release.id).to eq 416934
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'returns nil on invalid id' do
|
101
|
+
release = MetalArchives::Release.find_by! :title => 'SomeNonExistantName'
|
102
|
+
|
103
|
+
expect(release).to be_nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'search' do
|
108
|
+
it 'returns a collection' do
|
109
|
+
collection = MetalArchives::Release.search 'Rhapsody'
|
110
|
+
|
111
|
+
expect(collection).to be_instance_of MetalArchives::Collection
|
112
|
+
expect(collection.first).to be_instance_of MetalArchives::Release
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'returns an empty collection' do
|
116
|
+
expect(MetalArchives::Release.search 'SomeNoneExistantName').to be_empty
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'searches by title' do
|
120
|
+
expect(MetalArchives::Release.search_by(:title => 'Rhapsody').count).to eq 13
|
121
|
+
# expect(MetalArchives::Release.search_by(:title => 'Lost Horizon').count).to eq 3
|
122
|
+
# expect(MetalArchives::Release.search_by(:title => 'Lost Horizon', :exact => true).count).to eq 2
|
123
|
+
# expect(MetalArchives::Release.search_by(:title => 'Alquimia', :genre => 'Melodic Power').count).to eq 2
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe 'all' do
|
128
|
+
it 'returns a collection' do
|
129
|
+
expect(MetalArchives::Release.all).to be_instance_of MetalArchives::Collection
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metal_archives
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Dejonckheere
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byebug
|
@@ -220,10 +220,12 @@ files:
|
|
220
220
|
- lib/metal_archives/models/band.rb
|
221
221
|
- lib/metal_archives/models/base_model.rb
|
222
222
|
- lib/metal_archives/models/label.rb
|
223
|
+
- lib/metal_archives/models/release.rb
|
223
224
|
- lib/metal_archives/parsers/artist.rb
|
224
225
|
- lib/metal_archives/parsers/band.rb
|
225
226
|
- lib/metal_archives/parsers/label.rb
|
226
227
|
- lib/metal_archives/parsers/parser.rb
|
228
|
+
- lib/metal_archives/parsers/release.rb
|
227
229
|
- lib/metal_archives/utils/collection.rb
|
228
230
|
- lib/metal_archives/utils/lru_cache.rb
|
229
231
|
- lib/metal_archives/utils/nil_date.rb
|
@@ -239,6 +241,7 @@ files:
|
|
239
241
|
- spec/models/artist_spec.rb
|
240
242
|
- spec/models/band_spec.rb
|
241
243
|
- spec/models/base_model_spec.rb
|
244
|
+
- spec/models/release_spec.rb
|
242
245
|
- spec/parser_spec.rb
|
243
246
|
- spec/spec_helper.rb
|
244
247
|
- spec/support/factory_girl.rb
|
@@ -280,6 +283,7 @@ test_files:
|
|
280
283
|
- spec/models/artist_spec.rb
|
281
284
|
- spec/models/band_spec.rb
|
282
285
|
- spec/models/base_model_spec.rb
|
286
|
+
- spec/models/release_spec.rb
|
283
287
|
- spec/parser_spec.rb
|
284
288
|
- spec/spec_helper.rb
|
285
289
|
- spec/support/factory_girl.rb
|