hots_api 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +12 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +197 -0
- data/bin/console +7 -0
- data/bin/rspec +4 -0
- data/bin/setup +8 -0
- data/hots_api.gemspec +24 -0
- data/lib/hots_api.rb +42 -0
- data/lib/hots_api/fetcher.rb +46 -0
- data/lib/hots_api/models/hero_translation.rb +10 -0
- data/lib/hots_api/models/map_translation.rb +10 -0
- data/lib/hots_api/models/model.rb +11 -0
- data/lib/hots_api/models/player.rb +14 -0
- data/lib/hots_api/models/replay.rb +26 -0
- data/lib/hots_api/models/uploaded_replay.rb +22 -0
- data/lib/hots_api/repositories/hero_translation_repository.rb +17 -0
- data/lib/hots_api/repositories/map_translation_repository.rb +17 -0
- data/lib/hots_api/repositories/replay_repository.rb +86 -0
- data/lib/hots_api/repositories/repository.rb +94 -0
- data/lib/hots_api/version.rb +5 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 85fa5449294a897c754bd86e1b20a40fa582be9b
|
4
|
+
data.tar.gz: 4a9d18c63be08574f5e655df491aab57faf55186
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ec51284bc413a0d7e21be5869e09ae8af8e4f475cc14ec0a0f61cc0dded102975996f1c230f8398c6a08a2e3b831c4398a13af4f2d3f21d0a81dbb22f54911e9
|
7
|
+
data.tar.gz: 6630b7edadd30698a5e9d6026e46e6efff162a410619a42496d527a68fc8ff95ade71f688995b1896b7eb75dc60ec7145314ae966138aae19a1e9172965b0adf
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Tobias Bühlmann
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
# HotsApi
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/tbuehlmann/hots_api.svg?branch=master)](https://travis-ci.org/tbuehlmann/hots_api)
|
4
|
+
|
5
|
+
HotsApi is an API client for the Heroes of the Storm replay metadata API [hotsapi.net](http://hotsapi.net/). It consumes the API and lets you retrieve information about uploaded replays.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'hots_api'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install hots_api
|
22
|
+
|
23
|
+
## Finding Replays
|
24
|
+
|
25
|
+
#### Finding a Single Replay
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
replay = HotsApi.replays.find(59) # => #<HotsApi::Models::Replay>
|
29
|
+
replay.id # => 59
|
30
|
+
replay.filename # => '04e92942-7a46-f12c-24f6-65dcf4ea409f'
|
31
|
+
replay.fingerprint # => '04e92942-7a46-2cf1-24f6-65dcf4ea409f'
|
32
|
+
replay.game_date # => 2017-08-15 23:16:28 +0200
|
33
|
+
replay.game_length # => 872
|
34
|
+
replay.game_map # => 'Braxis Holdout'
|
35
|
+
replay.game_type # => 'HeroLeague'
|
36
|
+
replay.game_version # => '2.27.1.56361'
|
37
|
+
replay.players # => [#<HotsApi::Models::Player>, …]
|
38
|
+
|
39
|
+
player = replay.players[0] # => #<HotsApi::Models::Player>
|
40
|
+
player.blizz_id # => 215378
|
41
|
+
player.battletag # => 'Poma'
|
42
|
+
player.hero # => 'Chromie'
|
43
|
+
player.hero_level # => 13
|
44
|
+
player.team # => 0
|
45
|
+
player.winner # => true
|
46
|
+
```
|
47
|
+
|
48
|
+
#### Finding Replays
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
replays = HotsApi.replays.to_a # => [#<HotsApi::Models::Replay>, …]
|
52
|
+
```
|
53
|
+
|
54
|
+
#### Filtering Replays
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
# by game date
|
58
|
+
replays = HotsApi.replays.where(start_date: '2017-09-01 00:00').to_a
|
59
|
+
replays = HotsApi.replays.where(end_date: '2017-09-01 00:00').to_a
|
60
|
+
|
61
|
+
# by game type
|
62
|
+
replays = HotsApi.replays.where(game_type: 'HeroLeague').to_a
|
63
|
+
|
64
|
+
# by id
|
65
|
+
replays = HotsApi.replays.where(min_id: 1000).to_a
|
66
|
+
|
67
|
+
# by player
|
68
|
+
replays = HotsApi.replays.where(player: 'Poma').to_a
|
69
|
+
|
70
|
+
# by hero
|
71
|
+
replays = HotsApi.replays.where(hero: 'Tassadar').to_a
|
72
|
+
|
73
|
+
# conditions are chainable
|
74
|
+
replays = HotsApi.replays.where(start_date: '2017-09-01 00:00', end_date: '2017-09-01 23:59').where(game_type: 'HeroLeague').to_a
|
75
|
+
```
|
76
|
+
|
77
|
+
#### Include Players
|
78
|
+
|
79
|
+
Replays don't include its players per default. If you want to include players, use `with_players` (which is also chainable):
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
replays = HotsApi.replays.with_players.to_a
|
83
|
+
replays = HotsApi.replays.where(start_date: '2017-09-01 00:00').with_players.to_a
|
84
|
+
```
|
85
|
+
|
86
|
+
#### Pagination
|
87
|
+
|
88
|
+
The API returns a maximum of 100 replays per request. If you want to retrieve all replays for a given query, use `find_each`:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
HotsApi.replays.where(start_date: '2017-09-01 00:00', end_date: '2017-09-01 23:59').find_each do |replay|
|
92
|
+
# …
|
93
|
+
end
|
94
|
+
|
95
|
+
# or
|
96
|
+
|
97
|
+
replays = HotsApi.replays.where(start_date: '2017-09-01 00:00', end_date: '2017-09-01 23:59').find_each.to_a
|
98
|
+
```
|
99
|
+
|
100
|
+
Note that this might take some time, depending on the query's replay count.
|
101
|
+
|
102
|
+
## Replay Utilities
|
103
|
+
|
104
|
+
#### Uploading Replays
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
uploaded_replay = HotsApi.replays.upload('/path/to/Garden of Terror.StormReplay') # => #<HotsApi::Models::UploadedReplay>
|
108
|
+
uploaded_replay.id # => 2431959
|
109
|
+
uploaded_replay.filename # => '1745472b-94a0-2b2d-3f14-8794717545fc'
|
110
|
+
uploaded_replay.original_name # => 'Garden of Terror.StormReplay'
|
111
|
+
uploaded_replay.status # => 'duplicate'
|
112
|
+
uploaded_replay.success # => true
|
113
|
+
uploaded_replay.url # => 'http://hotsapi.s3-website-eu-west-1.amazonaws.com/1745472b-94a0-2b2d-3f14-8794717545fc.StormReplay'
|
114
|
+
```
|
115
|
+
|
116
|
+
You can also retrieve the replay for a given uploaded replay:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
uploaded_replay.replay # => #<HotsApi::Models::Replay>
|
120
|
+
```
|
121
|
+
|
122
|
+
#### Checking for Replay Existence
|
123
|
+
|
124
|
+
Check whether a given replay was uploaded by its fingerprint:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
HotsApi.replays.fingerprint_uploaded?('04e92942-7a46-2cf1-24f6-65dcf4ea409f') # => true
|
128
|
+
HotsApi.replays.fingerprint_uploaded?('non-existing-fingerprint') # => false
|
129
|
+
```
|
130
|
+
|
131
|
+
Check whether given replays were uploaded by its fingerprints:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
fingerprints = ['04e92942-7a46-2cf1-24f6-65dcf4ea409f', 'non-existing-fingerprint']
|
135
|
+
HotsApi.replays.fingerprints_uploaded?(fingerprints) # => {'04e92942-7a46-2cf1-24f6-65dcf4ea409f' => true, 'non-existing-fingerprint' => false}
|
136
|
+
```
|
137
|
+
|
138
|
+
#### Triggering HotsLogs Uploads
|
139
|
+
|
140
|
+
If there's a replay saved on HotsApi, you can trigger uploading it to HotsLogs by its fingerprint:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
fingerprint = '04e92942-7a46-2cf1-24f6-65dcf4ea409f'
|
144
|
+
upload_triggered = HotsApi.replays.trigger_hotslogs_upload(fingerprint)
|
145
|
+
|
146
|
+
if upload_triggered
|
147
|
+
puts 'Triggered HotsLogs upload'
|
148
|
+
else
|
149
|
+
puts 'Replay for given fingerprint does not exist'
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
The actual uploading to HotsLogs happens from the HotsApi server.
|
154
|
+
|
155
|
+
#### Getting The Minimal Supported Build Version
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
HotsApi.replays.minimum_supported_build # => 43905
|
159
|
+
```
|
160
|
+
|
161
|
+
## Finding Hero Translations
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
hero_translations = HotsApi.hero_translations.to_a # => [#<HotsApi::Models::HeroTranslation>, …]
|
165
|
+
|
166
|
+
hero_translation = hero_translations[0] # => #<HotsApi::Models::HeroTranslation>
|
167
|
+
hero_translation.name # => 'Abathur'
|
168
|
+
hero_translation.versions # => ['abatur', 'абатур', '아바투르', '阿巴瑟', 'abathur']
|
169
|
+
```
|
170
|
+
|
171
|
+
## Finding Map Translations
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
map_translations = HotsApi.map_translations.to_a # => [#<HotsApi::Models::MapTranslation>, …]
|
175
|
+
|
176
|
+
map_translation = map_translations[0] # => #<HotsApi::Models::MapTranslation>
|
177
|
+
map_translation.name # => 'Battlefield of Eternity'
|
178
|
+
map_translation.versions # => ["campo de batalha da eternidade", "campo de batalla de la eternidad", "永恆戰場", "永恒战场", "영원의 전쟁터", "campos de batalla de la eternidad", "schlachtfeld der ewigkeit", "champs de l’éternité", "вечная битва", "campi di battaglia eterni", "pole bitewne wieczności", "battlefield of eternity"]
|
179
|
+
```
|
180
|
+
|
181
|
+
## Rate Limiting
|
182
|
+
|
183
|
+
The API probably uses some kind of leaky bucket algorithm for rate limiting. It allows for 300 requests in a short period of time and refills this pool of available requests every other second.
|
184
|
+
|
185
|
+
When the client requests the API and hits the request rate limit, it will sleep for 0.5 seconds and try again after that. It will retry 9 times for a given query. If it hits the rate limit on its last try, it will raise a `HotsApi::Fetcher::ApiLimitReachedError`.
|
186
|
+
|
187
|
+
## Development
|
188
|
+
|
189
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
190
|
+
|
191
|
+
## Contributing
|
192
|
+
|
193
|
+
Bug reports and pull requests are welcome on [GitHub](https://github.com/tbuehlmann/hots_api).
|
194
|
+
|
195
|
+
## License
|
196
|
+
|
197
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/bin/console
ADDED
data/bin/rspec
ADDED
data/bin/setup
ADDED
data/hots_api.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'lib/hots_api/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'hots_api'
|
5
|
+
spec.version = HotsApi::VERSION
|
6
|
+
spec.authors = ['Tobias Bühlmann']
|
7
|
+
spec.email = ['tobias@xn--bhlmann-n2a.de']
|
8
|
+
|
9
|
+
spec.summary = 'Client library for the hotsapi.net API'
|
10
|
+
spec.description = 'hots_api is a client library for the Heroes of the Storm replay metadata API hotsapi.net.'
|
11
|
+
spec.homepage = 'https://github.com/tbuehlmann/hots_api'
|
12
|
+
spec.license = 'MIT'
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
15
|
+
f.match(%r{^(test|spec|features)/})
|
16
|
+
end
|
17
|
+
|
18
|
+
spec.bindir = 'exe'
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_dependency 'virtus', '~> 1.0'
|
23
|
+
spec.add_dependency 'http', '~> 2.0'
|
24
|
+
end
|
data/lib/hots_api.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'hots_api/fetcher'
|
4
|
+
require_relative 'hots_api/version'
|
5
|
+
|
6
|
+
require_relative 'hots_api/models/model'
|
7
|
+
require_relative 'hots_api/models/hero_translation'
|
8
|
+
require_relative 'hots_api/models/map_translation'
|
9
|
+
require_relative 'hots_api/models/player'
|
10
|
+
require_relative 'hots_api/models/replay'
|
11
|
+
require_relative 'hots_api/models/uploaded_replay'
|
12
|
+
|
13
|
+
require_relative 'hots_api/repositories/repository'
|
14
|
+
require_relative 'hots_api/repositories/hero_translation_repository'
|
15
|
+
require_relative 'hots_api/repositories/map_translation_repository'
|
16
|
+
require_relative 'hots_api/repositories/replay_repository'
|
17
|
+
|
18
|
+
module HotsApi
|
19
|
+
def self.fetcher
|
20
|
+
@fetcher ||= Fetcher.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.get(path, params: {})
|
24
|
+
fetcher.get(path, params: params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.post(path, body: nil, file: nil)
|
28
|
+
fetcher.post(path, body: body, file: file)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.replays
|
32
|
+
Repositories::ReplayRepository.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.hero_translations
|
36
|
+
Repositories::HeroTranslationRepository.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.map_translations
|
40
|
+
Repositories::MapTranslationRepository.new
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'http'
|
4
|
+
|
5
|
+
module HotsApi
|
6
|
+
class Fetcher
|
7
|
+
ApiLimitReachedError = Class.new(StandardError)
|
8
|
+
|
9
|
+
attr_reader :last_response
|
10
|
+
|
11
|
+
def get(path, params: {})
|
12
|
+
with_retrying do
|
13
|
+
HTTP.get("http://hotsapi.net/api/v1/#{path}", params: params)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def post(path, body: nil, file: nil)
|
18
|
+
with_retrying do
|
19
|
+
HTTP.post("http://hotsapi.net/api/v1/#{path}", post_options_for(body: body, file: file))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def post_options_for(body:, file:)
|
26
|
+
{}.tap do |options|
|
27
|
+
options[:body] = body if body
|
28
|
+
options[:form] = {file: HTTP::FormData::File.new(file)} if file
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def with_retrying(tries: 10)
|
33
|
+
tries.times do |try|
|
34
|
+
response = yield
|
35
|
+
|
36
|
+
if response.status.too_many_requests? && try < tries - 1
|
37
|
+
sleep 0.5
|
38
|
+
else
|
39
|
+
return @last_response = response
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
raise ApiLimitReachedError, "API limit reached, tried #{tries} times"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HotsApi
|
4
|
+
module Models
|
5
|
+
class Player < Model
|
6
|
+
attribute :battletag, String
|
7
|
+
attribute :hero, String
|
8
|
+
attribute :hero_level, Integer
|
9
|
+
attribute :team, Integer
|
10
|
+
attribute :winner, Boolean
|
11
|
+
attribute :blizz_id, Integer
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HotsApi
|
4
|
+
module Models
|
5
|
+
class Replay < Model
|
6
|
+
attribute :id, Integer
|
7
|
+
attribute :filename, String
|
8
|
+
attribute :size, Integer
|
9
|
+
attribute :game_type, String
|
10
|
+
attribute :game_date, Time
|
11
|
+
attribute :game_length, Integer
|
12
|
+
attribute :game_map, String
|
13
|
+
attribute :game_version, String
|
14
|
+
attribute :region, Integer
|
15
|
+
attribute :fingerprint, String
|
16
|
+
attribute :url, String
|
17
|
+
attribute :players, Array[Player]
|
18
|
+
|
19
|
+
def reload
|
20
|
+
tap do
|
21
|
+
self.attributes = HotsApi.replays.find(id).attributes
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HotsApi
|
4
|
+
module Models
|
5
|
+
class UploadedReplay < Model
|
6
|
+
attribute :id, Integer
|
7
|
+
attribute :success, Boolean
|
8
|
+
attribute :original_name, String
|
9
|
+
attribute :status, String
|
10
|
+
attribute :filename, String
|
11
|
+
attribute :url, String
|
12
|
+
|
13
|
+
def originalName=(name)
|
14
|
+
self.original_name = name
|
15
|
+
end
|
16
|
+
|
17
|
+
def replay
|
18
|
+
HotsApi.replays.find(id) if id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HotsApi
|
4
|
+
module Repositories
|
5
|
+
class ReplayRepository < Repository
|
6
|
+
def upload(file)
|
7
|
+
response = HotsApi.post('replays', file: file)
|
8
|
+
Models::UploadedReplay.new(response.parse)
|
9
|
+
end
|
10
|
+
|
11
|
+
def trigger_hotslogs_upload(fingerprint)
|
12
|
+
HotsApi.get("replays/fingerprints/v3/#{fingerprint}", params: {uploadToHotslogs: 1}).parse['exists']
|
13
|
+
end
|
14
|
+
|
15
|
+
def fingerprint_uploaded?(fingerprint)
|
16
|
+
HotsApi.get("replays/fingerprints/v3/#{fingerprint}").parse['exists']
|
17
|
+
end
|
18
|
+
|
19
|
+
def fingerprints_uploaded?(fingerprints)
|
20
|
+
return {} if fingerprints.empty?
|
21
|
+
|
22
|
+
upload_statuses = HotsApi.post('replays/fingerprints', body: fingerprints.join("\n")).parse
|
23
|
+
|
24
|
+
{}.tap do |fingerprint_statuses|
|
25
|
+
upload_statuses['exists'].each do |fingerprint|
|
26
|
+
fingerprint_statuses[fingerprint] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
upload_statuses['absent'].each do |fingerprint|
|
30
|
+
fingerprint_statuses[fingerprint] = false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def minimum_supported_build
|
36
|
+
HotsApi.get('replays/min-build').to_s.to_i
|
37
|
+
end
|
38
|
+
|
39
|
+
def with_players
|
40
|
+
spawn { where_values[:with_players] = 1 }
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def start_date=(date)
|
46
|
+
where_values[:start_date] = date_string_for(date)
|
47
|
+
end
|
48
|
+
|
49
|
+
def end_date=(date)
|
50
|
+
where_values[:end_date] = date_string_for(date)
|
51
|
+
end
|
52
|
+
|
53
|
+
def game_type=(game_type)
|
54
|
+
where_values[:game_type] = game_type
|
55
|
+
end
|
56
|
+
|
57
|
+
def min_id=(id)
|
58
|
+
where_values[:min_id] = id
|
59
|
+
end
|
60
|
+
|
61
|
+
def player=(player)
|
62
|
+
where_values[:player] = player
|
63
|
+
end
|
64
|
+
|
65
|
+
def hero=(hero)
|
66
|
+
where_values[:hero] = hero
|
67
|
+
end
|
68
|
+
|
69
|
+
def date_string_for(date)
|
70
|
+
if date.respond_to?(:strftime)
|
71
|
+
date.strftime('%F %T')
|
72
|
+
else
|
73
|
+
date.to_s
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def path
|
78
|
+
'replays'
|
79
|
+
end
|
80
|
+
|
81
|
+
def model
|
82
|
+
Models::Replay
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HotsApi
|
4
|
+
module Repositories
|
5
|
+
class Repository
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize_copy(_original)
|
9
|
+
@records = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def find(id)
|
13
|
+
response = HotsApi.get("#{path}/#{id}")
|
14
|
+
|
15
|
+
if response.status.ok?
|
16
|
+
model.new(response.parse)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def where(conditions = {})
|
21
|
+
spawn do
|
22
|
+
conditions.each do |attribute, value|
|
23
|
+
if respond_to?("#{attribute}=", true)
|
24
|
+
send("#{attribute}=", value)
|
25
|
+
else
|
26
|
+
raise "Unknown attribute: #{attribute}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def next_page
|
33
|
+
if records.any?
|
34
|
+
where(min_id: records.last.id + 1)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def each(&block)
|
39
|
+
records.each(&block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_each(&block)
|
43
|
+
find_each_enum.each(&block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def last(n = nil)
|
47
|
+
n ? records.last(n) : records.last
|
48
|
+
end
|
49
|
+
|
50
|
+
def spawn(&block)
|
51
|
+
clone.tap do |repository|
|
52
|
+
repository.instance_exec(&block)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def find_each_enum
|
59
|
+
Enumerator.new do |yielder|
|
60
|
+
page = self
|
61
|
+
|
62
|
+
while page && page.any?
|
63
|
+
page.each { |model| yielder << model }
|
64
|
+
page = page.next_page
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def where_values
|
70
|
+
@where_values ||= {}
|
71
|
+
end
|
72
|
+
|
73
|
+
def records
|
74
|
+
@records ||= fetch_records
|
75
|
+
end
|
76
|
+
|
77
|
+
def fetch_records
|
78
|
+
response = HotsApi.get(path, params: where_values)
|
79
|
+
|
80
|
+
response.parse.map do |attributes|
|
81
|
+
model.new(attributes)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def path
|
86
|
+
raise NotImplementedError
|
87
|
+
end
|
88
|
+
|
89
|
+
def model
|
90
|
+
raise NotImplementedError
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hots_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tobias Bühlmann
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: virtus
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: http
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
description: hots_api is a client library for the Heroes of the Storm replay metadata
|
42
|
+
API hotsapi.net.
|
43
|
+
email:
|
44
|
+
- tobias@xn--bhlmann-n2a.de
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- ".rspec"
|
51
|
+
- ".travis.yml"
|
52
|
+
- Gemfile
|
53
|
+
- LICENSE.txt
|
54
|
+
- README.md
|
55
|
+
- bin/console
|
56
|
+
- bin/rspec
|
57
|
+
- bin/setup
|
58
|
+
- hots_api.gemspec
|
59
|
+
- lib/hots_api.rb
|
60
|
+
- lib/hots_api/fetcher.rb
|
61
|
+
- lib/hots_api/models/hero_translation.rb
|
62
|
+
- lib/hots_api/models/map_translation.rb
|
63
|
+
- lib/hots_api/models/model.rb
|
64
|
+
- lib/hots_api/models/player.rb
|
65
|
+
- lib/hots_api/models/replay.rb
|
66
|
+
- lib/hots_api/models/uploaded_replay.rb
|
67
|
+
- lib/hots_api/repositories/hero_translation_repository.rb
|
68
|
+
- lib/hots_api/repositories/map_translation_repository.rb
|
69
|
+
- lib/hots_api/repositories/replay_repository.rb
|
70
|
+
- lib/hots_api/repositories/repository.rb
|
71
|
+
- lib/hots_api/version.rb
|
72
|
+
homepage: https://github.com/tbuehlmann/hots_api
|
73
|
+
licenses:
|
74
|
+
- MIT
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.6.13
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: Client library for the hotsapi.net API
|
96
|
+
test_files: []
|