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 # w 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| #NameThomas 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='
Black Lukas Zach (lukaszach) 30 kyu (+11%)-30 kyu (0%) Prisoners: 18
Time remaining: 6 days and 1 hour
White Thomas Preymesser (thopre) 30 kyu (0%)-29 kyu (-11%) Prisoners: 2
Time remaining: 9 days and 6 hours
Rules: Komi: 6.5,   Handicap: 0,   Rated game: Yes
Time limit: Japanese byoyomi: 15 days + 1 day per move and 3 extra periods
' 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