#!/usr/bin/ruby # # cpsn - Query Friend status on the Playstation Network (tm) # # Author:: James Bowes # Copyright:: Copyright (C) 2009 James Bowes require 'rubygems' require 'mechanize' require 'json' require 'yaml' require 'optparse' require 'logger' require 'set' @login_url = "https://store.playstation.com/external/index.vm?returnURL=https%3a%2f%2fsecureus.playstation.com%2fRegistration%2fPSNL%2fSignInFrame.aspx" $friend_url = "http://profiles.us.playstation.com/playstation/psn/profile/friends" $json_url = "http://profiles.us.playstation.com/playstation/psn/profile/get_gamer_summary_data?id=" class Cpsn attr_accessor :settings, :groups def initialize(options) @log = Logger.new(STDERR) @log.level = Logger::WARN if options[:debug] @log.level = Logger::DEBUG end @settings = load_settings() @groups = load_groups(@settings) get_agent(@settings[:username].value, @settings[:password].value, options[:cookie]) end def load_settings() @log.debug("Loading settings") settings = YAML::parse_file(File.expand_path("~/.cpsn/settings.yml")) return settings end def load_groups(settings) @log.debug("Loading groups") groups = {} if not settings[:groups] return groups end for group in settings[:groups].value name = group.value.keys[0].value vals = group.value[group.value.keys[0]] members = [] mem_str = "" for user in vals.value do members << user.value mem_str += user.value mem_str += " " end @log.debug("Found group #{name} [ #{mem_str}]") groups[name] = members end return groups end def get_cookie(username, password) @log.debug("Signing in for new cookie") page = @agent.get(@login_url) login_form = page.forms.first login_form.loginName = username login_form.password = password page = @agent.submit(login_form) link = page.links.first if link.text == "Sign In" puts "Error logging in. Did you give the right username and password?" exit end page = link.click @agent.cookie_jar.save_as File.expand_path("~/.cpsn/cookies.yml") end def get_agent(username, password, force_cookie) @log.debug("Creating new user agent") @agent = WWW::Mechanize.new @agent.user_agent_alias = 'Mac FireFox' @agent.redirect_ok = true if File.exist? File.expand_path("~/.cpsn/cookies.yml") and not force_cookie @agent.cookie_jar.load File.expand_path("~/.cpsn/cookies.yml") else get_cookie(username, password) end end def get_friends() @log.debug("Getting friends list") page = @agent.get($friend_url) divs = page.search("div.slotcontent") friends = [] for div in divs friend = div.attributes["id"] friends << friend @log.debug("Found friend #{friend}") end return friends end def get_friend_status(friend) @log.debug("Loading friend status for #{friend}") page = @agent.get($json_url + friend) data = JSON.parse(page.body) @log.debug(data) friend = {:name => data["userName"]} if data["onlineStatus"] == nil return nil end if data["onlineStatus"]["extensionStatus"] != nil friend[:status] = 'online' friend[:playing] = data["onlineStatus"]["extensionStatus"]["title"] friend[:game_status] = data["onlineStatus"]["extensionStatus"]["status"] else friend[:status] = 'offline' friend[:playing] = "" friend[:game_status] = "" end return friend end end options = {} optparse = OptionParser.new do |opts| options[:offline] = false opts.on('-o', '--offline', 'Show offline contacts') do options[:offline] = true end options[:debug] = false opts.on('-d', '--debug', 'Show debugging information') do options[:debug] = true end options[:cookie] = false opts.on('-c', '--cookie', 'Force cookie expiration') do options[:cookie] = true end opts.on(nil, '--version', 'Display version information') do gem_dir = File.join(File.dirname(__FILE__), '..') File.open(File.join(gem_dir, 'VERSION')) do |version_file| print version_file.read end exit end opts.on('-h', '--help', 'Show help') do puts opts exit end end optparse.parse! cpsn = Cpsn.new(options) if ARGV.length >= 1 friend_names = Set.new [] args = ARGV[0..-1] for arg in args if cpsn.groups.has_key? arg friend_names.merge(cpsn.groups[arg]) else friend_names.add(arg) end end else begin friend_names = cpsn.get_friends() rescue WWW::Mechanize::ResponseCodeError => response if response.response_code == '403' cpsn.get_cookie(cpsn.settings[:username].value, cpsn.settings[:password].value) retry end end end for friend_name in friend_names begin friend = cpsn.get_friend_status(friend_name) rescue WWW::Mechanize::ResponseCodeError => response if response.response_code == '403' cpsn.get_cookie(cpsn.settings[:username].value, cpsn.settings[:password].value) retry end end if friend if friend[:status] != "offline" or options[:offline] puts friend[:status] + "\t" + friend[:name] + "\t" + friend[:playing] + "\t" + friend[:game_status] end else puts "Error: no access to " + friend_name end end