quakelive_api 0.0.1 → 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 +1 -0
- data/.travis.yml +3 -2
- data/CHANGELOG.md +11 -0
- data/README.md +6 -2
- data/lib/quakelive_api/base.rb +23 -23
- data/lib/quakelive_api/game_time.rb +5 -5
- data/lib/quakelive_api/parser/awards.rb +21 -21
- data/lib/quakelive_api/parser/base.rb +1 -1
- data/lib/quakelive_api/parser/statistics.rb +17 -17
- data/lib/quakelive_api/parser/summary.rb +25 -24
- data/lib/quakelive_api/profile/awards/base.rb +10 -10
- data/lib/quakelive_api/profile/awards/career_milestones.rb +1 -1
- data/lib/quakelive_api/profile/awards/experience.rb +1 -1
- data/lib/quakelive_api/profile/awards/mad_skillz.rb +1 -1
- data/lib/quakelive_api/profile/awards/social_life.rb +4 -5
- data/lib/quakelive_api/profile/awards/sweet_success.rb +1 -1
- data/lib/quakelive_api/profile/statistics.rb +7 -7
- data/lib/quakelive_api/profile/summary.rb +21 -21
- data/lib/quakelive_api/version.rb +1 -1
- data/quakelive_api.gemspec +7 -6
- data/test/fixtures/awards/career_milestones.yml +262 -0
- data/test/fixtures/awards/experience.yml +1019 -0
- data/test/fixtures/profiles/emqz.yml +331 -0
- data/test/fixtures/profiles/error.yml +53 -0
- data/test/fixtures/profiles/full/awards_experience.yml +1019 -0
- data/test/fixtures/profiles/full/awards_milestones.yml +262 -0
- data/test/fixtures/profiles/full/awards_skillz.yml +592 -0
- data/test/fixtures/profiles/full/awards_social.yml +163 -0
- data/test/fixtures/profiles/full/awards_success.yml +449 -0
- data/test/fixtures/profiles/full/statistics.yml +438 -0
- data/test/fixtures/profiles/full/summary.yml +331 -0
- data/test/fixtures/profiles/mariano.yml +329 -0
- data/test/fixtures/profiles/not_existing.yml +57 -0
- data/test/fixtures/statistics/xsi.yml +438 -0
- data/test/quakelive_api/profile/awards/career_milestones_test.rb +8 -9
- data/test/quakelive_api/profile/awards/experience_test.rb +6 -7
- data/test/quakelive_api/profile/statistics_test.rb +31 -37
- data/test/quakelive_api/profile/summary_test.rb +60 -51
- data/test/quakelive_api/profile_test.rb +37 -32
- data/test/test_helper.rb +10 -30
- metadata +71 -72
- data/test/fixtures/awards/career.txt +0 -382
- data/test/fixtures/awards/experience.txt +0 -769
- data/test/fixtures/awards/mad_skillz.txt +0 -915
- data/test/fixtures/awards/social_life.txt +0 -155
- data/test/fixtures/awards/sweet_success.txt +0 -684
- data/test/fixtures/profile/error.txt +0 -24
- data/test/fixtures/profile/not_found.txt +0 -36
- data/test/fixtures/profile/summary.txt +0 -383
- data/test/fixtures/statistics/emqz.txt +0 -431
- data/test/fixtures/statistics/xsi.txt +0 -558
- data/test/fixtures/summary/emqz.txt +0 -304
- data/test/fixtures/summary/mariano.txt +0 -380
- data/test/quakelive_api/profile/awards/mad_skillz_test.rb +0 -38
- data/test/quakelive_api/profile/awards/social_life_test.rb +0 -38
- data/test/quakelive_api/profile/awards/sweet_success_test.rb +0 -38
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 709a918a29beb2d88f7beb75da2c7f6096adc835
|
4
|
+
data.tar.gz: d4a6265dead1d076be6ae38443f2c089c99a41ed
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e9840762fc084ddc77e0073bc7ec2bc45c2766e8e22f56bed4aee3b3e9b4399aeefc9879d01a02ee65e9ae97bd55b2e9becdeaca5b1b3b11567fbbc93ec5f531
|
7
|
+
data.tar.gz: aa5dee7c81d9251820f6b8b0fa8a54f5fc314d15aeeec57527e52c3529da9264c63a7310673c195e71849d100f916a84a06265445b8385cc967e214209588c3a
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
[![Code Climate](https://codeclimate.com/github/emq/quakelive_api.png)](https://codeclimate.com/github/emq/quakelive_api) [![Build Status](https://travis-ci.org/emq/quakelive_api.png?branch=master)](https://travis-ci.org/emq/quakelive_api)
|
2
|
-
|
3
1
|
# QuakeliveApi
|
4
2
|
|
3
|
+
[![Code Climate](https://codeclimate.com/github/emq/quakelive_api.png)](https://codeclimate.com/github/emq/quakelive_api)
|
4
|
+
[![Build Status](https://travis-ci.org/emq/quakelive_api.png?branch=master)](https://travis-ci.org/emq/quakelive_api)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/emq/quakelive_api/badge.png)](https://coveralls.io/r/emq/quakelive_api)
|
6
|
+
[![Dependency Status](https://gemnasium.com/emq/quakelive_api.png)](https://gemnasium.com/emq/quakelive_api)
|
7
|
+
[![Gem Version](https://badge.fury.io/rb/quakelive_api.png)](http://badge.fury.io/rb/quakelive_api)
|
8
|
+
|
5
9
|
This gem fetches (basic) publicly available data from [QuakeLive site][1]. Unfortunately currently there is no real API provided by ID so we're forced to parse html to get what we can. It will go down in flames if QL changes its internal html structure, so be prepared for that too.
|
6
10
|
|
7
11
|
The dirty job is made under `Parser` module (nothing pretty there, but response from QL is not pretty as well).
|
data/lib/quakelive_api/base.rb
CHANGED
@@ -18,35 +18,35 @@ module QuakeliveApi
|
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def get
|
22
|
+
Net::HTTP.get(URI.parse(URI::encode("#{QuakeliveApi.site}#{url}")))
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def url
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
def parser
|
30
|
+
@parser
|
31
|
+
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
def set_parser(document)
|
34
|
+
@parser ||= ::QuakeliveApi::Parser.const_get(self.class.class_name).new(document)
|
35
|
+
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
def self.class_name
|
38
|
+
name.split('::').last
|
39
|
+
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
def setup_variables!
|
42
|
+
raise Error::PlayerNotFound if parser.invalid_player?
|
43
|
+
raise Error::RequestError if parser.request_error?
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
setup_variables
|
46
|
+
end
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
def setup_variables
|
49
|
+
raise NotImplementedError
|
50
|
+
end
|
51
51
|
end
|
52
52
|
end
|
@@ -25,10 +25,10 @@ module QuakeliveApi
|
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
def reverse_match(string)
|
29
|
+
attrs = string.split(/\.|:/).reverse.map { |a| a.to_i }
|
30
|
+
(4 - attrs.size).times { attrs << 0 }
|
31
|
+
Interval.new(*attrs)
|
32
|
+
end
|
33
33
|
end
|
34
34
|
end
|
@@ -15,30 +15,30 @@ module QuakeliveApi
|
|
15
15
|
|
16
16
|
private
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
def selectors
|
19
|
+
{
|
20
|
+
earned: ".detailArea",
|
21
|
+
unearned: ".detailArea_off"
|
22
|
+
}
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
def parse_node(node)
|
26
|
+
attrs = {
|
27
|
+
icon: node.at('img')['src'],
|
28
|
+
info: node.at('img')['title'],
|
29
|
+
name: node.at('span.bigRedTxt').content,
|
30
|
+
description: node.at('span.blktxt_11').content,
|
31
|
+
awarded: awarded_at(node)
|
32
|
+
}
|
33
|
+
Items::Award.new(attrs)
|
34
|
+
end
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
def awarded_at(node)
|
37
|
+
return unless node.css('ul.fl li').count >= 3
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
matches = node.at('ul.fl li:first-child').content.match(/(\d{2})\/(\d{2})\/(\d{4})/)
|
40
|
+
Date.new(matches[3].to_i, matches[1].to_i, matches[2].to_i) unless matches.nil?
|
41
|
+
end
|
42
42
|
end
|
43
43
|
|
44
44
|
class CareerMilestones < Awards; end
|
@@ -5,14 +5,14 @@ module QuakeliveApi
|
|
5
5
|
def weapons
|
6
6
|
document.css(selector(:weapon)).each_with_index.map do |node, idx|
|
7
7
|
attrs = {
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
8
|
+
name: node.text,
|
9
|
+
frags: frags(weapon_next(:frags, idx)),
|
10
|
+
accuracy: accuracy(weapon_next(:accuracy, idx)),
|
11
|
+
usage: usage(weapon_next(:usage, idx))
|
12
12
|
}
|
13
13
|
|
14
14
|
hits, shots = hits_shots(weapon_next(:accuracy, idx))
|
15
|
-
attrs.merge!(:
|
15
|
+
attrs.merge!(hits: hits, shots: shots)
|
16
16
|
|
17
17
|
Items::Weapon.new(attrs)
|
18
18
|
end
|
@@ -26,13 +26,13 @@ module QuakeliveApi
|
|
26
26
|
next if no_records?
|
27
27
|
|
28
28
|
attrs = {
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
34
|
-
:
|
35
|
-
:
|
29
|
+
title: node.at('.col_st_gametype').text.strip,
|
30
|
+
played: to_integer(node.at('.col_st_played').text),
|
31
|
+
finished: to_integer(node.at('.col_st_finished').text),
|
32
|
+
wins: to_integer(node.at('.col_st_wins').text),
|
33
|
+
quits: to_integer(node.at('.col_st_withdraws').text),
|
34
|
+
completed: to_integer(node.at('.col_st_completeperc').text.gsub('%','')),
|
35
|
+
wins_percentage: to_integer(node.at('.col_st_winperc').text.gsub('%',''))
|
36
36
|
}
|
37
37
|
Items::Record.new(attrs)
|
38
38
|
end
|
@@ -42,11 +42,11 @@ module QuakeliveApi
|
|
42
42
|
|
43
43
|
def selectors
|
44
44
|
{
|
45
|
-
:
|
46
|
-
:
|
47
|
-
:
|
48
|
-
:
|
49
|
-
:
|
45
|
+
weapon: ".prf_weapons .col_weapon",
|
46
|
+
frags: ".col_frags",
|
47
|
+
accuracy: ".col_accuracy",
|
48
|
+
usage: ".col_usage",
|
49
|
+
record: ".qlv_profile_section_statistics .prf_record > div"
|
50
50
|
}
|
51
51
|
end
|
52
52
|
|
@@ -7,11 +7,12 @@ module QuakeliveApi
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def nick
|
10
|
-
document.at(selector(:nick)).text
|
10
|
+
document.at(selector(:nick)).xpath('text()').text.strip
|
11
11
|
end
|
12
12
|
|
13
13
|
def clan
|
14
|
-
|
14
|
+
clan_tag = document.at(selector(:clan))
|
15
|
+
clan_tag.text if clan_tag
|
15
16
|
end
|
16
17
|
|
17
18
|
def model
|
@@ -27,12 +28,12 @@ module QuakeliveApi
|
|
27
28
|
|
28
29
|
def last_game
|
29
30
|
node = vitals.at selector(:last)
|
30
|
-
|
31
|
+
decode_time(node['title']) if node
|
31
32
|
end
|
32
33
|
|
33
34
|
def time_played
|
34
35
|
node = vitals.at selector(:played)
|
35
|
-
|
36
|
+
GameTime.new(node['title']) if node
|
36
37
|
end
|
37
38
|
|
38
39
|
def wins
|
@@ -88,7 +89,7 @@ module QuakeliveApi
|
|
88
89
|
Items::RecentGame.new(gametype, finish, played, image)
|
89
90
|
end.compact
|
90
91
|
|
91
|
-
games.any?
|
92
|
+
games if games.any?
|
92
93
|
end
|
93
94
|
|
94
95
|
def recent_competitors
|
@@ -96,36 +97,36 @@ module QuakeliveApi
|
|
96
97
|
next if node.at('.rcmp_none')
|
97
98
|
|
98
99
|
icon = decode_background node.at('.usericon_standard_lg')['style']
|
99
|
-
nick = node.at('a.player_nick_dark').text
|
100
|
+
nick = node.at('a.player_nick_dark').xpath('child::text()').to_s
|
100
101
|
played = decode_time(node.at('span.text_tooltip')['title'])
|
101
102
|
|
102
103
|
Items::Competitor.new(icon, nick, played )
|
103
104
|
end.compact
|
104
105
|
|
105
|
-
competitors.any?
|
106
|
+
competitors if competitors.any?
|
106
107
|
end
|
107
108
|
|
108
109
|
private
|
109
110
|
|
110
111
|
def selectors
|
111
112
|
{
|
112
|
-
:
|
113
|
-
:
|
114
|
-
:
|
115
|
-
:
|
116
|
-
:
|
117
|
-
:
|
118
|
-
:
|
119
|
-
:
|
120
|
-
:
|
121
|
-
:
|
122
|
-
:
|
123
|
-
:
|
124
|
-
:
|
125
|
-
:
|
126
|
-
:
|
127
|
-
:
|
128
|
-
:
|
113
|
+
country: "img.playerflag",
|
114
|
+
nick: ".profile_title",
|
115
|
+
clan: ".profile_title a.clan",
|
116
|
+
model: ".prf_imagery div",
|
117
|
+
vitals: ".prf_vitals p",
|
118
|
+
member: "b:contains('Member Since')",
|
119
|
+
last: "b:contains('Last Game') + span",
|
120
|
+
played: "b:contains('Time Played') + span",
|
121
|
+
wins: "b:contains('Wins')",
|
122
|
+
losses: "b:contains('Losses')",
|
123
|
+
frags: "b:contains('Frags')",
|
124
|
+
hits: "b:contains('Hits')",
|
125
|
+
accuracy: "b:contains('Accuracy')",
|
126
|
+
favs: ".prf_faves b",
|
127
|
+
awards: ".prf_awards .awd_details",
|
128
|
+
games: ".recent_match",
|
129
|
+
competitors: "#qlv_profileBottomInset .rcmp_block"
|
129
130
|
}
|
130
131
|
end
|
131
132
|
|
@@ -6,18 +6,18 @@ module QuakeliveApi
|
|
6
6
|
|
7
7
|
private
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
def page
|
10
|
+
raise NotImplementedError
|
11
|
+
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
def url
|
14
|
+
"/profile/awards/#{player_name}/#{page}"
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
def setup_variables
|
18
|
+
@earned = parser.earned
|
19
|
+
@unearned = parser.unearned
|
20
|
+
end
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -5,14 +5,14 @@ module QuakeliveApi
|
|
5
5
|
|
6
6
|
private
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
def url
|
9
|
+
"/profile/statistics/#{player_name}"
|
10
|
+
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
def setup_variables
|
13
|
+
@weapons = parser.weapons
|
14
|
+
@records = parser.records
|
15
|
+
end
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -8,28 +8,28 @@ module QuakeliveApi
|
|
8
8
|
|
9
9
|
private
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def url
|
12
|
+
"/profile/summary/#{player_name}"
|
13
|
+
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
15
|
+
def setup_variables
|
16
|
+
@country = parser.country
|
17
|
+
@nick = parser.nick
|
18
|
+
@clan = parser.clan
|
19
|
+
@model = parser.model
|
20
|
+
@member_since = parser.member_since
|
21
|
+
@last_game = parser.last_game
|
22
|
+
@time_played = parser.time_played
|
23
|
+
@wins = parser.wins
|
24
|
+
@accuracy = parser.accuracy
|
25
|
+
@losses, @quits = parser.losses_quits
|
26
|
+
@frags, @deaths = parser.frags_deaths
|
27
|
+
@hits, @shots = parser.hits_shots
|
28
|
+
@favourite = parser.favourites
|
29
|
+
@recent_awards = parser.awards
|
30
|
+
@recent_games = parser.recent_games
|
31
|
+
@recent_competitors = parser.recent_competitors
|
32
|
+
end
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
data/quakelive_api.gemspec
CHANGED
@@ -18,11 +18,12 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency
|
21
|
+
spec.add_dependency 'nokogiri', '>= 1.5'
|
22
22
|
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'minitest', '~> 5.2.0'
|
26
|
+
spec.add_development_dependency 'webmock', '~> 1.18.0'
|
27
|
+
spec.add_development_dependency 'vcr', '~> 2.9.2'
|
28
|
+
spec.add_development_dependency 'coveralls', '~> 0.7.1'
|
28
29
|
end
|