#! ruby -Ks $KCODE = "sjis" $debug = 0; require 'net/http' require 'cgi' require 'fileutils' require 'strscan' require 'jcode' require 'erb' require 'typekey' #require 'time' class Array def randomize sort_by{ rand(100) } end def randomize! replace randomize end end $server_names = [ 'ninjinix.x0.com', 'ninjinel.sakura.ne.jp', 'ninjinel.sakura.ne.jp', 'ninjinel.sakura.ne.jp', 'ninjinel.x0.com', 'ninjin001.x0.com', 'ninjin001.x0.com', 'ninjin002.x0.com', ] $folder_names = [ 'wolf', 'wolf', 'wolfa', 'wolfb', 'wolfc', 'wolfd', 'wolfe', 'wolff', ] $log_places = [ 'log/old/', 'log/home/', 'log/a/', 'log/b/', 'log/c/', 'log/d/', 'log/e/', 'log/f/', ] $name_list = [ '村長 ヴァルター', '老人 モーリッツ', '神父 ジムゾン', '木こり トーマス', '旅人 ニコラス', 'ならず者 ディーター', '少年 ペーター', '少女 リーザ', '行商人 アルビン', '羊飼い カタリナ', 'パン屋 オットー', '青年 ヨアヒム', '村娘 パメラ', '農夫 ヤコブ', '宿屋の女主人 レジーナ', 'シスター フリーデル', '楽天家 ゲルト', ] $nicknames = { '楽天家 ゲルト' => 'ゲ', '村長 ヴァルター' => 'ヴ', '老人 モーリッツ' => 'モ', '神父 ジムゾン' => 'ジ', '木こり トーマス' => 'ト', '旅人 ニコラス' => 'ニ', 'ならず者 ディーター' => 'デ', '少年 ペーター' => 'ペ', '少女 リーザ' => 'リ', '行商人 アルビン' => 'ア', '羊飼い カタリナ' => 'カ', 'パン屋 オットー' => 'オ', '青年 ヨアヒム' => 'ヨ', '村娘 パメラ' => 'パ', '農夫 ヤコブ' => 'ヤ', '宿屋の女主人 レジーナ' => 'レ', 'シスター フリーデル' => 'フ', } $nicknames2 = { '楽天家 ゲルト' => 'ゲルト', '村長 ヴァルター' => 'ヴァルター', '老人 モーリッツ' => 'モーリッツ', '神父 ジムゾン' => 'ジムゾン', '木こり トーマス' => 'トーマス', '旅人 ニコラス' => 'ニコラス', 'ならず者 ディーター' => 'ディーター', '少年 ペーター' => 'ペーター', '少女 リーザ' => 'リーザ', '行商人 アルビン' => 'アルビン', '羊飼い カタリナ' => 'カタリナ', 'パン屋 オットー' => 'オットー', '青年 ヨアヒム' => 'ヨアヒム', '村娘 パメラ' => 'パメラ', '農夫 ヤコブ' => 'ヤコブ', '宿屋の女主人 レジーナ' => 'レジーナ', 'シスター フリーデル' => 'フリーデル', } $inv_nick2 = $nicknames2.invert $nicknames3 = { '楽天家 ゲルト' => '楽', # '村長 ヴァルター' => '村', '村長 ヴァルター' => '長', # '老人 モーリッツ' => '爺', '老人 モーリッツ' => '老', '神父 ジムゾン' => '神', '木こり トーマス' => '木', # '木こり トーマス' => '樵', '旅人 ニコラス' => '旅', 'ならず者 ディーター' => '者', '少年 ペーター' => '年', '少女 リーザ' => '妙', # '少女 リーザ' => '女', '行商人 アルビン' => '商', '羊飼い カタリナ' => '羊', 'パン屋 オットー' => '屋', '青年 ヨアヒム' => '青', '村娘 パメラ' => '娘', '農夫 ヤコブ' => '農', '宿屋の女主人 レジーナ' => '宿', 'シスター フリーデル' => '修', # 'シスター フリーデル' => '尼', } $nicknames4 = { 'ゲルト' => /.*(?:ゲルト|楽|ゲル)/, 'ヴァルター' => /.*(?:ヴァルター|村|長|バル|ヴァル|ヴィ)/, 'モーリッツ' => /.*(?:モーリッツ|爺|老|翁|モリ|じい|じぃ)/, 'ジムゾン' => /.*(?:ジムゾン|神|ジム|ヅム)/, 'トーマス' => /.*(?:トーマス|木|樵|トマ)/, 'ニコラス' => /.*(?:ニコラス|旅|ニコ)/, 'ディーター' => /.*(?:ディーター|者|ディ)/, 'ペーター' => /.*(?:ペーター|年|ペタ|ベタ|ペータ)/, 'リーザ' => /.*(?:リーザ|妙|女|リー|リザ)/, 'アルビン' => /.*(?:アルビン|商|アル)/, 'カタリナ' => /.*(?:カタリナ|羊|リナ|カタ)/, 'オットー' => /.*(?:オットー|屋|オト)/, 'ヨアヒム' => /.*(?:ヨアヒム|青|ヨア)/, 'パメラ' => /.*(?:パメラ|娘|パメ|バメ)/, 'ヤコブ' => /.*(?:ヤコブ|農|ヤコ)/, 'レジーナ' => /.*(?:レジーナ|宿|レジ|女将)/, 'フリーデル' => /.*(?:フリーデル|修|尼|フリ|シス)/, } $images = { '楽天家 ゲルト' => 'body01.jpg', '村長 ヴァルター' => 'body02.jpg', '老人 モーリッツ' => 'body03.jpg', '神父 ジムゾン' => 'body04.jpg', '木こり トーマス' => 'body05.jpg', '旅人 ニコラス' => 'body06.jpg', 'ならず者 ディーター' => 'body07.jpg', '少年 ペーター' => 'body08.jpg', '少女 リーザ' => 'body09.jpg', '行商人 アルビン' => 'body10.jpg', '羊飼い カタリナ' => 'body11.jpg', 'パン屋 オットー' => 'body12.jpg', '青年 ヨアヒム' => 'body13.jpg', '村娘 パメラ' => 'body14.jpg', '農夫 ヤコブ' => 'body15.jpg', '宿屋の女主人 レジーナ' => 'body16.jpg', 'シスター フリーデル' => 'body17.jpg', } $face_images = { '楽天家 ゲルト' => 'face01.jpg', '村長 ヴァルター' => 'face02.jpg', '老人 モーリッツ' => 'face03.jpg', '神父 ジムゾン' => 'face04.jpg', '木こり トーマス' => 'face05.jpg', '旅人 ニコラス' => 'face06.jpg', 'ならず者 ディーター' => 'face07.jpg', '少年 ペーター' => 'face08.jpg', '少女 リーザ' => 'face09.jpg', '行商人 アルビン' => 'face10.jpg', '羊飼い カタリナ' => 'face11.jpg', 'パン屋 オットー' => 'face12.jpg', '青年 ヨアヒム' => 'face13.jpg', '村娘 パメラ' => 'face14.jpg', '農夫 ヤコブ' => 'face15.jpg', '宿屋の女主人 レジーナ' => 'face16.jpg', 'シスター フリーデル' => 'face17.jpg', } $colors = { '楽天家 ゲルト' => 'gerd', '村長 ヴァルター' => 'walter', '老人 モーリッツ' => 'moritz', '神父 ジムゾン' => 'simson', '木こり トーマス' => 'thomas', '旅人 ニコラス' => 'nicolas', 'ならず者 ディーター' => 'dieter', '少年 ペーター' => 'peter', '少女 リーザ' => 'liesa', '行商人 アルビン' => 'albin', '羊飼い カタリナ' => 'katharina', 'パン屋 オットー' => 'otto', '青年 ヨアヒム' => 'joachim', '村娘 パメラ' => 'pamela', '農夫 ヤコブ' => 'jacob', '宿屋の女主人 レジーナ' => 'regina', 'シスター フリーデル' => 'fridel', } $life_and_death_colors = { "生存"=>"", "死亡"=>"BGCOLOR(#aaaaaa):", } $role_colors = [ { #人間側……青、緑系 '占い師' => 'BGCOLOR(#ccffff):', '霊能者' => 'BGCOLOR(#ccccff):', '狩人' => 'BGCOLOR(#ccffcc):', '村人' => '', '共有者' => 'BGCOLOR(#ffffcc):', #中立……灰系 'ハムスター人間' => 'BGCOLOR(#cccccc):', #狼側……赤系 '狂人' => 'BGCOLOR(#ffccff):', '人狼' => 'BGCOLOR(#ffcccc):', }, { #JBオリジナル(風)仕様 '人狼' => 'BGCOLOR(#ffcccc):', '村人' => '', '占い師' => 'BGCOLOR(#ffffcc):', '霊能者' => 'BGCOLOR(#ccccff):', '狂人' => 'BGCOLOR(#cccccc):', '狩人' => 'BGCOLOR(#ffccaa):', '共有者' => 'BGCOLOR(#ccffcc):', 'ハムスター人間' => 'BGCOLOR(#ffccff):', }, { #まとめサイトテンプレート仕様 '人狼' => 'BGCOLOR(#ff9999):', '村人' => '', '占い師' => 'BGCOLOR(#ccccff):', '霊能者' => 'BGCOLOR(#ccffff):', '狂人' => 'BGCOLOR(#ffcc99):', '狩人' => 'BGCOLOR(#ccffcc):', '共有者' => 'BGCOLOR(#ffffcc):', 'ハムスター人間' => 'BGCOLOR(#ffaaff):', }, ] $new_message = '
new
' $day_delimit = 'd' $role_colors_type = 0 class Jinro def initialize @server_number = 0 @village_number = 0 @char_visible = { '楽天家 ゲルト'=>true, '村長 ヴァルター'=>true, '老人 モーリッツ'=>true, '神父 ジムゾン'=>true, '木こり トーマス'=>true, '旅人 ニコラス'=>true, 'ならず者 ディーター'=>true, '少年 ペーター'=>true, '少女 リーザ'=>true, '行商人 アルビン'=>true, '羊飼い カタリナ'=>true, 'パン屋 オットー'=>true, '青年 ヨアヒム'=>true, '村娘 パメラ'=>true, '農夫 ヤコブ'=>true, '宿屋の女主人 レジーナ'=>true, 'シスター フリーデル'=>true, } @role_visible = {'groan'=>true,'whisper'=>true,'say'=>true,'think'=>true} @impress_visible = {'名言'=>true,'怪しい'=>true,'注意'=>true} @user_id = "" @pass = "" @user_id2 = "" @pass2 = "" @session_id = '' @search_word = "" @search_reg = false @last_modified = "" @exist_days = [] @impresses = {} @proxy_address = "" @proxy_port = 8080 @big_mode = false @simple_mode = false @impress_mode = false @day_number = 0 @login_id = '' end def set_impress_mode(b) @impress_mode = b end def set_big_mode(b) @big_mode = b end def set_simple_mode(b) @simple_mode = b end def set_impress_visible(hash) @impress_visible = hash end def set_char_visible(hash) @char_visible = hash end def set_role_visible(hash) @role_visible = hash end def exist_days return @exist_days.join(' ') end def set_search_word(search_word, search_reg) @search_word = search_word @search_reg = search_reg end def set_user(user_id, pass, user_id2, pass2) # if !(@user_id2 == '' && @pass2 == '' && user_id2 == '' && pass2 == '') && (@user_id2 != user_id2 || @pass2 != pass2) # File::delete(TypeKey::KEY_CACHE_PATH) # end @user_id = user_id @pass = pass @user_id2 = user_id2 @pass2 = pass2 @session_id = get_session_id(@user_id2, @pass2) return @session_id end def set_proxy(proxy_address, proxy_port) @proxy_address = proxy_address @proxy_port = proxy_port end def load_ini() @last_modified = "" @exist_days = [] @impresses = {} @references = {} data = nil if FileTest.exist?("#{saved_folder_name()}/ini") File.open("#{saved_folder_name()}/ini") do |fin| data = Marshal.load(fin) @last_modified = data["last_modified"] || "" @exist_days = data["exist_days"] || [] @impresses = data["impresses"] || {} @references = data["references"] || {} end end @day_number = @exist_days.length - 1 end def save_ini() data = {"last_modified"=>@last_modified,"exist_days"=>@exist_days,"impresses"=>@impresses,"references"=>@references } File.open("#{saved_folder_name()}/ini","w") do |out| begin Marshal.dump(data,out) rescue # out << $! << $@<< "\n" end end end def start_http_raw(serv,port,&block) Net::HTTP.version_1_2 if @proxy_address == "" Net::HTTP.start(serv, port, &block) else Net::HTTP::Proxy(@proxy_address, @proxy_port).start(serv, port, &block) end end def start_http(&block) Net::HTTP.version_1_2 if @proxy_address == "" Net::HTTP.start($server_names[@server_number], 80, &block) else Net::HTTP::Proxy(@proxy_address, @proxy_port).start($server_names[@server_number], 80, &block) end end #rssをチェックする。更新されていればtrue =begin def check_rss(http) if @last_modified == "" return true end res = http.head("/#{$folder_names[@server_number]}/index.rb?vid=#{@village_number}&cmd=rss",{'User-Agent'=>'JB'}) if Time.parse(@last_modified) < Time.parse(res['Last-modified']) @last_modified = res['Last-modified'] return true else return false end end =end def http_get(http,str) res = nil if @user_id == "" res = http.get(str,{'User-Agent'=>'JB'}) else if @server_number == 4 res = http.get(str,{'User-Agent'=>'JB','Cookie'=>'login=' + CGI.escape("L:5%0AS:user_id%0AS:#{@user_id}%0AS:password%0AS:#{@pass}%0AH:L:1%3DL:2%2CL:3%3DL:4%0AEOF")}) elsif @server_number == 6 res = http.get(str,{'User-Agent'=>'JB','Cookie'=>"session_id=#{@session_id}"}) else res = http.get(str,{'User-Agent'=>'JB','Cookie'=>'login=' + CGI.escape("\{\"user_id\"%3D>\"#{@user_id}\"%2C%20\"password\"%3D>\"#{@pass}\"\}")}) end end if res.code == '200' return res end raise res.code end def http_get2(http,str) if @last_modified == "" return true,http_get(http,str) end res = nil if @user_id == "" res = http.get(str,{'User-Agent'=>'JB'})#,'If-Modified-Since'=>@last_modified else if @server_number == 4 res = http.get(str,{'User-Agent'=>'JB','Cookie'=>'login=' + CGI.escape("L:5%0AS:user_id%0AS:#{@user_id}%0AS:password%0AS:#{@pass}%0AH:L:1%3DL:2%2CL:3%3DL:4%0AEOF")}) elsif @server_number == 6 res = http.get(str,{'User-Agent'=>'JB','Cookie'=>"session_id=#{@session_id}"}) else res = http.get(str,{'User-Agent'=>'JB','Cookie'=>'login=' + CGI.escape("\{\"user_id\"%3D>\"#{@user_id}\"%2C%20\"password\"%3D>\"#{@pass}\"\}")}) end end if res.code == '200' return true,res end if res.code == '304' return false,res end raise res.code end def set_number(server_number,village_number) FileUtils.mkdir_p("#{saved_folder_name()}") save_ini() @server_number = server_number @village_number = village_number FileUtils.mkdir_p("#{saved_folder_name()}") load_ini() end #最後の発言取得 def get_last_delivery(ret) last_delivery = "" ret.scan(%r!
.*?.*?
.*?.*?.*?.*?!im){ |m| last_delivery = m } return last_delivery end #ログ結合 def bind(old,new) nstr = $new_message old.gsub!(%r!(#{nstr})!im,"") last_delivery = get_last_delivery(old) last_de_reg = %r!#{Regexp.quote(last_delivery)}(.*)!im if last_delivery != "" hit = false new.scan(last_de_reg) do |m| s1 = $1 old.gsub!(last_de_reg) do |m2| hit = true last_delivery + nstr + s1 end end if hit return old else old = get_html_all() old.gsub!(last_de_reg) do |m| last_delivery + nstr + $1 end return old end else return get_html_all() end end def saved_folder_name return "#{$log_places[@server_number]}/#{@village_number}" end def get_html(reload=false) file_name = "#{saved_folder_name()}/_.html" if reload || !FileTest.exist?(file_name) ret = "" if !FileTest.exist?(file_name) ret = get_html_all() File.open(file_name,"w"){ |out| out.write ret } else start_http do |http| #if check_rss(http) then res = http_get(http,"/#{$folder_names[@server_number]}/index.rb?vid=#{@village_number}") @last_modified = res["Last-modified"] ret = bind(IO.read(file_name),res.body) File.open(file_name,"w"){ |out| out.write ret } #else # ret = IO.read(file_name) #end end end return ret else return IO.read(file_name) end end def get_html_all() ret = "" start_http() do |http| res = http_get(http,"/#{$folder_names[@server_number]}/index.rb?vid=#{@village_number}&mes=all") @last_modified = res["Last-modified"] ret = res.body end return ret end def get_ready_html(reload=false) file_name = "#{saved_folder_name()}/ready.html" if reload || !FileTest.exist?(file_name) ret = "" start_http() {|http| res = http_get(http,"/#{$folder_names[@server_number]}/index.rb?vid=#{@village_number}&meslog=#{@village_number}_ready_0") ret = res.body } open(file_name,"w"){|out| out.write ret } return ret else return IO.read(file_name) end end def get_progress_html(n,reload=false) file_name = "#{saved_folder_name()}/#{n}.html" if reload || !FileTest.exist?(file_name) ret = "" start_http() {|http| res = http_get(http,"/#{$folder_names[@server_number]}/index.rb?vid=#{@village_number}&meslog=#{@village_number}_progress_#{n}") ret = res.body } open(file_name,"w"){|out| out.write ret } return ret else return IO.read(file_name) end end def get_party_html(n,reload=false) file_name = "#{saved_folder_name()}/party.html" if reload || !FileTest.exist?(file_name) ret = "" start_http() {|http| res = http_get(http,"/#{$folder_names[@server_number]}/index.rb?vid=#{@village_number}&meslog=#{@village_number}_party_#{n}") ret = res.body } open(file_name,"w"){|out| out.write ret } return ret else return IO.read(file_name) end end def del_html() file_name = "#{saved_folder_name()}/_.html" FileUtils.rm_f([file_name]) end def del_ready_html() file_name = "#{saved_folder_name()}/ready.html" FileUtils.rm_f([file_name]) end def del_progress_html(n) file_name = "#{saved_folder_name()}/#{n}.html" FileUtils.rm_f([file_name]) end def del_party_html(n) file_name = "#{saved_folder_name()}/party.html" FileUtils.rm_f([file_name]) end def pick_out(html) html = html.gsub(/次の日へ<\/a>/, '次の日へ') html = html.gsub(/(WolfBBS:\d+ by )(ninjin\.)<\/a>/, '\1\2') ss = StringScanner.new(html) messages = [] @login_id = '' if ss.scan(/.*?/mi) ss.scan(%r!人狼BBS:?[A-Z]?\s([A-Z]?\d+.*村)!smi) messages.push({:type=>:title, :text=>ss[1]}) end if ss.scan(/.*?
/mi) ss.scan(%r!(.*?)!smi) if ss[1] =~ / : / @login_id = $`.strip end end if ss.scan(/.*?/mi) ss.scan(%r!((.*?))!smi) messages.push({:type=>:change, :text=>ss[1]}) end while !ss.eos? break if !ss.scan(/.*?
\s*/mi) if ss.scan(/
/mi) ss.scan(%r!(.*?)
!mi) messages.push({:type=>:announce, :text=>ss[1]}) elsif ss.scan(/
/mi) tmptime = ss[1] ss.scan(%r!(.*?).*?(.*?).*?(.*?)
!mi) mes = {:type=>:char, :name=>ss[1], :time=>ss[2], :time2=>tmptime, :kind=>ss[3], :text=>ss[4], :size=>ss[4].gsub(/
/, "\r\n").size, :jsize=>ss[4].gsub(/
/, "\r\n").jsize, :nsize=>ss[4].split(/
/).size} messages.push(mes) Summary.make(mes, @day_number, @references) elsif ss.scan(/
/mi) ss.scan(%r!(.*?)
!mi) messages.push({:type=>:order, :text=>ss[1]}) elsif ss.scan(/
/mi) ss.scan(%r!(.*?)
!mi) messages.push({:type=>:extra, :text=>ss[1]}) elsif ss.scan(/new/) messages.push({:type=>:new}) end end if ss.scan(/.*?/mi) ss.scan(%r!(.*?):userinfo, :character=>ss[1]}) end if ss.scan(/.*?/mi) ss.scan(%r!\s*

(.*?)

!smi) messages.push({:type=>:skill, :text=>ss[1]}) end if ss.scan(/.*?<\/table>(.*?)
:skillmes, :text=>ss[1]}) elsif ss.scan(/.*?<\/table>(.*?)<\/td>/mi) messages.push({:type=>:skillmes, :text=>ss[1]}) end return messages end def kind_mark(it) case it[:kind] when 'say' 'cnt_say"> ' when 'whisper' 'cnt_whisper"> *' when 'think' 'cnt_think"> -' when 'groan' 'cnt_groan"> +' else '' end end def mes_day() if @day_number == @exist_days.size-1 '' else @day_number.to_s + $day_delimit end end def simple_process(html,out) div_id = [1] out << < #{References.javascript} #{@impress_mode ? "" : ""} EOS unless @login_id == '' out << <
EOS end messages = pick_out(html) countmap = {'say'=>Hash.new,'whisper'=>Hash.new,'think'=>Hash.new,'groan'=>Hash.new,'size'=>Hash.new,'jsize'=>Hash.new} ['say','whisper','think','groan','size','jsize'].each {|kind| $name_list.each {|name| countmap[kind][name]=0 } } messages.each do |it| if it[:type] == :announce line = it[:text].to_s if /^.+? は .+? に投票した。/ =~ line line = '>' + it[:text].to_s a = line.scan(/>\s*(.+?) は (.+?) に投票した。/) sig = Hash.new(0) a.each {|n| sig[$nicknames2[n[1]]] = sig[$nicknames2[n[1]]].to_i + 1 } sig_a = sig.to_a.sort {|a, b| b[1] <=> a[1]} s = '' sig_a.each {|a| s << a[0] + '(' + a[1].to_s + '票) ' } if /^(.*)

(.*)/ =~ it[:text].to_s line = $1 + '

' + s + '

' + $2 else line = it[:text].to_s + '

' + s end end out << < #{line}
EOS elsif it[:type] == :extra if ( @role_visible['groan'] && @role_visible['whisper'] && @role_visible['say'] && @role_visible['think'] ) out << < #{it[:text]}
EOS end elsif it[:type] == :order out << < #{it[:text]}
EOS elsif it[:type] == :title out << <<-EOS

#{it[:text]} #{@exist_days[@day_number]} EOS elsif it[:type] == :change out << < #{it[:text]}

EOS elsif it[:type] == :userinfo out << < #{it[:character].strip.gsub(/<.*?>/,'')}
EOS elsif it[:type] == :skill out << < #{it[:text]}
EOS elsif it[:type] == :skillmes out << < #{it[:text]}
EOS elsif it[:type] == :char && @char_visible[it[:name]] && @role_visible[it[:kind]] if !(/今日がお前の命日だ!/ =~ it[:text].to_s) countmap[it[:kind]][it[:name]] += 1 if it[:kind] == 'say' countmap['size'][it[:name]] += it[:size] countmap['jsize'][it[:name]] += it[:jsize] end end hit_search_word = false if @search_word!="" && !(@search_word =~ %r[^//[pharmn]?$]) if @search_reg if it[:text].gsub!(Regexp.new(@search_word)){|m| "#{m}" } hit_search_word = true end elsif @search_word[0]==?/ && @search_word[-1]==?/ if it[:text].gsub!(Regexp.new(@search_word[1...-1])){|m| "#{m}" } hit_search_word = true end else @search_word.split(/ | /).each do |word| if it[:text].gsub!(word){|m| "#{m}" } hit_search_word = true end end end else hit_search_word = true end if !hit_search_word next end if @impress_mode impress_data = "#{@day_number}#{it[:name]}#{it[:time]}".gsub(" ",""){} hit_impress = false @impress_visible.each do |key,val| impin = impresses_in?(impress_data,key) if val && !impin hit_impress = true end end if hit_impress next end end # 発言参照を調べる $simple_mode = true ref = References.find(it, div_id, @day_number, @references) next if ref.skip?(@search_word) out << <'}
#{ if @impress_mode < EOS else "" end }
#{$nicknames2[it[:name]]} #{$nicknames3[it[:name]]}#{mes_day}#{Time::at(it[:time2].to_i).strftime('%H:%M')}#{Time::at(it[:time2].to_i).strftime('(%Y/%m/%d %H:%M:%S)')}

#{ref.text}
EOS out << <
EOS elsif it[:type] == :new out << <ここから下が新規取得分です
EOS end end aary = [] $name_list.each do |name| if countmap['say'][name]!=0 then aary.push([countmap['say'][name], name]) end end if aary.length > 0 out << '
' out << 'この日のそれぞれの発言回数/発言密度:' aary.sort!{|x, y| y[0] <=> x[0]} rt = "" aary.each{|a| rt += "#{$nicknames[a[1]]}(#{a[0]}/#{countmap['jsize'][a[1]]/a[0]}) " } out << rt out << "
" out << '
Powered by ruby ' << RUBY_VERSION << ' (' << RUBY_RELEASE_DATE << ')' << ' [' << RUBY_PLATFORM << ']' << '
' end out << <" : ""} EOS rescue out << "#{$!}#{$@}" end def process(html,out) References.togglepop(@search_word) if @simple_mode return simple_process(html,out) end div_id = [1] out << < #{References.javascript}
#{@impress_mode ? "" : ""}
EOS unless @login_id == '' out << <
EOS end messages = pick_out(html) countmap = {"楽天家 ゲルト"=>0} $name_list.each do |name| countmap[name]=0 end messages.each do |it| if it[:type] == :announce line = it[:text].to_s if /^.+? は .+? に投票した。/ =~ line line = '>' + it[:text].to_s a = line.scan(/>\s*(.+?) は (.+?) に投票した。/) sig = Hash.new(0) a.each {|n| sig[$nicknames2[n[1]]] = sig[$nicknames2[n[1]]].to_i + 1 } sig_a = sig.to_a.sort {|a, b| b[1] <=> a[1]} s = '' sig_a.each {|a| s << a[0] + '(' + a[1].to_s + '票) ' } if /^(.*)

(.*)/ =~ it[:text].to_s line = $1 + '

' + s + '

' + $2 else line = it[:text].to_s + '

' + s end end if it[:text] =~ %r!楽天家 ゲルト (.*?)、死亡。村人だった。! out << <
まとめサイトにそのまま貼れるキャスト一覧を生成します。以下をコピペしてください。

|LEFT:~配役|LEFT:~参加者|LEFT:~生死|LEFT:~役職|LEFT:~備考|h
EOS it[:text].scan(/(.*?) ((.*?))、(.*?)。(.*?)だった。/) do s1 = $1 s2 = $2 s3 = $3 s4 = $4 s5 = "" s6 = "" if s2 =~ %r!>(.*)\s*?/,"") out << < EOS end out << <
EOS end out << <
#{line}
EOS elsif it[:type] == :extra if ( @role_visible['groan'] && @role_visible['whisper'] && @role_visible['say'] && @role_visible['think'] ) out << <
#{it[:text]}
EOS end elsif it[:type] == :order out << <
#{it[:text]}
EOS elsif it[:type] == :title out << < #{it[:text]} EOS elsif it[:type] == :change out << < #{it[:text]}

EOS elsif it[:type] == :userinfo out << < #{it[:character].strip.gsub(/<.*?>/,'')}
EOS elsif it[:type] == :skill out << < #{it[:text]}
EOS elsif it[:type] == :skillmes out << < #{it[:text]}
EOS elsif it[:type] == :char && @char_visible[it[:name]] && @role_visible[it[:kind]] if it[:kind]=="say" countmap[it[:name]] += 1 end hit_search_word = false if @search_word!="" && !(@search_word =~ %r[^//[pharmn]?$]) if @search_reg if it[:text].gsub!(Regexp.new(@search_word)){|m| "#{m}" } hit_search_word = true end elsif @search_word[0]==?/ && @search_word[-1]==?/ if it[:text].gsub!(Regexp.new(@search_word[1...-1])){|m| "#{m}" } hit_search_word = true end else @search_word.split(/ | /).each do |word| if it[:text].gsub!(word){|m| "#{m}" } hit_search_word = true end end end else hit_search_word = true end if !hit_search_word next end if @impress_mode impress_data = "#{@day_number}#{it[:name]}#{it[:time]}".gsub(" ",""){} hit_impress = false @impress_visible.each do |key,val| impin = impresses_in?(impress_data,key) if val && !impin hit_impress = true end end if hit_impress next end end # 発言参照を調べる $simple_mode = false ref = References.find(it, div_id, @day_number, @references) next if ref.skip?(@search_word) out << < #{ @impress_mode ? "
" : "" } #{it[:name]} #{it[:time]} #{ it[:kind]=="say" ? " #{countmap[it[:name]]}回" : "" } #{ if @impress_mode <
EOS # # # # # # else "" end }
#{ref.text}
#{ref.summary} EOS elsif it[:type] == :new out << <
ここから下が新規取得分です

EOS end end aary = [] aary2 = [] $name_list.each do |name| if countmap[name]!=0 then aary.push([countmap[name],$nicknames[name]]) aary2.push([countmap[name],$nicknames2[name]]) end #mes += name #mes += "は、この日#{countmap[name]}回発言した。
" end if aary.length > 0 out << '
' out << 'この日のそれぞれの発言回数
' aary.sort!{|x, y| y[0] <=> x[0]} aary2.sort!{|x, y| y[0] <=> x[0]} rt = "" aary.each{|a| rt += "#{a[1]}#{a[0]} " } out << rt out << "

" rt = "" aary2.each{|a| rt += "#{a[1]}(#{a[0]}) " } out << rt out << "
" end out << < #{@impress_mode ? "" : ""}
EOS rescue out << "#{$!}#{$@}" end def set_impress(str) #open("debug.txt","a"){|out| str.sub(/dummy:\/\/impress\/\?(.*?)=(.*)/m) do |m| s1 = CGI.unescape($1) s2 = CGI.unescape($2) #out.puts "#{CGI.unescape $1},#{CGI.unescape $2}" if @impresses[s1] != nil if @impresses[s1][s2] #out.puts "set false" @impresses[s1][s2] = false else #out.puts "set true" @impresses[s1][s2] = true end else #out.puts "set true" @impresses[s1] = { s2=>true } end end #} end def impresses_in?(data,imp) #open("debug.txt","a"){|out| #out.puts "- #{data},#{CGI.unescape imp}" if @impresses[data] != nil return @impresses[data][imp] else return false end #} end def pick_out_exist_days(ret) ret.sub(%r!

(.*?)

!im){|m| @exist_days=[] m.gsub(%r!(.*?)!im){ @exist_days.push($1) } m.sub(/(.*?)<\/span>/im){ @exist_days.push($1) } } end def arrange_ready(reload=false) @day_number = 0 File.open("temp.html","w"){ |out| process(get_ready_html(reload),out) } end def arrange_progress(n,reload=false) @day_number = n + 1 File.open("temp.html","w"){ |out| process(get_progress_html(n,reload),out) } end def arrange_party(n,reload=false) @day_number = n + 1 File.open("temp.html","w"){ |out| process(get_party_html(n,reload),out) } end def arrange(reload=false) html = get_html(reload) pick_out_exist_days(html); @day_number = @exist_days.length - 1 File.open("temp.html","w"){ |out| process(html,out) } save_ini() end def get_data(http,dst,src) res = http_get(http,src) open(dst,'w'){ |out| out.binmode out.write res.body } end def get_pictures() if FileTest.exist?("plugin_wolf/img/think06.jpg") && FileTest.exist?("img/skill07.jpg") return end FileUtils.mkdir_p("img") FileUtils.mkdir_p("plugin_wolf/img") if !FileTest.exist?("plugin_wolf/img/think06.jpg") start_http_raw('ninjin001.x0.com', 80) {|http| get_data http,'plugin_wolf/css.css','/wolfe/plugin_wolf/css.css' get_data http,'plugin_wolf/img/say05.jpg','/wolfe/plugin_wolf/img/say05.jpg' get_data http,'plugin_wolf/img/say06.jpg','/wolfe/plugin_wolf/img/say06.jpg' get_data http,'plugin_wolf/img/whisper05.jpg','/wolfe/plugin_wolf/img/whisper05.jpg' get_data http,'plugin_wolf/img/whisper06.jpg','/wolfe/plugin_wolf/img/whisper06.jpg' get_data http,'plugin_wolf/img/groan05.jpg','/wolfe/plugin_wolf/img/groan05.jpg' get_data http,'plugin_wolf/img/groan06.jpg','/wolfe/plugin_wolf/img/groan06.jpg' get_data http,'plugin_wolf/img/think05.jpg','/wolfe/plugin_wolf/img/think05.jpg' get_data http,'plugin_wolf/img/think06.jpg','/wolfe/plugin_wolf/img/think06.jpg' } end if !FileTest.exist?("img/skill07.jpg") start_http_raw('ninjin001.x0.com', 80) do |http| get_data http,'img/face99.jpg','/wolfe/plugin_wolf/img/face99.jpg' get_data http,'img/title.jpg','/wolfe/plugin_wolf/img/title.jpg' get_data http,'img/say00.jpg','/wolfe/plugin_wolf/img/say00.jpg' get_data http,'img/say01.jpg','/wolfe/plugin_wolf/img/say01.jpg' get_data http,'img/say02.jpg','/wolfe/plugin_wolf/img/say02.jpg' get_data http,'img/say03.jpg','/wolfe/plugin_wolf/img/say03.jpg' get_data http,'img/say04.jpg','/wolfe/plugin_wolf/img/say04.jpg' get_data http,'img/whisper00.jpg','/wolfe/plugin_wolf/img/whisper00.jpg' get_data http,'img/groan00.jpg','/wolfe/plugin_wolf/img/groan00.jpg' get_data http,'img/think00.jpg','/wolfe/plugin_wolf/img/think00.jpg' get_data http,'img/face01.jpg','/wolfe/plugin_wolf/img/face01.jpg' get_data http,'img/face02.jpg','/wolfe/plugin_wolf/img/face02.jpg' get_data http,'img/face03.jpg','/wolfe/plugin_wolf/img/face03.jpg' get_data http,'img/face04.jpg','/wolfe/plugin_wolf/img/face04.jpg' get_data http,'img/face05.jpg','/wolfe/plugin_wolf/img/face05.jpg' get_data http,'img/face06.jpg','/wolfe/plugin_wolf/img/face06.jpg' get_data http,'img/face07.jpg','/wolfe/plugin_wolf/img/face07.jpg' get_data http,'img/face08.jpg','/wolfe/plugin_wolf/img/face08.jpg' get_data http,'img/face09.jpg','/wolfe/plugin_wolf/img/face09.jpg' get_data http,'img/face10.jpg','/wolfe/plugin_wolf/img/face10.jpg' get_data http,'img/face11.jpg','/wolfe/plugin_wolf/img/face11.jpg' get_data http,'img/face12.jpg','/wolfe/plugin_wolf/img/face12.jpg' get_data http,'img/face13.jpg','/wolfe/plugin_wolf/img/face13.jpg' get_data http,'img/face14.jpg','/wolfe/plugin_wolf/img/face14.jpg' get_data http,'img/face15.jpg','/wolfe/plugin_wolf/img/face15.jpg' get_data http,'img/face16.jpg','/wolfe/plugin_wolf/img/face16.jpg' get_data http,'img/face17.jpg','/wolfe/plugin_wolf/img/face17.jpg' get_data http,'img/say00b.jpg','/wolfe/plugin_wolf/img/say00b.jpg' get_data http,'img/body01.jpg','/wolfe/plugin_wolf/img/body01.jpg' get_data http,'img/body02.jpg','/wolfe/plugin_wolf/img/body02.jpg' get_data http,'img/body03.jpg','/wolfe/plugin_wolf/img/body03.jpg' get_data http,'img/body04.jpg','/wolfe/plugin_wolf/img/body04.jpg' get_data http,'img/body05.jpg','/wolfe/plugin_wolf/img/body05.jpg' get_data http,'img/body06.jpg','/wolfe/plugin_wolf/img/body06.jpg' get_data http,'img/body07.jpg','/wolfe/plugin_wolf/img/body07.jpg' get_data http,'img/body08.jpg','/wolfe/plugin_wolf/img/body08.jpg' get_data http,'img/body09.jpg','/wolfe/plugin_wolf/img/body09.jpg' get_data http,'img/body10.jpg','/wolfe/plugin_wolf/img/body10.jpg' get_data http,'img/body11.jpg','/wolfe/plugin_wolf/img/body11.jpg' get_data http,'img/body12.jpg','/wolfe/plugin_wolf/img/body12.jpg' get_data http,'img/body13.jpg','/wolfe/plugin_wolf/img/body13.jpg' get_data http,'img/body14.jpg','/wolfe/plugin_wolf/img/body14.jpg' get_data http,'img/body15.jpg','/wolfe/plugin_wolf/img/body15.jpg' get_data http,'img/body16.jpg','/wolfe/plugin_wolf/img/body16.jpg' get_data http,'img/body17.jpg','/wolfe/plugin_wolf/img/body17.jpg' get_data http,'img/body99.jpg','/wolfe/plugin_wolf/img/body99.jpg' get_data http,'img/skill00.jpg','/wolfe/plugin_wolf/img/skill00.jpg' get_data http,'img/skill01.jpg','/wolfe/plugin_wolf/img/skill01.jpg' get_data http,'img/skill02.jpg','/wolfe/plugin_wolf/img/skill02.jpg' get_data http,'img/skill03.jpg','/wolfe/plugin_wolf/img/skill03.jpg' get_data http,'img/skill04.jpg','/wolfe/plugin_wolf/img/skill04.jpg' get_data http,'img/skill05.jpg','/wolfe/plugin_wolf/img/skill05.jpg' get_data http,'img/skill06.jpg','/wolfe/plugin_wolf/img/skill06.jpg' get_data http,'img/skill07.jpg','/wolfe/plugin_wolf/img/skill07.jpg' end end end def get_max_village_number(n) server_name=$server_names[n] folder_name=$folder_names[n] @server_number_tmp = @server_number @server_number = n ret = "" max = "0" start_http_raw(server_name, 80) do |http| res = http_get(http,"/#{folder_name}/index.rb") ret = res.body ret.sub(/
(.*?)<\/a>/m) do max = $1 end end open("top.html","w"){ |out| out.write ret } @server_number = @server_number_tmp return max end def get_max_village() return "94 744 366 182 #{get_max_village_number(4)} 703 #{get_max_village_number(6)} #{get_max_village_number(7)}" end def get_session_id(username, password) session = '' session_id = '' if username != '' && password != '' tk = TypeKey.new(username, password) session = tk.login f = File::open('tk_key_cache', 'w') f.print 'username=', username, '; ' f.puts session f.close if session =~ /session_id=(\d+);/ session_id = $1 end end return session_id end end #require 'novel.rb' $jinro = Jinro.new() class Summary attr_accessor :time, :nick, :kind, :ddhhmm, :text def initialize(time, kind, nick, ddhhmm) @time = time; @kind = kind @nick = nick; @ddhhmm = ddhhmm end def self.make(it, day, references) mdate = MessageDate.parse("#{day}d#{Time::at(it[:time2].to_i).strftime('%H:%M')}", day) ddhhmm = mdate.to_s nick = $nicknames2[it[:name]] m = self.new(it[:time2], it[:kind], nick, ddhhmm) m.text = it[:text].gsub(%r!(?:
)+!, "
") # 空行は除く found = 0 if references[ddhhmm] == nil references[ddhhmm] = [] end references[ddhhmm].each {|x| found = 1 if x.time == m.time && x.nick == m.nick} if found == 0 references[ddhhmm] << m end end def time return @time end def nick return @nick end def link ltxt = "#{@nick} #{@ddhhmm}#{k(@kind)}" return ltxt #return "
#{ltxt}" end def face img = @kind=='groan' ? "face99.jpg" : $face_images[$inv_nick2[@nick]] ltxt = %| #{@nick} #{@ddhhmm}#{k(@kind)}| return ltxt #return "#{ltxt}" end def k(kind) case kind when 'say' ' ' when 'whisper' ' *' when 'think' ' -' when 'groan' ' +' else '' end end def summary if $simple_mode return "
#{self.link} #{@text}
" else return "
#{self.face} #{@text}
" end end def self.parse_nick(pre) found = [] # 見つかったものを集める name = (" " + pre)[-20..-1] # まあ10文字くらい見ればいいだろう $nicknames4.keys.each do |nick| nick_regex = $nicknames4[nick] pos = 22 if nick_regex != nil && nick_regex =~ name found << [$'.length, nick] end end found.sort{|a,b| a[0]<=>b[0]}.map{|x| x[1]}.first end # 参照先の発言を見つける def self.find(mdate, day, pre, it, references) kind = it[:kind] nick = self.parse_nick(pre) rej = []; rej2 = []; rej3 = [] found = []; found2 = []; found3 = [] (found, rej) = self.find2(mdate, day, nick, kind, references) if found.empty? # 見つからなかった # 日付指定がされていなければ午後、前日の順で調べる if mdate.dd_text == nil && mdate.hh < 12 && mdate.ampm === '' mdate2 = mdate.clone mdate2.hh = mdate2.hh + 12 mdate2.recalc_ddhhmm (found2, rej2) = self.find2(mdate2, day, nick, kind, references) end if mdate.dd_text == nil && day > 0 mdate3 = mdate.clone mdate3.dd = mdate3.dd - 1 mdate3.recalc_ddhhmm (found3, rej3) = self.find2(mdate3, day-1, nick, kind, references) end end if found.empty? && nick != nil # 名前が指定されている場合、午後、前日の順 found = found2 if found.empty? found = found3 if found.empty? found = rej if found.empty? found = rej2 if found.empty? found = rej3 if found.empty? else # 指定されていない場合、今日の名前し、午後、前日の順 found = rej if found.empty? found = found2 if found.empty? found = rej2 if found.empty? found = found3 if found.empty? found = rej3 if found.empty? end if found.empty? return nil else return found.map{|x| x.summary}.join("\n") end rescue return "#{$!}#{$@}" end def self.find2(mdate, day, nick, kind, references) begin ddhhmm = mdate.to_s found = references[ddhhmm] # 見つかったものを集める found = [] if found == nil # found = [ Summary, ... ] rej_nick = [] # nick不一致ではじかれたもの rej_kind = [] # kind条件はじかれたもの # ログ色でフィルタ # 白ログからの参照で赤ログが出てこないようにフィルタ # あーでも、エピだと出ることがあるのか…… begin kind_ok = found.select do |m| k = m.kind case kind when 'say' kind == k # 白ログからは白ログのみ when 'whisper', 'groan' k == 'say' || kind == k # 赤と青からは白も見える when 'think' true # 灰ログからはどれの可能性もある end end rej_kind = found - kind_ok found = kind_ok end # 名前でフィルタ if nick rej_nick = found.select{|x| x.nick != nick} found = found - rej_nick end return [found, rej_nick] end end end class MessageDate # 日付アンカーの正規表現解説 # 基本的に全角数字、漢数字は無視ね。 def self.regex return @@datetime_regex end @@num_zen_han = Hash[*%w(0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9)] @@d = %r([0-90-9]) def self.zen_han(num) ret = nil if !num.nil? ret = num.gsub(/(#{@@d})/) {|x| @@num_zen_han[x] || x} end return ret end @@datetime_regex = %r((?ix) # 日付部分 # 3d, 3D, 3日, 3日目, 3-, 3d など (?: (?: (昨日|今日) # $1 = 昨日 or 今日 | (#{@@d}+) # $2 = 日: 長丁場の村では2ケタになることも (?:d(?:ay)?|d|日(?:目)?|-) # 日付を表わすsuffix。 ) (?:[\-\s,:()] # 日付とampmの区切り。 |:|、|の|に|で|()* # 文字クラス内に全角文字置くと効かないのはなぜ? )? # 日付はなくてもok(その場合当日) # 午前/午後部分 # 午前, 午後, am, PM ( # $3 = 午前午後 (?:午前|午後|am|pm)? # 省略可 ) \s? # am/pmと時刻の間の区切りには空白が高々ひとつまで # 時刻部分 (?: # パターン1: 13:24など、必ず区切りがあるパターン。途中で空白は出てこない (#{@@d}?#{@@d}) # $4 = 時: 1ケタでもよい (?:[:*\-]|:) # 時分の区切りは普通:でしょ。でも-とか*を使ってる人も # 「:」は文字クラス内書いちゃだめ (#{@@d}#{@@d}) # $5 = 分: この形式のとき、分は1ケタではダメ。 | # パターン2: 13時24分、9時6分、など。時分があるので空白が入り得る (#{@@d}?#{@@d})時 # $6 = 時: 1ケタでもよい \s? # 間には空白が高々ひとつ (#{@@d}?#{@@d})分 # $7 = 分: 1ケタでもよい | # パターン3: 0200など「ヒトフタマルマル」形式 # 色指定の「#ff0000」「#800030」などを誤認識したくない #(?!<#{@@d}|[a-fA-F\#]) # 16進数と#に続いてたらダメ # negative lookbehindが使えれば…… (#{@@d}#{@@d}) # $8 = 時: 必ず2ケタ (#{@@d}#{@@d}) # $9 = 分: 必ず2ケタ。時分はくっついていること (?!#{@@d}|[a-fA-F\x22\x21]) # 後ろに数字やダブルクォートが続いてたらダメ )) attr_accessor :dd_text, :dd, :ampm, :hh, :mm, :ddhhmm, :pm def self.parse(text, day) return nil unless text =~ @@datetime_regex if $~[1] dd_text = $~[1] dd = day + (dd_text == '昨日' ? -1 : 0) else dd_text = $~[2] dd = zen_han(dd_text) || day dd = dd.to_i + 0 end ampm = $~[3] hh = zen_han($~[4] || $~[6] || $~[8]) mm = zen_han($~[5] || $~[7] || $~[9]) hh = hh.to_i pm = ampm =~ /午後|pm/i hh += 12 if pm && hh != 12 # 午後12時は正午とする return new(dd_text, dd, ampm, hh, mm, pm) end def recalc_ddhhmm @ddhhmm = sprintf("%dd%02d:%02d", @dd, @hh % 24, @mm.to_i) end def initialize(dd_text, dd, ampm, hh, mm, pm) @dd_text = dd_text; @dd = dd; @ampm = ampm; @hh = hh; @mm = mm; @pm = pm recalc_ddhhmm end def to_str return @ddhhmm end def to_s return self.to_str end def has_day? return @dd_text != nil end end class References attr_accessor :anchor_found, :referer_found, :misshit_found, :summary, :text def initialize(sum, text) @summary = sum @text = text @anchor_found = @referer_found = @misshit_found = false end def self.find(it, div_id, day, refs) sum = "" txt = "" lastpre = "" anchor_found = false referer_found = false misshit_found = false begin done = {} ss2 = StringScanner.new(it[:text]) while !ss2.eos? break if !ss2.scan(/(.*?)(#{MessageDate.regex})/omi) pre = ss2[1] txt << pre if pre.length <= 2 pre = lastpre + pre end lastpre = pre #sum << "#{ss2[2]}: " mdate = MessageDate.parse(ss2[2], day) ddhhmm = mdate.to_s anchor_found = true #sum << "#{ddhhmm}: " if !done[ddhhmm] div_id[0] = div_id[0] + 1 done[ddhhmm] = div_id[0] ref = Summary.find(mdate, day, pre, it, refs) if ref != nil sum << "

#{ref}
" else done[ddhhmm] = 1 end end if done[ddhhmm] > 1 txt << %|#{ss2[2]}| referer_found = true else txt << ss2[2] misshit_found = true end end txt << ss2[1] if ss2.scan(/(.*)/) ref = References.new(sum, txt) ref.anchor_found = anchor_found ref.referer_found = referer_found ref.misshit_found = misshit_found return ref rescue txt << $! << $@.join("
") << "\n" return References.new(sum, txt) end end def skip?(pat) if pat =~ %r[^//([armn]?)$] case $1 when 'r', '' return !@referer_found when 'a' return !@anchor_found when 'm' return !@misshit_found when 'n' return @anchor_found end end return false end def self.javascript < function showHide(id){ var node = document.getElementById(id) var d = node.style.display if (d == "none") { node.style.display = 'block'; } else { node.style.display = 'none'; } return false; } EOS end # デフォルトでリンク先ポップアップを出すかどうか # @@popup = true # 出す @@popup = false # 出さない def self.popstyle() return "style='display: " + (@@popup ? 'block' : 'none') + "'" end def self.togglepop(pat) if pat =~ %r[^//([ph]?)$] case $1 when 'p' @@popup = true when 'h' @@popup = false end end end end