xbox_live 0.3.3

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.
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: []