metal_archives 2.1.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|