metal_archives 2.1.1 → 3.1.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 +5 -5
- data/.github/workflows/ci.yml +93 -0
- data/.gitignore +6 -6
- data/.overcommit.yml +35 -0
- data/.rspec +2 -0
- data/.rubocop.yml +69 -6
- data/CHANGELOG.md +29 -0
- data/Gemfile +1 -1
- data/LICENSE.md +17 -4
- data/README.md +65 -86
- data/Rakefile +8 -7
- data/bin/console +38 -0
- data/bin/setup +8 -0
- data/config/inflections.rb +7 -0
- data/config/initializers/.keep +0 -0
- data/docker-compose.yml +23 -0
- data/lib/metal_archives.rb +82 -25
- data/lib/metal_archives/cache/base.rb +40 -0
- data/lib/metal_archives/cache/memory.rb +68 -0
- data/lib/metal_archives/cache/null.rb +22 -0
- data/lib/metal_archives/cache/redis.rb +49 -0
- data/lib/metal_archives/{utils/collection.rb → collection.rb} +3 -5
- data/lib/metal_archives/configuration.rb +33 -50
- data/lib/metal_archives/{error.rb → errors.rb} +9 -1
- data/lib/metal_archives/http_client.rb +45 -44
- data/lib/metal_archives/models/artist.rb +90 -45
- data/lib/metal_archives/models/band.rb +80 -55
- data/lib/metal_archives/models/base.rb +218 -0
- data/lib/metal_archives/models/label.rb +14 -15
- data/lib/metal_archives/models/release.rb +349 -0
- data/lib/metal_archives/parsers/artist.rb +86 -50
- data/lib/metal_archives/parsers/band.rb +155 -88
- data/lib/metal_archives/parsers/base.rb +14 -0
- data/lib/metal_archives/parsers/country.rb +21 -0
- data/lib/metal_archives/parsers/date.rb +31 -0
- data/lib/metal_archives/parsers/genre.rb +67 -0
- data/lib/metal_archives/parsers/label.rb +39 -31
- data/lib/metal_archives/parsers/parser.rb +16 -63
- data/lib/metal_archives/parsers/release.rb +242 -0
- data/lib/metal_archives/parsers/year.rb +29 -0
- data/lib/metal_archives/version.rb +12 -1
- data/metal_archives.env.example +10 -0
- data/metal_archives.gemspec +43 -28
- data/nginx/default.conf +60 -0
- metadata +181 -72
- data/.travis.yml +0 -12
- data/lib/metal_archives/middleware/cache_check.rb +0 -20
- data/lib/metal_archives/middleware/encoding.rb +0 -16
- data/lib/metal_archives/middleware/headers.rb +0 -38
- data/lib/metal_archives/middleware/rewrite_endpoint.rb +0 -38
- data/lib/metal_archives/models/base_model.rb +0 -215
- data/lib/metal_archives/utils/lru_cache.rb +0 -61
- data/lib/metal_archives/utils/nil_date.rb +0 -99
- data/lib/metal_archives/utils/range.rb +0 -66
- data/spec/configuration_spec.rb +0 -96
- data/spec/factories/artist_factory.rb +0 -37
- data/spec/factories/band_factory.rb +0 -60
- data/spec/factories/nil_date_factory.rb +0 -9
- data/spec/factories/range_factory.rb +0 -8
- data/spec/models/artist_spec.rb +0 -138
- data/spec/models/band_spec.rb +0 -164
- data/spec/models/base_model_spec.rb +0 -219
- data/spec/parser_spec.rb +0 -19
- data/spec/spec_helper.rb +0 -111
- data/spec/support/factory_girl.rb +0 -5
- data/spec/support/metal_archives.rb +0 -33
- data/spec/utils/collection_spec.rb +0 -72
- data/spec/utils/lru_cache_spec.rb +0 -53
- data/spec/utils/nil_date_spec.rb +0 -156
- data/spec/utils/range_spec.rb +0 -62
@@ -0,0 +1,218 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MetalArchives
|
4
|
+
##
|
5
|
+
# Abstract model class
|
6
|
+
#
|
7
|
+
class Base
|
8
|
+
##
|
9
|
+
# Generic shallow copy constructor
|
10
|
+
#
|
11
|
+
def initialize(attributes = {})
|
12
|
+
raise Errors::NotImplementedError, "no :id property in model" unless respond_to? :id
|
13
|
+
|
14
|
+
set(**attributes)
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Set properties
|
19
|
+
#
|
20
|
+
def set(**attributes)
|
21
|
+
attributes.each { |key, value| instance_variable_set(:"@#{key}", value) }
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Returns true if two objects have the same type and id
|
26
|
+
#
|
27
|
+
def ==(other)
|
28
|
+
other.is_a?(self.class) &&
|
29
|
+
id == other.id
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Fetch, parse and load the data
|
34
|
+
#
|
35
|
+
# [Raises]
|
36
|
+
# - rdoc-ref:Errors::InvalidIDError when no id
|
37
|
+
# - rdoc-ref:Errors::APIError when receiving a status code >= 400 (except 404)
|
38
|
+
#
|
39
|
+
def load!
|
40
|
+
raise Errors::InvalidIDError, "no id present" unless id
|
41
|
+
|
42
|
+
# Use constructor to set attributes
|
43
|
+
set(**assemble)
|
44
|
+
|
45
|
+
@loaded = true
|
46
|
+
MetalArchives.cache[id] = self
|
47
|
+
rescue StandardError => e
|
48
|
+
# Don't cache invalid requests
|
49
|
+
MetalArchives.cache.delete id
|
50
|
+
raise e
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Whether or not the object is currently loaded
|
55
|
+
#
|
56
|
+
def loaded?
|
57
|
+
@loaded ||= false
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Whether or not the object is currently cached
|
62
|
+
#
|
63
|
+
def cached?
|
64
|
+
loaded? && MetalArchives.cache.include?(id)
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# String representation
|
69
|
+
#
|
70
|
+
def inspect
|
71
|
+
"#<#{self.class.name} @id=#{@id} @name=\"#{@name}\">"
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
##
|
77
|
+
# Fetch the data and assemble the model
|
78
|
+
#
|
79
|
+
# Override this method
|
80
|
+
#
|
81
|
+
# [Raises]
|
82
|
+
# - rdoc-ref:Errors::InvalidIDError when no or invalid id
|
83
|
+
# - rdoc-ref:Errors::APIError when receiving a status code >= 400 (except 404)
|
84
|
+
#
|
85
|
+
def assemble
|
86
|
+
raise Errors::NotImplementedError, "method :assemble not implemented"
|
87
|
+
end
|
88
|
+
|
89
|
+
class << self
|
90
|
+
##
|
91
|
+
# Declared properties
|
92
|
+
#
|
93
|
+
def properties
|
94
|
+
@properties ||= {}
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
##
|
100
|
+
# Defines a model property.
|
101
|
+
#
|
102
|
+
# [+name+]
|
103
|
+
# Name of the property
|
104
|
+
#
|
105
|
+
# [+opts+]
|
106
|
+
# [+type+]
|
107
|
+
# Data type of property (a constant)
|
108
|
+
#
|
109
|
+
# Default: +String+
|
110
|
+
#
|
111
|
+
# [+multiple+]
|
112
|
+
# Whether or not the property has multiple values (which
|
113
|
+
# turns it into an +Array+ of +type+)
|
114
|
+
#
|
115
|
+
def property(name, opts = {})
|
116
|
+
properties[name] = opts
|
117
|
+
|
118
|
+
# property
|
119
|
+
define_method(name) do
|
120
|
+
# Load only when not loaded or id property
|
121
|
+
load! unless loaded? || name == :id
|
122
|
+
|
123
|
+
instance_variable_get(:"@#{name}")
|
124
|
+
end
|
125
|
+
|
126
|
+
# property?
|
127
|
+
define_method("#{name}?") do
|
128
|
+
send(name).present?
|
129
|
+
end
|
130
|
+
|
131
|
+
# property=
|
132
|
+
define_method("#{name}=") do |value|
|
133
|
+
return instance_variable_set(:"@#{name}", value) if value.nil?
|
134
|
+
|
135
|
+
# Check value type
|
136
|
+
type = opts[:type] || String
|
137
|
+
if opts[:multiple]
|
138
|
+
raise Errors::TypeError, "invalid type #{value.class}, must be Array for #{name}" unless value.is_a? Array
|
139
|
+
|
140
|
+
value.each do |val|
|
141
|
+
raise Errors::TypeError, "invalid type #{val.class}, must be #{type} for #{name}" unless val.is_a? type
|
142
|
+
end
|
143
|
+
else
|
144
|
+
raise Errors::TypeError, "invalid type #{value.class}, must be #{type} for #{name}" unless value.is_a? type
|
145
|
+
end
|
146
|
+
|
147
|
+
instance_variable_set(:"@#{name}", value)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
##
|
152
|
+
# Defines a model enum property.
|
153
|
+
#
|
154
|
+
# [+name+]
|
155
|
+
# Name of the property
|
156
|
+
#
|
157
|
+
# [+opts+]
|
158
|
+
# [+values+]
|
159
|
+
# Required. An array of possible values
|
160
|
+
#
|
161
|
+
# [+multiple+]
|
162
|
+
# Whether or not the property has multiple values (which
|
163
|
+
# turns it into an +Array+ of +type+)
|
164
|
+
#
|
165
|
+
def enum(name, opts)
|
166
|
+
raise ArgumentError, "opts[:values] is required" unless opts && opts[:values]
|
167
|
+
|
168
|
+
properties[name] = opts
|
169
|
+
|
170
|
+
# property
|
171
|
+
define_method(name) do
|
172
|
+
load! unless loaded?
|
173
|
+
|
174
|
+
instance_variable_get(:"@#{name}")
|
175
|
+
end
|
176
|
+
|
177
|
+
# property?
|
178
|
+
define_method("#{name}?") do
|
179
|
+
load! unless loaded? && instance_variable_defined?("@#{name}")
|
180
|
+
|
181
|
+
property = instance_variable_get(:"@#{name}")
|
182
|
+
property.respond_to?(:empty?) ? !property.empty? : !property.nil?
|
183
|
+
end
|
184
|
+
|
185
|
+
# property=
|
186
|
+
define_method("#{name}=") do |value|
|
187
|
+
# Check enum type
|
188
|
+
if opts[:multiple]
|
189
|
+
raise Errors::TypeError, "invalid enum value #{value}, must be Array for #{name}" unless value.is_a? Array
|
190
|
+
|
191
|
+
value.each do |val|
|
192
|
+
raise Errors::TypeError, "invalid enum value #{val} for #{name}" unless opts[:values].include? val
|
193
|
+
end
|
194
|
+
else
|
195
|
+
raise Errors::TypeError, "invalid enum value #{value} for #{name}" unless opts[:values].include? value
|
196
|
+
end
|
197
|
+
|
198
|
+
instance_variable_set(:"@#{name}", value)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
##
|
203
|
+
# Defines a model boolean property. This method is an alias for <tt>enum name, :values => [true, false]</tt>
|
204
|
+
#
|
205
|
+
# [+name+]
|
206
|
+
# Name of the property
|
207
|
+
#
|
208
|
+
# [+opts+]
|
209
|
+
# [+multiple+]
|
210
|
+
# Whether or not the property has multiple values (which
|
211
|
+
# turns it into an +Array+ of +type+)
|
212
|
+
#
|
213
|
+
def boolean(name, opts = {})
|
214
|
+
enum name, opts.merge(values: [true, false])
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "date"
|
4
|
+
require "countries"
|
5
5
|
|
6
6
|
module MetalArchives
|
7
7
|
##
|
8
8
|
# Represents a record label
|
9
9
|
#
|
10
|
-
class Label <
|
10
|
+
class Label < Base
|
11
11
|
##
|
12
12
|
# :attr_reader: id
|
13
13
|
#
|
14
14
|
# Returns +Integer+
|
15
15
|
#
|
16
|
-
property :id, :
|
16
|
+
property :id, type: Integer
|
17
17
|
|
18
18
|
##
|
19
19
|
# :attr_reader: name
|
@@ -46,7 +46,7 @@ module MetalArchives
|
|
46
46
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
47
47
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
48
48
|
#
|
49
|
-
property :country, :
|
49
|
+
property :country, type: ISO3166::Country
|
50
50
|
|
51
51
|
##
|
52
52
|
# :attr_reader: phone
|
@@ -68,25 +68,25 @@ module MetalArchives
|
|
68
68
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
69
69
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
70
70
|
#
|
71
|
-
property :specializations, :
|
71
|
+
property :specializations, multiple: true
|
72
72
|
|
73
73
|
##
|
74
74
|
# :attr_reader: date_founded
|
75
75
|
#
|
76
|
-
# Returns +
|
76
|
+
# Returns +Date+
|
77
77
|
#
|
78
78
|
# [Raises]
|
79
79
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
80
80
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
81
81
|
#
|
82
|
-
property :date_founded, :
|
82
|
+
property :date_founded, type: Date
|
83
83
|
|
84
84
|
##
|
85
85
|
# :attr_reader: sub_labels
|
86
86
|
#
|
87
87
|
# Returns +Array+ of rdoc-ref:Label
|
88
88
|
#
|
89
|
-
property :sub_labels, :
|
89
|
+
property :sub_labels, type: Label, multiple: true
|
90
90
|
|
91
91
|
##
|
92
92
|
# :attr_reader: online_shopping
|
@@ -100,14 +100,14 @@ module MetalArchives
|
|
100
100
|
#
|
101
101
|
# Returns +Hash+ with the following keys: +title+, +content+
|
102
102
|
#
|
103
|
-
property :contact, :
|
103
|
+
property :contact, type: Hash, multiple: true
|
104
104
|
|
105
105
|
##
|
106
106
|
# :attr_reader: status
|
107
107
|
#
|
108
108
|
# Returns +:active+, +:closed+ or +:unknown+
|
109
109
|
#
|
110
|
-
enum :status, :
|
110
|
+
enum :status, values: [:active, :closed, :unknown]
|
111
111
|
|
112
112
|
class << self
|
113
113
|
##
|
@@ -116,8 +116,7 @@ module MetalArchives
|
|
116
116
|
# Returns +Array+ of rdoc-ref:Label
|
117
117
|
#
|
118
118
|
def search(_name)
|
119
|
-
|
120
|
-
results
|
119
|
+
[]
|
121
120
|
end
|
122
121
|
|
123
122
|
##
|
@@ -128,8 +127,8 @@ module MetalArchives
|
|
128
127
|
def find_by_name(name, id)
|
129
128
|
client.find_resource(
|
130
129
|
:band,
|
131
|
-
:
|
132
|
-
:
|
130
|
+
name: name,
|
131
|
+
id: id,
|
133
132
|
)
|
134
133
|
end
|
135
134
|
end
|
@@ -0,0 +1,349 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
require "nokogiri"
|
5
|
+
|
6
|
+
module MetalArchives
|
7
|
+
##
|
8
|
+
# Represents a release
|
9
|
+
#
|
10
|
+
class Release < Base
|
11
|
+
##
|
12
|
+
# :attr_reader: id
|
13
|
+
#
|
14
|
+
# Returns +Integer+
|
15
|
+
#
|
16
|
+
property :id, type: Integer
|
17
|
+
|
18
|
+
##
|
19
|
+
# :attr_reader: title
|
20
|
+
#
|
21
|
+
# Returns +String+
|
22
|
+
#
|
23
|
+
# [Raises]
|
24
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
25
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
26
|
+
#
|
27
|
+
property :title
|
28
|
+
|
29
|
+
# TODO: band
|
30
|
+
|
31
|
+
##
|
32
|
+
# :attr_reader: type
|
33
|
+
#
|
34
|
+
# Returns +:full_length+, +:live+, +:demo+, +:single+, +:ep+, +:video+, +:boxed_set+, +:split+, +:compilation+, +:split_video+, +:collaboration+
|
35
|
+
#
|
36
|
+
# [Raises]
|
37
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
38
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
39
|
+
#
|
40
|
+
enum :type, values: [:full_length, :live, :demo, :single, :ep, :video, :boxed_set, :split, :compilation, :split_video, :collaboration]
|
41
|
+
|
42
|
+
##
|
43
|
+
# :attr_reader: date_released
|
44
|
+
#
|
45
|
+
# Returns rdoc-ref:Date
|
46
|
+
#
|
47
|
+
# [Raises]
|
48
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
49
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
50
|
+
#
|
51
|
+
property :date_released, type: Date
|
52
|
+
|
53
|
+
##
|
54
|
+
# :attr_reader_: catalog_id
|
55
|
+
#
|
56
|
+
# Return +String+
|
57
|
+
#
|
58
|
+
# [Raises]
|
59
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
60
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
61
|
+
#
|
62
|
+
property :catalog_id
|
63
|
+
|
64
|
+
##
|
65
|
+
# :attr_reader_: version_description
|
66
|
+
#
|
67
|
+
# Return +String+
|
68
|
+
#
|
69
|
+
# [Raises]
|
70
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
71
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
72
|
+
#
|
73
|
+
property :version_description
|
74
|
+
|
75
|
+
# TODO: label
|
76
|
+
|
77
|
+
##
|
78
|
+
# :attr_reader: format
|
79
|
+
#
|
80
|
+
# Returns +:cd+, +:cassette+, +:vinyl+, +:vhs+, +:dvd+, +:digital+, +:blu_ray+, +:other+, +:unknown+
|
81
|
+
#
|
82
|
+
# [Raises]
|
83
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
84
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
85
|
+
#
|
86
|
+
property :format
|
87
|
+
|
88
|
+
##
|
89
|
+
# :attr_reader: limitation
|
90
|
+
#
|
91
|
+
# Returns +Integer+
|
92
|
+
#
|
93
|
+
# [Raises]
|
94
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
95
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
96
|
+
#
|
97
|
+
property :limitation
|
98
|
+
|
99
|
+
# TODO: reviews
|
100
|
+
# TODO: songs
|
101
|
+
# TODO: lineup
|
102
|
+
# TODO: other versions
|
103
|
+
# TODO: links
|
104
|
+
|
105
|
+
##
|
106
|
+
# :attr_reader: notes
|
107
|
+
#
|
108
|
+
# Returns raw HTML +String+
|
109
|
+
#
|
110
|
+
# [Raises]
|
111
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
112
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
113
|
+
#
|
114
|
+
property :notes
|
115
|
+
|
116
|
+
protected
|
117
|
+
|
118
|
+
##
|
119
|
+
# Fetch the data and assemble the model
|
120
|
+
#
|
121
|
+
# [Raises]
|
122
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when receiving a status code == 404
|
123
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
124
|
+
#
|
125
|
+
def assemble # :nodoc:
|
126
|
+
## Base attributes
|
127
|
+
response = MetalArchives.http.get "/albums/view/id/#{id}"
|
128
|
+
|
129
|
+
Parsers::Release.parse_html response.to_s
|
130
|
+
end
|
131
|
+
|
132
|
+
class << self
|
133
|
+
##
|
134
|
+
# Find by ID
|
135
|
+
#
|
136
|
+
# Returns rdoc-ref:Release, even when ID is invalid (because the data is lazily fetched)
|
137
|
+
#
|
138
|
+
# [+id+]
|
139
|
+
# +Integer+
|
140
|
+
#
|
141
|
+
def find(id)
|
142
|
+
return MetalArchives.cache[id] if MetalArchives.cache.include? id
|
143
|
+
|
144
|
+
Release.new id: id
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Find by ID (no lazy loading)
|
149
|
+
#
|
150
|
+
# Returns rdoc-ref:Release
|
151
|
+
#
|
152
|
+
# [Raises]
|
153
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
154
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
155
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
156
|
+
#
|
157
|
+
# [+id+]
|
158
|
+
# +Integer+
|
159
|
+
#
|
160
|
+
def find!(id)
|
161
|
+
obj = find id
|
162
|
+
obj.load! if obj && !obj.loaded?
|
163
|
+
|
164
|
+
obj
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Find by attributes
|
169
|
+
#
|
170
|
+
# Refer to {MA's FAQ}[http://www.metal-archives.com/content/help?index=3#tab_db] for search tips.
|
171
|
+
#
|
172
|
+
# Returns rdoc-ref:Release or nil when no results
|
173
|
+
#
|
174
|
+
# [Raises]
|
175
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400
|
176
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
177
|
+
#
|
178
|
+
# [+query+]
|
179
|
+
# Hash containing one or more of the following keys:
|
180
|
+
# - +:band_name+: +String+
|
181
|
+
# - +:title+: +String+
|
182
|
+
# - +:from_year+: +Integer+
|
183
|
+
# - +:from_month+: +Integer+
|
184
|
+
# - +:to_year+: +Integer+
|
185
|
+
# - +:to_month+: +Integer+
|
186
|
+
# - +:country+: +ISO3166::Country+ or +Array+ of ISO3166::Country
|
187
|
+
# - +:location+: +String+
|
188
|
+
# - +:label_name+: +String+
|
189
|
+
# - +:indie+: +Boolean+
|
190
|
+
# - +:catalog_id+: +String+
|
191
|
+
# - +:identifier+: +String+, identifier (barcode, matrix, etc.)
|
192
|
+
# - +:recording_info+: +String+, recording information (studio, city, etc.)
|
193
|
+
# - +:version_description+: +String+, version description (country, digipak, etc.)
|
194
|
+
# - +:notes+: +String+
|
195
|
+
# - +:genre+: +String+
|
196
|
+
# - +:types+: +Array+ of +Symbol+, see rdoc-ref:Release.type
|
197
|
+
# - +:formats+: +Array+ of +Symbol+, see rdoc-ref:Release.format
|
198
|
+
#
|
199
|
+
def find_by(query)
|
200
|
+
params = Parsers::Release.map_params query
|
201
|
+
|
202
|
+
response = MetalArchives.http.get "/search/ajax-advanced/searching/albums", params
|
203
|
+
json = JSON.parse response.to_s
|
204
|
+
|
205
|
+
return nil if json["aaData"].empty?
|
206
|
+
|
207
|
+
data = json["aaData"].first
|
208
|
+
id = Nokogiri::HTML(data[1]).xpath("//a/@href").first.value.delete('\\').split("/").last.gsub(/\D/, "").to_i
|
209
|
+
|
210
|
+
find id
|
211
|
+
end
|
212
|
+
|
213
|
+
##
|
214
|
+
# Find by attributes (no lazy loading)
|
215
|
+
#
|
216
|
+
# Refer to {MA's FAQ}[http://www.metal-archives.com/content/help?index=3#tab_db] for search tips.
|
217
|
+
#
|
218
|
+
# Returns rdoc-ref:Release or nil when no results
|
219
|
+
#
|
220
|
+
# [Raises]
|
221
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400
|
222
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
223
|
+
#
|
224
|
+
# [+query+]
|
225
|
+
# Hash containing one or more of the following keys:
|
226
|
+
# - +:band_name+: +String+
|
227
|
+
# - +:title+: +String+
|
228
|
+
# - +:from_year+: +Integer+
|
229
|
+
# - +:from_month+: +Integer+
|
230
|
+
# - +:to_year+: +Integer+
|
231
|
+
# - +:to_month+: +Integer+
|
232
|
+
# - +:country+: +ISO3166::Country+ or +Array+ of ISO3166::Country
|
233
|
+
# - +:location+: +String+
|
234
|
+
# - +:label_name+: +String+
|
235
|
+
# - +:indie+: +Boolean+
|
236
|
+
# - +:catalog_id+: +String+
|
237
|
+
# - +:identifier+: +String+, identifier (barcode, matrix, etc.)
|
238
|
+
# - +:recording_info+: +String+, recording information (studio, city, etc.)
|
239
|
+
# - +:version_description+: +String+, version description (country, digipak, etc.)
|
240
|
+
# - +:notes+: +String+
|
241
|
+
# - +:genre+: +String+
|
242
|
+
# - +:types+: +Array+ of +Symbol+, see rdoc-ref:Release.type
|
243
|
+
# - +:formats+: +Array+ of +Symbol+, see rdoc-ref:Release.format
|
244
|
+
#
|
245
|
+
def find_by!(query)
|
246
|
+
obj = find_by query
|
247
|
+
obj.load! if obj && !obj.loaded?
|
248
|
+
|
249
|
+
obj
|
250
|
+
end
|
251
|
+
|
252
|
+
##
|
253
|
+
# Search by attributes
|
254
|
+
#
|
255
|
+
# Refer to {MA's FAQ}[http://www.metal-archives.com/content/help?index=3#tab_db] for search tips.
|
256
|
+
#
|
257
|
+
# Returns rdoc-ref:Collection of rdoc-ref:Release
|
258
|
+
#
|
259
|
+
# [Raises]
|
260
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400
|
261
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
262
|
+
#
|
263
|
+
# [+query+]
|
264
|
+
# Hash containing one or more of the following keys:
|
265
|
+
# - +:band_name+: +String+
|
266
|
+
# - +:title+: +String+
|
267
|
+
# - +:from_year+: +Integer+
|
268
|
+
# - +:from_month+: +Integer+
|
269
|
+
# - +:to_year+: +Integer+
|
270
|
+
# - +:to_month+: +Integer+
|
271
|
+
# - +:country+: +ISO3166::Country+ or +Array+ of ISO3166::Country
|
272
|
+
# - +:location+: +String+
|
273
|
+
# - +:label_name+: +String+
|
274
|
+
# - +:indie+: +Boolean+
|
275
|
+
# - +:catalog_id+: +String+
|
276
|
+
# - +:identifier+: +String+, identifier (barcode, matrix, etc.)
|
277
|
+
# - +:recording_info+: +String+, recording information (studio, city, etc.)
|
278
|
+
# - +:version_description+: +String+, version description (country, digipak, etc.)
|
279
|
+
# - +:notes+: +String+
|
280
|
+
# - +:genre+: +String+
|
281
|
+
# - +:types+: +Array+ of +Symbol+, see rdoc-ref:Release.type
|
282
|
+
# - +:formats+: +Array+ of +Symbol+, see rdoc-ref:Release.format
|
283
|
+
#
|
284
|
+
def search_by(query)
|
285
|
+
params = Parsers::Release.map_params query
|
286
|
+
|
287
|
+
l = lambda do
|
288
|
+
@start ||= 0
|
289
|
+
|
290
|
+
if @max_items && @start >= @max_items
|
291
|
+
[]
|
292
|
+
else
|
293
|
+
response = MetalArchives.http.get "/search/ajax-advanced/searching/albums", params.merge(iDisplayStart: @start)
|
294
|
+
json = JSON.parse response.to_s
|
295
|
+
|
296
|
+
@max_items = json["iTotalRecords"]
|
297
|
+
|
298
|
+
objects = []
|
299
|
+
|
300
|
+
json["aaData"].each do |data|
|
301
|
+
# Create Release object for every ID in the results list
|
302
|
+
id = Nokogiri::HTML(data.first).xpath("//a/@href").first.value.delete('\\').split("/").last.gsub(/\D/, "").to_i
|
303
|
+
objects << Release.find(id)
|
304
|
+
end
|
305
|
+
|
306
|
+
@start += 200
|
307
|
+
|
308
|
+
objects
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
MetalArchives::Collection.new l
|
313
|
+
end
|
314
|
+
|
315
|
+
##
|
316
|
+
# Search by title, resolves to rdoc-ref:Release.search_by <tt>(:title => title)</tt>
|
317
|
+
#
|
318
|
+
# Refer to {MA's FAQ}[http://www.metal-archives.com/content/help?index=3#tab_db] for search tips.
|
319
|
+
#
|
320
|
+
# Returns (possibly empty) +Array+ of rdoc-ref:Release
|
321
|
+
#
|
322
|
+
# [Raises]
|
323
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400
|
324
|
+
# - rdoc-ref:MetalArchives::Errors::ArgumentError when +title+ isn't a +String+
|
325
|
+
#
|
326
|
+
# [+title+]
|
327
|
+
# +String+
|
328
|
+
#
|
329
|
+
def search(title)
|
330
|
+
raise MetalArchives::Errors::ArgumentError unless title.is_a? String
|
331
|
+
|
332
|
+
search_by title: title
|
333
|
+
end
|
334
|
+
|
335
|
+
##
|
336
|
+
# Get all releases
|
337
|
+
#
|
338
|
+
# Returns rdoc-ref:Collection of rdoc-ref:Release
|
339
|
+
#
|
340
|
+
# [Raises]
|
341
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400
|
342
|
+
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
343
|
+
#
|
344
|
+
def all
|
345
|
+
search ""
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|