require 'rubygems'
require 'mechanize'
require 'gorank'
require 'hpricot'
#require 'pp'
class Dgs
# text if not logged in
LOGGED_IN="Sorry, you have to be logged in to do that"
# your turn message
YOUR_TURN="Your turn to move in the following games"
# DGS Status page
DGS_STATUS_PAGE = 'http://www.dragongoserver.net/status.php/'
# DGS Index page
DGS_INDEX_PAGE = 'http://www.dragongoserver.net/index.php'
# DGS Waiting room page
DGS_WAITING_ROOM_PAGE = 'http://www.dragongoserver.net/waiting_room.php'
# User agent
USER_AGENT_ALIAS = 'Mac Safari' # should work with every browser type
# if we are doing too many requests at DGS the account (YOUR ACCOUNT)
# will be temporarily blocked (for about 1 day)
# wait n seconds before each request
SAVE_WAIT = 15
attr_reader :username
def initialize(username=nil,password=nil)
@username = username
@password = password
if @username == nil or @password == nil
@username = ENV['DGS_USERNAME']
@password = ENV['DGS_PASSWORD']
if @username == nil or @password == nil
raise(RuntimeError, "username and/or password not set")
end
end
@userinfo = Hash.new
end
# Array of waiting games
def waiting_games
save_wait
games = []
@home = DGS_STATUS_PAGE
agent = WWW::Mechanize.new
agent.user_agent_alias = USER_AGENT_ALIAS
page = agent.get(@home)
if page.body.include?(LOGGED_IN)
# dann erst zum Einloggen gehen
page = login(agent)
end
# muss kommen, sonst sind wir noch nicht auf der richtigen Seite
if !page.body.include?(YOUR_TURN)
raise "PageError: #{DGS_STATUS_PAGE} not found"
end
game_id=0
user_id=0
page.body.each_line {|line|
if line =~ /gid=([0-9]+)"/
game_id = $1.to_i
# ??? games << {:game => game_id, :user => userid}
# games << $1.to_i
games << game_id
end
if line =~ /uid=([0-9]+)"/ and game_id > 0
user_id = $1.to_i
end
}
# aus Bequemlichkeitsgruenden (gid= kommt mehrfach vor): uniq
games.uniq
end
# Array of your running games
# http://www.dragongoserver.net/show_games.php?uid=10737
def running_games
save_wait
games = []
#@home = 'http://www.dragongoserver.net/show_games.php?uid=10737' #TODO:
@home = DGS_STATUS_PAGE
agent = WWW::Mechanize.new
agent.user_agent_alias = USER_AGENT_ALIAS
page = agent.get(@home)
if page.body.include?(LOGGED_IN)
page = login(agent)
end
if !page.body.include?(YOUR_TURN)
raise "PageError: #{DGS_STATUS_PAGE} not found"
end
# page = agent.click page.links.text('Show running games')
page = agent.click page.link_with(:text => 'Show running games')
# *_with(:text => "Show running games")
page.body.each_line {|line|
if line =~ /gid=([0-9]+)"/
games << $1.to_i
end
}
# BEGIN naechste Seite(n)
#p page.links
# page = agent.click page.link_with(:text => '=>')
while true
begin
page = agent.click page.link_with(:text => '=>')
rescue
break # keine weitere Seite vorhanden
end
page.body.each {|line|
if line =~ /gid=([0-9]+)"/
games << $1.to_i
end
}
end
# END naechste Seite(n)
# aus Bequemlichkeitsgruenden (gid= kommt mehrfach vor): uniq
games.uniq
end
# Array of your finished games
# http://www.dragongoserver.net/show_games.php?uid=10737
def finished_games
save_wait
games = []
#@home = 'http://www.dragongoserver.net/show_games.php?uid=10737' #TODO:
@home = DGS_STATUS_PAGE
agent = WWW::Mechanize.new
agent.user_agent_alias = USER_AGENT_ALIAS
page = agent.get(@home)
if page.body.include?(LOGGED_IN)
page = login(agent)
end
#if !page.body.include?(YOUR_TURN)
# raise "PageError: #{DGS_STATUS_PAGE} not found"
#end
# page = agent.click page.links.text('Show finished games')
page = agent.click page.link_with(:text => 'Show finished games')
page.body.each_line {|line|
if line =~ /gid=([0-9]+)"/
games << {:id => $1.to_i, :finished_at => DateTime.now}
end
}
page_no = 1
# p page.links.find { |l| l.title =~ /next page/ }
#p page.links
# naechste Seite
# while page.link_with(:text => '+')
while page.link_with(:title => 'next page [&>]')
page_no += 1
puts "at page_no = #{page_no}"
# page = agent.click page.link_with(:text => '+')
page = agent.click page.link_with(:title => 'next page [&>]')
# nochmal alle Spiele auf Folgeseite durchgehen
page.body.each {|line|
if line =~ /gid=([0-9]+)"/
games << {:id => $1.to_i, :finished_at => DateTime.now}
end
}
end
# aus Bequemlichkeitsgruenden (gid= kommt mehrfach vor): uniq
games.uniq
end
# same as finished_games but only the ids of the games
def finished_games_ids
result = []
finished_games.each { |e|
result << e[:id]
}
result
end
# http://www.dragongoserver.net/show_games.php?uid=31098&finished=1
# the first page of finished games for this user
def finished_games_for_user(user_id)
save_wait
games = []
@home = "http://www.dragongoserver.net/show_games.php?uid=#{user_id}&finished=1" #TODO:
#p @home
#@home = DGS_STATUS_PAGE
agent = WWW::Mechanize.new
agent.user_agent_alias = USER_AGENT_ALIAS
page = agent.get(@home)
if page.body.include?(LOGGED_IN)
page = login(agent)
page = agent.click page.link_with(:text => 'Users')
if !page.body.include?("Active users")
raise "Active users not diplaying"
end
form = page.forms.first
form.sf1 = user_id.to_s
form.checkbox_with(:name => "active").uncheck # auch inaktive User beruecksichtigen
page = agent.submit(form)
# page = agent.click page.links.text("#{user_id}")
page = agent.click page.link_with(:text => "#{user_id}")
# page = agent.click page.links.text("Show finished games")
# page = agent.click page.link_with(:text => "Show finished games")
page = agent.click page.link_with(:text => "Finished games")
end
if !page.body.include?("Finished games for")
#p page.body
raise "Finished games for not on page"
end
#page = agent.click page.links.text('Show finished games')
one_game = {}
page.body.each_line {|line|
# p line
#p one_game
if line =~ /gid=([0-9]+)"/
one_game[:id] = $1.to_i
end
#
 |
if line =~ /[wb].gif/ and
one_game[:id]
#p $1
color = line.split('.gif')[0][-1,1]
#p line.split('.gif')[0] #[-1,1]
#p color
if color == 'w'
one_game[:player_color] = :white
else
one_game[:player_color] = :black
end
end
# W+Time
if line =~ /[WB]\+/ and
one_game[:id]
color,reason = line.split('+')
if color[-1,1] == 'W'
one_game[:winner] = :white
else
one_game[:winner] = :black
end
one_game[:reason] = reason[0,reason.index('<')]
end
#2008-04-19 10:29 |
if line =~ /(\d+)-(\d+)-(\d+)/ and
one_game[:id]
d = Date.new($1.to_i,$2.to_i,$3.to_i)
one_game[:finished_at] = d
games << one_game
one_game = {}
end
}
# aus Bequemlichkeitsgruenden (gid= kommt mehrfach vor): uniq
#p games
games # .uniq
end
# your rank as a GoRank object
def get_rank
save_wait
@home = DGS_STATUS_PAGE
agent = WWW::Mechanize.new
agent.user_agent_alias = USER_AGENT_ALIAS
page = agent.get(@home)
if page.body.include?(LOGGED_IN)
page = login(agent)
end
if !page.body.include?(YOUR_TURN)
raise "PageError: #{DGS_STATUS_PAGE} not found"
end
a = show_regexp(page.body, /(\d+) (kyu|dan)/)
num = a[0].to_i
what = a[1].to_sym
myRank = GoRank.new num, what
myRank
end
# rank is an alias to get_rank
alias :rank :get_rank
# your id at DGS
def userid
save_wait
@home = DGS_STATUS_PAGE
agent = WWW::Mechanize.new
agent.user_agent_alias = USER_AGENT_ALIAS
page = agent.get(@home)
if page.body.include?(LOGGED_IN)
page = login(agent)
end
if !page.body.include?(YOUR_TURN)
raise "PageError: #{DGS_STATUS_PAGE} not found"
end
# Link 'http://www.dragongoserver.net/ratinggraph.php?uid=10737'
# enthaelt die Userid
#p page.links
page.links.each { |link|
if link.href =~ /ratinggraph/
a = show_regexp(link.href, /^ratinggraph.php\?uid=(\d+)$/)
@userid = a[0].to_i
break
end
}
@userid
end
# informations about a user at DGS
# returns a hash with attributes
def userinfo(user_id = nil)
save_wait
## http://www.dragongoserver.net/userinfo.php?uid=10737
agent = WWW::Mechanize.new
agent.user_agent_alias = USER_AGENT_ALIAS
user_id = 10737 unless user_id
page = agent.get("http://www.dragongoserver.net/userinfo.php?uid=#{user_id}")
if page.body.include?(LOGGED_IN)
page = login(agent)
page = agent.get("http://www.dragongoserver.net/userinfo.php?uid=#{user_id}")
end
if page.body.include?("Sorry, I couldn't find this user.")
raise 'no user with this id'
end
@userinfo[:city] = nil
@userinfo[:country] = nil
result = Hash.new
page.body.each_line {|line|
#Name | Thomas Preymesser |
if line =~ /td class="Rubric"/
#p line
a = show_regexp(line,
/td class="Rubric">(.*)<\/td>(.*)<\/td>/)
# /td class="Rubric">(.+)<\/td> | .+<\/td>"/)
#p a
if a[0]=="Name"
result[:name] = a[1]
elsif a[0]=="Userid"
result[:userid] = a[1]
elsif a[0]=="Country"
b = show_regexp(a[1], /alt="(.*)" /)
result[:country] = b[0]
elsif a[0]=="City"
result[:city] = a[1]
elsif a[0]=="Rating"
#
if a[1] =~ /(\d+) (kyu|dan)/
b = show_regexp(a[1], /(\d+) (kyu|dan)/)
num = b[0].to_i
what = b[1].to_sym
begin
result[:rating] = GoRank.new num, what
rescue
raise "illegal rank: #{a[1]}\n#{num}/#{what}"
end
else
result[:rating] = nil
end
##
#result[:rating] = a[1]
elsif a[0]=="Last access"
result[:lastaccess] = DateTime.parse(a[1].gsub(/ /,' '))
elsif a[0]=="Last move"
begin
result[:lastmove] = DateTime.parse(a[1].gsub(/ /,' '))
rescue
puts "invalid " + a[1].to_s
end
end
end
}
# @userinfo[:name]='Hugo Boss'
return result
end
#http://www.dragongoserver.net/game.php?gid=395863
def gameinfo(game_id)
demo='
'
save_wait
agent = WWW::Mechanize.new
agent.user_agent_alias = USER_AGENT_ALIAS
p = "http://www.dragongoserver.net/game.php?gid=#{game_id}"
page = agent.get(p)
if page.body.include?(LOGGED_IN)
page = login(agent)
page = agent.get(p)
end
#TODO:
if page.body.include?("Sorry, I can't find that game")
raise 'no game with this id'
end
result = Hash.new
result[:white] = {}
result[:black] = {}
doc = page
#elements = doc.search("//table[@class='GameInfos']").search('tr[@id='BlackInfo')
elements = doc.search("//table[@class='GameInfos']")
blackinfo = (elements/"tr[@id='blackInfo']")
whiteinfo = (elements/"tr[@id='whiteInfo']")
whiteinfo_name = (whiteinfo/"td[@class='Name']/a").inner_text #2008-12-28 inner_html
blackinfo_name = (blackinfo/"td[@class='Name']/a").inner_text #2008-12-28 inner_html
result[:black][:name] = blackinfo_name
result[:white][:name] = whiteinfo_name
result
end
# all games of the own user
# finished games + running games
# TODO: should return an array of game instances
def games
[4,5,6]
end
# Create one or more games in the waiting room
# Default values are taken from the file
# ~/.dgs_default_add_game.yml if it exists
# (if not the DGS form is just submitted)
def add_game
dgs_default_add_game = File.join(ENV['HOME'],".dgs_default_add_game.yml")
save_wait
my_rank = get_rank
my_rank_org = my_rank.dup
@waiting_room = DGS_WAITING_ROOM_PAGE
agent = WWW::Mechanize.new
agent.user_agent_alias = USER_AGENT_ALIAS
default_default_comment = 'added by dragongoserver ruby gem'
#--
# default = {
# :number_of_games => 3,
# :size => 19,
# :main_time => [15, :days], # or: :main_time => [15, :days]
# # or: :main_time => [24, :hours]
# # or: :main_time => [6, :months]
# :japanese_byoyomi => [1, :hours, 24, :extra_periods],
# # :canadian_byoyomi => false
# # :fischer_time => false
#
# :rated_game => true,
# :clock_runs_on_weekend => false,
# :require_rated_opponent => true,
# :relative_range => 9,
# :comment => default_default_comment,
# }
# open(File.join(ENV['HOME'],".dgs_default_add_game.yml"),"w") { |f|
# YAML.dump(default,f)
# }
begin
default = open(File.join(ENV['HOME'],".dgs_default_add_game.yml")) { |f|
YAML.load(f)
}
rescue Errno::ENOENT
# Datei nicht vorhanden.
# Auch nicht schlimm, dann nehmen wir die Default-Werte von DGS
end
#--
page = agent.get(@waiting_room)
if page.body.include?(LOGGED_IN)
# dann erst zum Einloggen gehen
page = login(agent)
page = agent.get(DGS_WAITING_ROOM_PAGE)
end
form = page.form("addgame")
if default
# wenn default Konfiguration nicht vorhanden,
# dann Formular in DGS einfach so lassen und bestätigen
# => 1 Spiel, 3 Monate, ...
if default[:number_of_games]
form.fields.find {|f| f.name == 'nrGames'}.value = default[:number_of_games]
end
if default[:size]
form.fields.find {|f| f.name == 'size'}.value = default[:size]
end
if default[:main_time]
form.fields.find {|f| f.name == 'timevalue'}.value = default[:main_time][0]
form.fields.find {|f| f.name == 'timeunit'}.value = default[:main_time][1].to_s
end
if default[:japanese_byoyomi]
# form.radiobuttons_with(:name => 'box')[1].check
form.radiobuttons_with(:name => 'byoyomitype')[0].check #e = 'JAP'
form.fields.find {|f| f.name == 'byotimevalue_jap'}.value =
default[:japanese_byoyomi][0]
form.fields.find {|f| f.name == 'timeunit_jap'}.value =
default[:japanese_byoyomi][1].to_s
form.fields.find {|f| f.name == 'byoperiods_jap'}.value =
default[:japanese_byoyomi][2]
# :japanese_byoyomi => [1, :hours, 24, :extra_periods],
end
if default[:comment]
form.fields.find {|f| f.name == 'comment'}.value = default[:comment]
end
if default[:require_rated_opponent]
form.checkbox_with(:name => 'must_be_rated').check
else
form.checkbox_with(:name => 'must_be_rated').uncheck
end
if default[:clock_runs_on_weekend]
form.checkbox_with(:name => 'weekendclock').check
else
form.checkbox_with(:name => 'weekendclock').uncheck
end
if default[:rated_game]
form.checkbox_with(:name => 'rated').check
else
form.checkbox_with(:name => 'rated').uncheck
end
if default[:relative_range]
r = default[:relative_range]
begin
rating1 = my_rank - r
rescue IndexError
rating1 = GoRank.new 30, :kyu
end
my_rank = my_rank_org
begin
rating2 = my_rank + r
rescue IndexError
rating2 = GoRank.new 6, :dan # go-rank max 6 dan, dgs max 9 dan TODO:
end
form.fields.find {|f| f.name == 'rating1'}.value = rating1.to_s
form.fields.find {|f| f.name == 'rating2'}.value = rating2.to_s
end
end # if default
unless default
form.fields.find {|f| f.name == 'comment'}.value = default_default_comment
end
page = agent.submit(form, form.buttons.first)
# puts "neue Einladung erstellt" if page.body.include? 'Game added!'
page.body.include? 'Game added!'
end
private
def show_regexp(a, re)
if a =~ re
return ["#$1", "#$2"]
else
"no match"
end
end
def login(agent)
@home = DGS_INDEX_PAGE
page = agent.get(@home)
#form = page.forms.with.name("loginform").first
form = page.form("loginform")
form.fields.find {|f| f.name == 'userid'}.value = @username
form.fields.find {|f| f.name == 'passwd'}.value = @password
page = agent.submit(form, form.buttons.first)
return page
end
def save_wait
sleep(SAVE_WAIT)
end
end
|