#!/usr/bin/perl -w use strict; $|++; use HTML::TableExtract; use Getopt::Long; use Time::Local; ############################################################################### # Generates a list of Xbox 360 achievements sorted by time achieved. # # # # v1.0: 2007-07-16, morbus@disobey.com, email me if you use/modify. # ############################################################################### # This script requires you to download all the relevant data from xbox.com # # yourself - I currently use OS X's Automator.app to do this. The relevant # # URLs are those that include "ViewAchievementDetails" in the path and # # compares your gamerscore with another ("compareTo" in the URL too). # # # # perl x360a.pl x360a_data/* > x360a_morbus_iff_else.html # ############################################################################### # changes (2007-06-01, version 1.0): # # - initial public release. # ############################################################################### use POSIX qw(strftime); use Net::SMTP_auth; use HTML::Entities; use LWP::Simple; my $data; while (<>) { $data .= $_; } # suck the achievement data. my %te_config = (keep_html => 1, strip_html_on_match => 0); # we use classes to get at the table we want. my $te = HTML::TableExtract->new( attribs => { class => 'XbcProfileTable XbcAchievementsDetailsTable' }, %te_config); $te->parse($data); # all games played by downloaded gamertags. my @achievements; # master data lookup. my $processed; # prevents duplicates. # start the loop to collect everything. foreach my $ts ($te->table_states) { my @gtcol; # maps column to gamer tag. my $game; # name of the game being searched. foreach my $r ($ts->rows) { # header row; grab gamertags and game. if (@$r[0] && @$r[0] =~ /XbcProfileTitle/) { @$r[0] =~ /(.*) <\/span>/; $game = $1; @$r[1] =~ /GamerTag=.*">(.*)<\/a><\/h3>/; $gtcol[1] = $1; @$r[2] =~ /GamerTag=.*">(.*)<\/a><\/h3>/; $gtcol[2] = $1; } # achievement row; look for success. if (@$r[0] && @$r[0] =~ /XbcAchievementsTitle/) { @$r[0] =~ /

(.*)<\/strong><\/p>/; my $a_title = $1; @$r[0] =~ /<\/p><\/div>

(.*)<\/p><\/div>/; my $a_description = $1; # unexciting, no? # look for per-player achievements. for (my $col = 1; $col <= 2; $col++) { if (@$r[$col] =~ /xbcDisplayDate/) { @$r[$col] =~ /<\/div>/; my $a_tile = $1; @$r[$col] =~ /<\/div>

(\d+) {$gtcol[$col]}->{$game}) { next; } my $time = timegm(0, $5, $4, $2, $1, $3); # store in epoch UTC. push (@achievements, { description => HTML::Entities::decode($a_description), game => HTML::Entities::decode($game), gamertag => $gtcol[$col], points => $a_points, tile_url => $a_tile, tile_file => $a_tile =~ /http:\/\/tiles.xbox.com\/tiles\/..\/..\/(.*)/, title => HTML::Entities::decode($a_title), time => $time, time_f => strftime "%a %b %e %H:%M:%S %Y", gmtime($time), }); } } } } # record games already processed. $processed->{$gtcol[1]}->{$game}++; $processed->{$gtcol[2]}->{$game}++; } # sort our achievements by date. @achievements = sort { $b->{'time'} <=> $a->{'time'} } @achievements; print < Xbox 360 Game Achievements

Xbox 360 Game Achievements

The below contains a listing of all Xbox 360 achievements attained by gamertag Morbus Iff Else. It was created by a Perl script from Morbus Iff which scans downloaded achievement lists from Xbox.com (how you actually download them is up to you). Currently, the Xbox Community Developer Program is not accepting new tools, nor does it provide this type of data at the API level (or so I'm told).

EVIL_HEREDOC_HEADER_OF_ORMS_BY_GORE foreach my $achievement (@achievements) { if ($achievement->{'gamertag'} ne 'Morbus Iff Else') { next; } unless (-e "x360a_tiles/$achievement->{tile_file}") { # store the tiles locally so we don't leech of xbox.com. getstore($achievement->{'tile_url'}, "x360a_tiles/$achievement->{tile_file}"); } print ""; print ""; print ""; print ""; print "\n"; } print "
GameTilePointsAchievementDate
$achievement->{game}{tile_file}\" />$achievement->{points}$achievement->{title}
$achievement->{description}
". strftime("%Y-%m-%d %H:%M:%S", gmtime($achievement->{'time'})) ."
";