xbox_live 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in xbox_live.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # XboxLive
2
+
3
+ XboxLive enables retrieval of player, game, and achievement data from
4
+ the Xbox Live web site.
5
+
6
+ ## Status
7
+
8
+ This is an early pre-release version! The API is almost certain to
9
+ change before the 1.0 release.
10
+
11
+ Questions and suggestions are welcomed, as are pull requests.
12
+
13
+ ## Installation
14
+
15
+ Include the gem in your Gemfile:
16
+
17
+ gem "xbox_live"
18
+
19
+ Or, if you aren't using Bundler, just run:
20
+
21
+ gem install xbox_live
22
+
23
+ ## Configuration
24
+
25
+ An Xbox Live username and password must be provided so that the gem
26
+ can log into the Xbox Live web site to retrieve data.
27
+
28
+ To configure these settings, include the following lines (substituting
29
+ your information) in your program, or for Rails applications, create
30
+ a `config/initializers/xbox_live.rb` file and add the lines there:
31
+
32
+ # Your Xbox Live login and password
33
+ XboxLive.options[:username] = 'your@email.address'
34
+ XboxLive.options[:password] = 'password'
35
+
36
+ Two optional configuration options are also available, but are not
37
+ required to be set:
38
+
39
+ # Pages retrieved from Xbox Live are cached for 10 minutes (600
40
+ # seconds) by default, to prevent unnecessary reloads from the Xbox
41
+ # Live web site. The maximum cache age can be changed here.
42
+ XboxLive.options[:refresh_age] = 300 # Cache for only 5 minutes
43
+
44
+ # Show debugging output on the console.
45
+ XboxLive.options[:debug] = true
46
+
47
+ ## Example
48
+
49
+ Below is a short sample stand-alone program to demonstrate basic
50
+ functionality. This sample program is also included in the git
51
+ repository.
52
+
53
+ require 'xbox_live'
54
+
55
+ # Your Xbox Live login and password
56
+ XboxLive.options[:username] = 'your@email.address'
57
+ XboxLive.options[:password] = 'password'
58
+
59
+ player = 'gamertag'
60
+
61
+ profile_page = XboxLive::ProfilePage.new(player)
62
+ puts "Gamerscore: #{profile_page.gamerscore}"
63
+
64
+ games_page = XboxLive::GamesPage.new(player)
65
+ first_game = games_page.games.first
66
+ puts "Score in '#{first_game.name}': #{first_game.unlocked_points} out of #{first_game.total_points}"
67
+
68
+ achievements_page = XboxLive::AchievementsPage.new(player, first_game.id)
69
+ first_ach = achievements_page.achievements.first
70
+ puts "Unlocked achievement '#{first_ach.name}' on #{first_ach.unlocked_on}"
71
+
72
+ This will output something along these lines (depending on the gamertag
73
+ entered for the `player` variable:
74
+
75
+ Gamerscore: 9454.
76
+ Score in 'Battlefield 3': 100 out of 1000.
77
+ Unlocked achievement '1st Loser' on 10/28/2011.
78
+
79
+ ## Available Data
80
+
81
+ The `XboxLive::ProfilePage` class makes the following data available
82
+ from a player's Profile page, via a call like `profile_page =
83
+ XboxLive::ProfilePage.new(gamertag)`:
84
+
85
+ * `profile_page.gamertag`
86
+ * `profile_page.gamerscore`
87
+ * `profile_page.motto`
88
+ * `profile_page.avatar`
89
+ * `profile_page.gamertile_small`
90
+ * `profile_page.nickname`
91
+ * `profile_page.bio`
92
+ * `profile_page.presence`
93
+
94
+ The `XboxLive::GamesPage` class makes the following data available from
95
+ a player's Game Comparison page, via a call like `games_page =
96
+ XboxLive::GamesPage.new(gamertag)`:
97
+
98
+ * `games_page.gamertag`
99
+ * `games_page.gamertile_large`
100
+ * `games_page.gamerscore`
101
+ * `games_page.progress`
102
+ * `games_page.games` _(see below)_
103
+
104
+ `games_page.games` is an Array of XboxLive::GameInfo instances, which track information about a
105
+ player's progress in a game. Each GameInfo instance makes the following data available:
106
+
107
+ * `game_info.id` - unique Microsoft identifier
108
+ * `game_info.name`
109
+ * `game_info.tile`
110
+ * `game_info.total_points`
111
+ * `game_info.total_achievements`
112
+ * `game_info.gamertag`
113
+ * `game_info.unlocked_points`
114
+ * `game_info.unlocked_achievements`
115
+ * `game_info.last_played`
116
+
117
+ The `XboxLive::AchievementsPage` class makes the following data
118
+ available from a player's Game Achievement Comparison page, via a call
119
+ like `ach_page = XboxLive::AchievementsPage.new(gamertag, game_id)`:
120
+
121
+ * `ach_page.gamertag`
122
+ * `ach_page.game_id`
123
+ * `ach_page.achievements` _(see below)_
124
+
125
+ `ach_page.achievements` is an Array of XboxLive::AchievementInfo
126
+ instances, which track information about a player's achievements in a
127
+ game. Each AchievementInfo instance makes the following data available:
128
+
129
+ * `ach_info.id` - Microsoft identifier, unique only within this game
130
+ * `ach_info.gamertag`
131
+ * `ach_info.game_id`
132
+ * `ach_info.name`
133
+ * `ach_info.description`
134
+ * `ach_info.tile`
135
+ * `ach_info.points`
136
+ * `ach_info.unlocked_at` - nil if the player has not yet unlocked it
137
+
138
+ ## Caveats
139
+
140
+ The contents, layout, and authentication scheme for the Xbox Live web
141
+ site may change at any time, and historically has changed several times
142
+ per year. These changes will almost certainly break the functionality
143
+ of this gem, requiring a new version of the gem to be coded and
144
+ released.
145
+
146
+ ## To Do for Version 1.0
147
+
148
+ * Write tests
149
+ * Refactor
150
+ * Improve API
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new('spec')
data/example-usage.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'xbox_live'
2
+
3
+ # Your Xbox Live login and password
4
+ XboxLive.options[:username] = 'your@email.address'
5
+ XboxLive.options[:password] = 'password'
6
+ XboxLive.options[:debug] = false
7
+
8
+ player = 'gamertag'
9
+
10
+ profile_page = XboxLive::ProfilePage.new(player)
11
+ puts "Gamerscore: #{profile_page.gamerscore}"
12
+
13
+ games_page = XboxLive::GamesPage.new(player)
14
+ first_game = games_page.games.first
15
+ puts "Score in '#{first_game.name}': #{first_game.unlocked_points} out of #{first_game.total_points}"
16
+
17
+ achievements_page = XboxLive::AchievementsPage.new(player, first_game.id)
18
+ first_ach = achievements_page.achievements.first
19
+ puts "Unlocked achievement '#{first_ach.name}' on #{first_ach.unlocked_on}"
20
+
@@ -0,0 +1,19 @@
1
+ module XboxLive
2
+
3
+ # Each AchievementInfo tracks information about a player's progress in a
4
+ # specific achievement.
5
+ class AchievementInfo
6
+
7
+ attr_accessor :id, :game_id, :gamertag, :name, :description, :tile, :points, :unlocked_at
8
+
9
+ # Create a new AchievementInfo for the provided player and game.
10
+ def initialize(gamertag, game_id, achievement_id)
11
+ @gamertag = gamertag
12
+ @game_id = game_id
13
+ @id = achievement_id
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+
@@ -0,0 +1,83 @@
1
+ module XboxLive
2
+
3
+ # Each AchievementsPage tracks and makes available the data contianed
4
+ # in an Xbox Live "Compare Game" page. This can be used to determine
5
+ # which achievements a player has unlocked in a game.
6
+ #
7
+ # Example: http://live.xbox.com/en-US/Activity/Details?titleId=1161890128&compareTo=someone
8
+ class AchievementsPage
9
+
10
+ attr_accessor :gamertag, :game_id, :page, :url, :updated_at, :achievements, :data
11
+
12
+ # Create a new AchievementsPage for the provided gamertag. Retrieve
13
+ # the html compare achievements page from the Xbox Live web site for
14
+ # analysis. To prevent multiple instances for the same gamertag,
15
+ # this method is marked as private. The AchievementsPage.find()
16
+ # method should be used to find an existing instance or create a new
17
+ # one if needed.
18
+ def initialize(gamertag, game_id)
19
+ @gamertag = gamertag
20
+ @game_id = game_id
21
+ refresh
22
+ end
23
+
24
+
25
+ # Force a reload of the AchievementsPage data from the Xbox Live web site.
26
+ def refresh
27
+ url = XboxLive.options[:url_prefix] + '/en-US/Activity/Details?' +
28
+ Mechanize::Util.build_query_string(titleId: @game_id, compareTo: @gamertag)
29
+ @page = XboxLive::Scraper::get_page url
30
+ return false if page.nil?
31
+
32
+ @url = url
33
+ @updated_at = Time.now
34
+ @data = retrieve_achievement_data
35
+ @gamertag = find_gamertag
36
+ @achievements = find_achievements
37
+
38
+ true
39
+ end
40
+
41
+
42
+ private
43
+
44
+ # POST to retrieve the JSON data about achievements for this game
45
+ def retrieve_achievement_data
46
+ data = @page.body.match(/loadCompareView\((.+)\)\;/)[1]
47
+ JSON.parse(data)
48
+ end
49
+
50
+ # Find the gamertag, in case the caps/lowercase are different than
51
+ # what was provided.
52
+ def find_gamertag
53
+ player = @data['Players'].find { |p| p['Gamertag'].casecmp(@gamertag) == 0 }
54
+ player ? player['Gamertag'] : nil
55
+ end
56
+
57
+ # Find and return an array of hashes containing information about each
58
+ # achievement the player has unlocked.
59
+ def find_achievements
60
+ achievements = @data['Achievements'].collect do |ach|
61
+ ai = AchievementInfo.new(gamertag, @game_id, ach['Id'])
62
+ ai.name = ach['Name']
63
+ ai.description = ach['Description']
64
+ ai.tile = ach['TileUrl']
65
+ if unlocked?(ach)
66
+ ai.points = ach['Score']
67
+ # TODO: Refactor this mess
68
+ time_field = ach['EarnDates'][@gamertag]['EarnedOn'].match(/Date\((\d+)/)
69
+ ai.unlocked_at = Time.at(time_field[1].to_i / 1000) if time_field
70
+ end
71
+ ai
72
+ end
73
+ achievements
74
+ end
75
+
76
+ # Has the player unlocked this achievement?
77
+ def unlocked?(ach)
78
+ !!ach['EarnDates'][@gamertag]
79
+ end
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,18 @@
1
+ module XboxLive
2
+
3
+ # Each GameInfo tracks information about a player's progress in a
4
+ # specific game.
5
+ class GameInfo
6
+
7
+ attr_accessor :id, :name, :tile, :gamertag, :total_points, :unlocked_points,
8
+ :total_achievements, :unlocked_achievements, :last_played
9
+
10
+ # Create a new GameInfo for the provided player and game.
11
+ def initialize(gamertag, game_id)
12
+ @gamertag = gamertag
13
+ @id = game_id
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,106 @@
1
+ module XboxLive
2
+
3
+ # Each GamesPage tracks the data contianed in an Xbox Live "Compare
4
+ # Games" page. This can be used to determine which games a player has
5
+ # played, and their score and number of achievements acquired in each
6
+ # game.
7
+ #
8
+ # Example: http://live.xbox.com/en-US/Activity?compareTo=someone
9
+ class GamesPage
10
+
11
+ attr_accessor :gamertag, :page, :url, :updated_at, :gamertile_large,
12
+ :gamerscore, :progress, :games, :data
13
+
14
+
15
+ # Create a new GamesPage for the provided gamertag. Retrieve the
16
+ # html game compare page from the Xbox Live web site for analysis.
17
+ def initialize(gamertag)
18
+ @gamertag = gamertag
19
+ refresh
20
+ end
21
+
22
+
23
+ # Force a reload of the GamesPage data from the Xbox Live web site.
24
+ def refresh
25
+ url = XboxLive.options[:url_prefix] + '/en-US/Activity?' +
26
+ Mechanize::Util.build_query_string(compareTo: @gamertag)
27
+ @page = XboxLive::Scraper::get_page(url)
28
+ return false if page.nil?
29
+
30
+ @url = url
31
+ @updated_at = Time.now
32
+ @data = retrieve_game_data
33
+ @gamertag = find_gamertag
34
+ @gamertile_large = find_gamertile_large
35
+ @gamerscore = find_gamerscore
36
+ @progress = find_progress
37
+ @games = find_games
38
+
39
+ return true
40
+ end
41
+
42
+
43
+ private
44
+
45
+ # POST to retrieve the JSON data about games that have been played
46
+ def retrieve_game_data
47
+ if token = find_request_verification_token
48
+ url = XboxLive.options[:url_prefix] + '/en-US/Activity/Summary?' +
49
+ Mechanize::Util.build_query_string(compareTo: @gamertag)
50
+ page = XboxLive::Scraper::post_page(url, '__RequestVerificationToken' => token)
51
+ end
52
+ JSON.parse(page.body)['Data']
53
+ end
54
+
55
+ # Find the RequestVerificationToken
56
+ def find_request_verification_token
57
+ token_block = @page.at('input[name=__RequestVerificationToken]')
58
+ token_block ? token_block.get_attribute('value') : nil
59
+ end
60
+
61
+ # Find the gamertag, in case the caps/lowercase are different than
62
+ # what was provided.
63
+ def find_gamertag
64
+ player = @data['Players'].find { |p| p['Gamertag'].casecmp(@gamertag) == 0 }
65
+ player ? player['Gamertag'] : nil
66
+ end
67
+
68
+ # Find and return the player's large gamertile url from the Games data
69
+ def find_gamertile_large
70
+ player = @data['Players'].find { |p| p['Gamertag'] == @gamertag }
71
+ player ? player['Gamerpic'] : nil
72
+ end
73
+
74
+ # Find and return the player's gamerscore from the Games page
75
+ def find_gamerscore
76
+ player = @data['Players'].find { |p| p['Gamertag'] == @gamertag }
77
+ player ? player['Gamerscore'] : nil
78
+ end
79
+
80
+ # Find and return the player's game progress statistic from the Games page
81
+ def find_progress
82
+ player = @data['Players'].find { |p| p['Gamertag'] == @gamertag }
83
+ player ? player['PercentComplete'] : nil
84
+ end
85
+
86
+ # Find and return an array of hashes containing information about each
87
+ # game the player has played.
88
+ def find_games
89
+ games = @data['Games'].collect do |game|
90
+ gi = GameInfo.new(gamertag, game['Id'])
91
+ gi.name = game['Name']
92
+ gi.tile = game['BoxArt']
93
+ gi.total_points = game['PossibleScore']
94
+ gi.total_achievements = game['PossibleAchievements']
95
+ gi.unlocked_points = game['Progress'][@gamertag]['Score']
96
+ gi.unlocked_achievements = game['Progress'][@gamertag]['Achievements']
97
+ time_field = game['Progress'][@gamertag]['LastPlayed'].match(/Date\((\d+)/)
98
+ gi.last_played = Time.at(time_field[1].to_i / 1000) if time_field
99
+ gi
100
+ end
101
+ return games
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,91 @@
1
+ module XboxLive
2
+
3
+ # Each ProfilePage tracks and makes available the data contained in an Xbox
4
+ # Live profile web page. This can be used to determine general information
5
+ # about a payer, such as their total score, avatar picture, or bio.
6
+ #
7
+ # Example: http://live.xbox.com/en-US/Profile?Gamertag=someone
8
+ class ProfilePage
9
+
10
+ attr_accessor :gamertag, :page, :url, :updated_at, :gamerscore, :motto,
11
+ :avatar, :gamertile_small, :nickname, :bio, :presence
12
+
13
+
14
+ # Create a new ProfilePage for the provided gamertag. Retrieve the
15
+ # html profile page from the Xbox Live web site for analysis.
16
+ def initialize(gamertag)
17
+ @gamertag = gamertag
18
+ refresh
19
+ end
20
+
21
+
22
+ # Force a reload of the ProfilePage data from the Xbox Live web site.
23
+ #
24
+ # TODO: Parse the Location: and reputation fields as well.
25
+ def refresh
26
+ url = XboxLive.options[:url_prefix] + '/en-US/Profile?' +
27
+ Mechanize::Util.build_query_string(gamertag: @gamertag)
28
+ @page = XboxLive::Scraper::get_page url
29
+ return false if @page.nil?
30
+
31
+ @url = url
32
+ @updated_at = Time.now
33
+ @gamerscore = find_gamerscore
34
+ @motto = find_motto
35
+ @avatar = find_avatar
36
+ @nickname = find_nickname
37
+ @bio = find_bio
38
+ @presence = find_presence
39
+ @gamertile_small = find_gamertile_small
40
+
41
+ return true
42
+ end
43
+
44
+ private
45
+
46
+ # Find and return the player's gamerscore from the ProfilePage
47
+ def find_gamerscore
48
+ score_block = @page.at('div.gamerscore')
49
+ score_block ? score_block.inner_html.to_i : nil
50
+ end
51
+
52
+ # Find and return the player's motto from the ProfilePage
53
+ def find_motto
54
+ motto_block = @page.at('div.motto')
55
+ # TODO: Need to strip out the empty bubble-arrow div
56
+ motto_block ? motto_block.inner_html.strip : nil
57
+ end
58
+
59
+ # Find and return the player's avatar url from the ProfilePage
60
+ def find_avatar
61
+ # FIXME: Not currently working. Javascript?
62
+ avatar_block = @page.at('img.bodyshot')
63
+ avatar_block ? avatar_block.get_attribute('src') : nil
64
+ end
65
+
66
+ # Find and return the player's small gamertile url from the ProfilePage
67
+ def find_gamertile_small
68
+ tile_block = @page.at('img.gamerpic')
69
+ tile_block ? tile_block.get_attribute('src') : nil
70
+ end
71
+
72
+ # Find and return the player's nickname from the ProfilePage
73
+ def find_nickname
74
+ nickname_block = @page.at('div.name div.value')
75
+ nickname_block ? nickname_block.inner_html.strip : nil
76
+ end
77
+
78
+ # Find and return the player's bio from the ProfilePage
79
+ def find_bio
80
+ bio_block = @page.at('div.bio div.value')
81
+ bio_block ? bio_block.inner_html.strip : nil
82
+ end
83
+
84
+ # Find and return the player's most recent presence info from the ProfilePage
85
+ def find_presence
86
+ presence_block = @page.at('div.presence')
87
+ presence_block ? presence_block.inner_html.strip : nil
88
+ end
89
+ end
90
+
91
+ end
@@ -0,0 +1,153 @@
1
+ module XboxLive
2
+
3
+ # Scraper is a collection of methods to log into the Xbox Live web site
4
+ # and retrieve web pages.
5
+ #
6
+ # The only public function is XboxLive::Scraper.get_page(url)
7
+ module Scraper
8
+
9
+ # Since loading pages from the Xbox Live web site is expensive
10
+ # (slow), pages should be cached for a short amount of time in case
11
+ # they are re-requested again.
12
+ @cache = Hash.new
13
+
14
+ # Load a page from Xbox Live and return a Mechanize/Nokogiri page
15
+ # TODO: cache pages for some time to prevent duplicative HTTP activity
16
+ def self.get_page(url)
17
+ log "Loading page #{url}."
18
+
19
+ # Check to see if there is a recent version of the page in cache
20
+ if @cache[url]
21
+ log " Found page in cache."
22
+ return @cache[url][:page] if Time.now - @cache[url][:updated_at] < XboxLive.options[:refresh_age]
23
+ log " but the cached page is stale."
24
+ end
25
+
26
+ # Load the specified page via Mechanize
27
+ log " Getting page from Xbox Live."
28
+ page = safe_get(url)
29
+
30
+ # Most pages require authentication. If the Mechanize agent has
31
+ # not logged in yet, or if the session has expired, it will be
32
+ # redirected to the Xbox Live login page.
33
+ if login_page?(page)
34
+ # Log the agent in via the returned login page.
35
+ log " Page load failed - not signed in."
36
+ page = login(page)
37
+
38
+ # The login SHOULD have returned the original page requested,
39
+ # but the URL will be the POST URL, so there is no way to be
40
+ # certain. Therefore, it is safest to just load the page again
41
+ # now that the Mechanize agent has logged in.
42
+ log " Retrying page #{url}"
43
+ page = safe_get(url)
44
+ end
45
+
46
+ if page.nil? or page.title.match /Error/
47
+ log " ERROR: failed to load page. Trying again."
48
+ page = safe_get(url)
49
+ if page.nil? or page.title.match /Error/
50
+ log " ERROR: failed on second try. Aborting."
51
+ return nil
52
+ else
53
+ log " SUCCESS: page loaded on retry."
54
+ end
55
+ end
56
+
57
+ if page.uri.to_s != url
58
+ log " ERROR: loaded page URL does not match expected URL. Loaded: #{page.uri.to_s}"
59
+ return nil
60
+ end
61
+
62
+ log " Loaded page '#{page.title.strip}'. Storing in cache."
63
+ @cache[url] = { page: page, updated_at: Time.now }
64
+ page
65
+ end
66
+
67
+ # POST a page to Xbox Live and return the result.
68
+ def self.post_page(url, params)
69
+ log "POSTing page #{url} with params #{params}."
70
+ page = agent.post(url, params)
71
+ page
72
+ end
73
+
74
+
75
+ # private
76
+
77
+ # Get a page, but catch any errors so processing can continue
78
+ def self.safe_get(page)
79
+ begin
80
+ return agent.get(page)
81
+ # rescue Errno::ETIMEDOUT, Timeout::Error, Mechanize::ResponseCodeError
82
+ rescue
83
+ return nil
84
+ end
85
+ end
86
+
87
+ # Log in to Xbox Live using the supplied login page.
88
+ def self.login(page)
89
+ return nil if !login_page?(page)
90
+
91
+ # Find the URL where the login form should be POSTed to.
92
+ url = page.body.match(/srf_uPost='([^']+)/)[1]
93
+ if url.empty?
94
+ log " ERROR: Trying to log in but 'Sign In' page doesn't contain needed info."
95
+ return nil
96
+ end
97
+
98
+ # PPFT appears to be some kind of session identifier which is
99
+ # required for the login process.
100
+ ppft_html = page.body.match(/srf_sFT='([^']+)/)[1]
101
+ ppft = ppft_html.match(/value="([^"]+)/)[1]
102
+
103
+ # The rest of the parameters are either user-provided (i.e.
104
+ # username and password) or are constants.
105
+ params = {
106
+ 'login' => XboxLive.options[:username],
107
+ 'passwd' => XboxLive.options[:password],
108
+ 'type' => '11',
109
+ 'LoginOptions' => '3',
110
+ 'NewUser' => '1',
111
+ 'PPSX' => 'Passpor',
112
+ 'PPFT' => ppft,
113
+ 'idshbo' => '1'
114
+ }
115
+
116
+ # POST the login form and hope for the best.
117
+ log " Submitting login form via POST"
118
+ page = agent.post(url, params)
119
+
120
+ # The login will fail and return a page saying that Javascript must be
121
+ # enabled. However, there is a hidden form in the page that can be
122
+ # submitted to enable non-javascript support.
123
+ form = page.form('fmHF')
124
+ if form.nil?
125
+ log " ERROR: The non-JS login page doesn't contain form fmHF."
126
+ return nil
127
+ end
128
+
129
+ # Submitting the form on the Javascript error page completes the
130
+ # login process, and SHOULD return the originally requested page.
131
+ log " Submitting final non-JS login form"
132
+ agent.submit(form)
133
+ end
134
+
135
+ # Check to see if the provided page the Xbox Live login page.
136
+ def self.login_page?(page)
137
+ page and page.title == "Welcome to Windows Live"
138
+ end
139
+
140
+ # Create and memoize the Mechanize agent
141
+ def self.agent
142
+ log " Initializing mechanize agent @ #{Time.now.to_s}" if !defined? @@agent
143
+ @@agent ||= Mechanize.new { |a| a.user_agent_alias = 'Mac Safari' }
144
+ end
145
+
146
+ # Write out a log entry
147
+ def self.log(message)
148
+ puts message if XboxLive.options[:debug]
149
+ end
150
+
151
+ end
152
+
153
+ end
@@ -0,0 +1,3 @@
1
+ module XboxLive
2
+ VERSION = "0.3.3"
3
+ end
data/lib/xbox_live.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'mechanize'
2
+ require 'json'
3
+ require 'xbox_live/version'
4
+ require 'xbox_live/scraper'
5
+ require 'xbox_live/game_info'
6
+ require 'xbox_live/achievement_info'
7
+ require 'xbox_live/profile_page'
8
+ require 'xbox_live/games_page'
9
+ require 'xbox_live/achievements_page'
10
+
11
+ module XboxLive
12
+
13
+ # Provides configurability.
14
+ def self.options
15
+ @options ||= {
16
+ :username => nil,
17
+ :password => nil,
18
+ :refresh_age => 600, # data will be re-fetched if older than X seconds
19
+ :url_prefix => 'http://live.xbox.com'
20
+ }
21
+ end
22
+
23
+ XboxLive.options[:username] = 'xboxlive@mfischer.com'
24
+ XboxLive.options[:password] = 's9dALtmG'
25
+ XboxLive.options[:debug] = true
26
+
27
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe XboxLive::Scraper do
4
+
5
+ describe "#get_page" do
6
+
7
+ context "with a public (non-authenticated) page" do
8
+ before { @page = XboxLive::Scraper.get_page('http://live.xbox.com/en-US/MyXbox/Profile?gamertag=major%20nelson') }
9
+
10
+ it 'should return a Mechanize::Page instance' do
11
+ @page.class.should == Mechanize::Page
12
+ end
13
+
14
+ it 'should return the page with the expected title' do
15
+ @page.title.strip.should == 'Major Nelson - Xbox.com'
16
+ end
17
+
18
+ end
19
+
20
+ context "with a private (authenticated) page" do
21
+ before { @page = XboxLive::Scraper.get_page('http://live.xbox.com/en-US/MyXbox/Profile?gamertag=major%20nelson') }
22
+
23
+ it 'should return the page with the expected title' do
24
+ @page.title.strip.should == 'Major Nelson - Xbox.com'
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,2 @@
1
+ require 'rspec'
2
+ require 'xbox_live'
data/xbox_live.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "xbox_live/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "xbox_live"
7
+ s.version = XboxLive::VERSION
8
+ s.authors = ["Mike Fischer"]
9
+ s.email = ["mikefischer99@gmail.com"]
10
+ s.homepage = "https://github.com/greendog99/xbox_live"
11
+ s.summary = %q{Xbox Live data retrieval}
12
+ s.description = %q{Log into Xbox Live and retrieve information about a player}
13
+ s.platform = Gem::Platform::RUBY
14
+ s.rubyforge_project = "xbox_live"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency "mechanize", "~> 1.0"
22
+ s.add_runtime_dependency "json"
23
+ s.add_development_dependency "rspec", "~> 2.6"
24
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xbox_live
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mike Fischer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-13 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mechanize
16
+ requirement: &70358515052260 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70358515052260
25
+ - !ruby/object:Gem::Dependency
26
+ name: json
27
+ requirement: &70358515051320 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70358515051320
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70358515050680 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '2.6'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70358515050680
47
+ description: Log into Xbox Live and retrieve information about a player
48
+ email:
49
+ - mikefischer99@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - Gemfile
56
+ - README.md
57
+ - Rakefile
58
+ - example-usage.rb
59
+ - lib/xbox_live.rb
60
+ - lib/xbox_live/achievement_info.rb
61
+ - lib/xbox_live/achievements_page.rb
62
+ - lib/xbox_live/game_info.rb
63
+ - lib/xbox_live/games_page.rb
64
+ - lib/xbox_live/profile_page.rb
65
+ - lib/xbox_live/scraper.rb
66
+ - lib/xbox_live/version.rb
67
+ - spec/scraper_spec.rb
68
+ - spec/spec_helper.rb
69
+ - xbox_live.gemspec
70
+ homepage: https://github.com/greendog99/xbox_live
71
+ licenses: []
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project: xbox_live
90
+ rubygems_version: 1.8.10
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: Xbox Live data retrieval
94
+ test_files: []