Changeset 33659

Show
Ignore:
Timestamp:
05/29/09 13:53:00 (4 years ago)
Author:
drry
Message:
  • (tig.rb) 一部の特殊なユーザーを WHOIS すると起きる不具合を修正しました。
  • (tig.rb) destroy コマンドが正常に動作しないバグを修正しました。
  • (tig.rb) Remove などにより友だちが減って PART する際にエラーが起きるバグを修正しました。
  • (tig.rb) まだ友だち一覧にないユーザーがタイムラインに流れてきた場合は即 JOIN するようにしました。
  • (tig.rb) 100人以上の友だち一覧に対応しました。環境によりますが最大で8,700人程度までの対応となります。
  • (tig.rb) check_friends_interval オプションを追加しました。友だち一覧の更新間隔を3600秒以下の秒数で指定します。既定では1時間の3600秒です。
  • (tig.rb) ほか。
Files:
1 modified

Legend:

Unmodified
Added
Removed
  • lang/ruby/net-irc/trunk/examples/tig.rb

    r33626 r33659  
    116116 
    117117### max_params_count=<number> 
     118 
     119### check_friends_interval=<seconds> 
    118120 
    119121## Extended commands through the CTCP ACTION 
     
    284286                post @prefix, JOIN, main_channel 
    285287                post server_name, MODE, main_channel, "+mto", @prefix.nick 
    286                 post @prefix, TOPIC, main_channel, generate_status_message(@me.status) if @me.status 
     288                if @me.status 
     289                        @me.status.user = @me 
     290                        post @prefix, TOPIC, main_channel, generate_status_message(@me.status.text) 
     291                end 
    287292 
    288293                if @opts.jabber 
     
    324329                                        end 
    325330                                end 
    326                                 sleep 3600 # interval(@ratio.friends) 
     331                                sleep @opts.check_friends_interval || 3600 
    327332                        end 
    328333                end 
     
    334339 
    335340                @check_timeline_thread = Thread.start do 
    336                         sleep 3 
     341                        sleep 2 * (@me.friends_count / 100.to_f).ceil 
    337342 
    338343                        loop do 
     
    422427                                        ret = api("statuses/update", { :status => mesg, :source => source }) 
    423428                                        log oops(ret) if ret.truncated 
    424                                         ret.user = nil 
    425                                         @me.status = ret 
     429                                        ret.user.status = ret 
     430                                        @me = ret.user 
    426431                                end 
    427432                        else # direct message 
     
    476481                                count = 20 
    477482                        end 
    478                         to = nick == @nick ? server_name : nick 
     483                        to  = nick == @nick ? server_name : nick 
    479484                        res = api("statuses/user_timeline/#{nick}", 
    480                                   { :count => count },{ :authenticate => false }).reverse_each do |s| 
     485                                  { :count => count }, { :authenticate => false }) 
     486                        res.reverse_each do |s| 
    481487                                time = Time.parse(s.created_at) rescue Time.now 
    482488                                post to, NOTICE, main_channel, 
    483                                      "#{time.strftime "%m-%d %H:%M"} #{generate_status_message(s)}" 
     489                                     "#{time.strftime "%m-%d %H:%M"} #{generate_status_message(s.text)}" 
    484490                        end 
    485491                        unless res 
     
    495501                                if method == "create" 
    496502                                        id = @timeline.last 
    497                                         @tmap.any? do |k, v| 
     503                                        @tmap.any? do |tid, v| 
    498504                                                if v.id == id 
    499505                                                        statuses.push v 
     
    513519                                        when status = @tmap[tid_or_nick] 
    514520                                                statuses.push status 
    515                                         when friend = @friends.find {|i| i.screen_name.casecmp(tid_or_nick).zero? } 
     521                                        when friend = (@friends || []).find {|i| i.screen_name.casecmp(tid_or_nick).zero? } 
    516522                                                if friend.status 
    517523                                                        statuses.push friend.status 
     
    532538                                end 
    533539                                res = api("favorites/#{method}/#{status.id}") 
    534                                 log "#{entered}: #{res.user.screen_name}: #{res.text}" 
     540                                log "#{entered}: #{res.user.screen_name}: #{generate_status_message(res.text)}" 
    535541                                if method == "create" 
    536542                                        @favorites.push res 
     
    538544                                        @favorites.delete_if {|i| i.id == res.id } 
    539545                                end 
    540                                 sleep 0.5 
    541546                        end 
    542547                when "link", "ln" 
     
    596601                        statuses.each do |status| 
    597602                                res = api("statuses/destroy/#{status.id}") 
    598                                 @tmap.delete_if {|k, v| v.id == res.id } 
    599                                 b = @me.key?("status") and @me.status.id == status.id 
     603                                @tmap.delete_if {|tid, v| v.id == res.id } 
     604                                b = @me.status and @me.status.id == status.id 
    600605                                log "Destroyed: #{res.text}" 
    601                                 sleep 0.5 
    602606                        end 
    603607                        if b 
     608                                sleep 2 
    604609                                @me = api("account/update_profile") #api("account/verify_credentials") 
    605                                 post @prefix, TOPIC, main_channel, generate_status_message(@me.status) if @me.status 
     610                                if @me.status 
     611                                        @me.status.user = @me 
     612                                        msg = generate_status_message(@me.status.text) 
     613                                        @tmap.any? do |tid, v| 
     614                                                if v.id == @me.status.id 
     615                                                        msg << " " << colored_tid(tid) 
     616                                                end 
     617                                        end 
     618                                        post @prefix, TOPIC, main_channel, msg 
     619                                end 
    606620                        end 
    607621                when "name" 
     
    609623                        unless name.nil? 
    610624                                @me = api("account/update_profile", { :name => name }) 
     625                                @me.status.user = @me if @me.status 
    611626                                log "You are named #{@me.name}." 
    612627                        end 
     
    616631                        unless email.nil? 
    617632                                @me = api("account/update_profile", { :email => email }) 
     633                                @me.status.user = @me if @me.status 
    618634                        end 
    619635                when "url" 
     
    621637                        url = args.first || "" 
    622638                        @me = api("account/update_profile", { :url => url }) 
     639                        @me.status.user = @me if @me.status 
    623640                when "in", "location" 
    624641                        location = mesg.split(/ +/, 3)[2] || "" 
    625642                        @me = api("account/update_profile", { :location => location }) 
    626                         location = @me.location.empty? ? "nowhere" : "in #{@me.location}" 
     643                        @me.status.user = @me if @me.status 
     644                        location = @me.location and @me.location.empty? ? "nowhere" : "in #{@me.location}" 
    627645                        log "You are #{location} now." 
    628646                when /\Adesc(?:ription)?\z/ 
     
    630648                        description = mesg.split(/ +/, 3)[2] || "" 
    631649                        @me = api("account/update_profile", { :description => description }) 
     650                        @me.status.user = @me if @me.status 
    632651                #when /\Acolou?rs?\z/ # TODO 
    633652                #       # bg, text, link, fill and border 
     
    644663                                                                :in_reply_to_status_id => status.id }) 
    645664                                log oops(ret) if ret.truncated 
    646                                 msg = generate_status_message(status) 
     665                                msg = generate_status_message(status.text) 
    647666                                url = permalink(status) 
    648667                                log "Status updated (In reply to #{colored_tid(tid)}: #{msg} <#{url}>)" 
    649                                 ret.user = nil 
    650                                 @me.status = ret 
     668                                ret.user.status = ret 
     669                                @me = ret.user 
    651670                        end 
    652671                when /\Aspoo(o+)?f\z/ 
     
    662681                        end 
    663682                        args.each do |bot| 
    664                                 unless user = @friends.find {|i| i.screen_name.casecmp(bot).zero? } 
     683                                user = (@friends || []).find {|i| i.screen_name.casecmp(bot).zero? } 
     684                                unless user 
    665685                                        post server_name, ERR_NOSUCHNICK, bot, "No such nick/channel" 
    666686                                        next 
     
    698718                end 
    699719 
    700                 host = hostname user 
    701                 desc = user.name 
    702                 desc = "#{desc} / #{user.description}".gsub(/\s+/, " ") unless user.description.empty? 
     720                host      = hostname user 
     721                desc      = user.name 
     722                desc      = "#{desc} / #{user.description}".gsub(/\s+/, " ") if user.description and not user.description.empty? 
    703723                signon_at = Time.parse(user.created_at).to_i rescue 0 
    704724                idle_sec  = (Time.now - (user.status ? Time.parse(user.status.created_at) : signon_at)).to_i rescue 0 
    705                 location  = user.location.empty? ? "SoMa neighborhood of San Francisco, CA" : user.location 
     725                location  = user.location 
     726                location  = "SoMa neighborhood of San Francisco, CA" if location.nil? or location.empty? 
    706727                post server_name, RPL_WHOISUSER,   @nick, nick, "id=%09d" % user.id, host, "*", desc 
    707                 #post server_name, RPL_WHOISSERVER, @nick, nick, api_base.host, "SoMa neighborhood of San Francisco, CA" 
    708728                post server_name, RPL_WHOISSERVER, @nick, nick, api_base.host, location 
    709729                post server_name, RPL_WHOISIDLE,   @nick, nick, "#{idle_sec}", "#{signon_at}", "seconds idle, signon time" 
     
    722742                        users.each {|friend| whoreply channel, friend } 
    723743                        post server_name, RPL_ENDOFWHO, @nick, channel 
    724                 when @groups.key?(channel) 
    725                         @groups[channel].each do |name| 
    726                                 whoreply channel, @friends.find {|i| i.screen_name == name } 
     744                when (@groups.key?(channel) and @friends) 
     745                        @groups[channel].each do |nick| 
     746                                whoreply channel, @friends.find {|i| i.screen_name == nick } 
    727747                        end 
    728748                        post server_name, RPL_ENDOFWHO, @nick, channel 
     
    775795                return if channel.casecmp(main_channel).zero? 
    776796 
    777                 if @friends and f = @friends.find {|i| i.screen_name.casecmp(nick).zero? } 
     797                f = (@friends || []).find {|i| i.screen_name.casecmp(nick).zero? } 
     798                if f 
    778799                        ((@groups[channel] ||= []) << f.screen_name).uniq! 
    779800                        post generate_prefix(f), JOIN, channel 
     
    811832                        topic    = m.params[1] 
    812833                        previous = @me.status 
     834                        return unless previous 
     835 
    813836                        distance = Levenshtein.normalized_distance(previous.text, topic) 
    814  
    815837                        return if distance.zero? 
    816838 
    817839                        status = api("statuses/update", { :status => topic, :source => source }) 
    818840                        log oops(ret) if status.truncated 
    819                         status.user = nil 
    820                         @me.status = status 
     841                        status.user.status = status 
     842                        @me = status.user 
    821843 
    822844                        if distance < 0.5 
     
    840862 
    841863                        @timeline << id 
    842                         tid  = @tmap.push(status.dup) 
    843                         mesg = generate_status_message(status) 
     864 
     865                        status.user.status = status 
     866                        tid  = @opts.tid ? @tmap.push(status) : nil 
    844867                        user = status.user 
    845                         nick = user.screen_name 
    846  
    847                         status.user = nil 
    848  
    849                         mesg << " " << colored_tid(tid) if @opts.tid 
    850  
    851                         @log.debug [id, nick, mesg] 
    852                         if nick == @me.screen_name # 自分のときは TOPIC に 
     868 
     869                        @log.debug [id, user.screen_name, status.text] 
     870 
     871                        if user.id == @me.id 
     872                                mesg = generate_status_message(status.text) 
     873                                mesg << " " << colored_tid(tid) if @opts.tid 
    853874                                post @prefix, TOPIC, main_channel, mesg 
    854875 
    855                                 @me.status = status 
     876                                @me = user 
    856877                        else 
    857                                 message(user, main_channel, mesg) 
    858  
    859                                 @friends.any? do |friend| 
    860                                         if friend.id == user.id 
    861                                                 friend.status = status 
    862                                         end 
    863                                 end 
     878                                if @friends 
     879                                        b = false 
     880                                        @friends.each_with_index do |friend, i| 
     881                                                if b = friend.id == user.id 
     882                                                        @friends[i] = user 
     883                                                        break 
     884                                                end 
     885                                        end 
     886                                        unless b 
     887                                                join main_channel, [user] 
     888                                                @friends << user 
     889                                        end 
     890                                end 
     891 
     892                                message(status, main_channel, tid) 
    864893                        end 
    865894                        @groups.each do |channel, members| 
    866                                 next unless members.include?(nick) 
    867                                 message(user, channel, mesg) 
     895                                next unless members.include?(user.screen_name) 
     896                                message(status, channel, tid) 
    868897                        end 
    869898                end 
     
    872901        end 
    873902 
    874         def generate_status_message(status) 
    875                 mesg = status.text 
     903        def generate_status_message(mesg) 
    876904                @log.debug mesg.gsub(/\r\n|[\r\n]/, "<\\n>") 
    877905 
    878906                mesg = decode_utf7(mesg) 
    879                 # time = Time.parse(status.created_at) rescue Time.now 
    880907                #mesg = mesg.gsub(/&[gl]t;|\r\n|[\r\n\t\u00A0\u1680\u180E\u2002-\u200D\u202F\u205F\u2060\uFEFF]/) do 
    881908                mesg = mesg.gsub(/&[gl]t;|\r\n|[\r\n\t]/) do 
     
    909936 
    910937                        @timeline << id 
     938 
     939                        mention.user.status = mention 
     940                        tid  = @opts.tid ? @tmap.push(mention) : nil 
    911941                        user = mention.user 
    912                         mesg = generate_status_message(mention) 
    913                         tid  = @tmap.push(mention) 
    914  
    915                         mesg << " " << colored_tid(tid) if @opts.tid 
    916  
    917                         @log.debug [id, user.screen_name, mesg].inspect 
    918                         message(user, main_channel, mesg) 
    919  
    920                         @friends.any? do |friend| 
     942 
     943                        @log.debug [id, user.screen_name, mention.text].inspect 
     944                        message(mention, main_channel, tid) 
     945 
     946                        @friends.each_with_index do |friend, i| 
    921947                                if friend.id == user.id 
    922                                         friend.status = status 
    923                                 end 
    924                         end 
     948                                        @friends[i] = user 
     949                                        break 
     950                                end 
     951                        end if @friends 
    925952                end 
    926953        end 
     
    932959                        id   = @prev_dm_id = mesg.id 
    933960                        user = mesg.sender 
    934                         text = mesg.text 
     961                        tid  = nil 
     962                        text = generate_status_message(mesg.text) 
    935963                        @log.debug [id, user.screen_name, text].inspect 
    936                         message(user, @nick, text) 
     964                        message(user, @nick, tid, text) 
    937965                end 
    938966        end 
     
    940968        def check_friends 
    941969                if @friends.nil? 
    942                         @friends = page("statuses/friends/#{@me.screen_name}", @me.friends_count) 
     970                        @friends = page("statuses/friends/#{@me.id}", @me.friends_count) 
    943971                        if @opts.athack 
    944972                                join main_channel, @friends 
     
    959987                        end 
    960988                else 
    961                         new_ids    = page("friends/ids/#{@me.screen_name}", @me.friends_count) 
     989                        new_ids    = page("friends/ids/#{@me.id}", @me.friends_count) 
    962990                        friend_ids = @friends.reverse.map {|friend| friend.id } 
    963991 
    964992                        (friend_ids - new_ids).each do |id| 
    965                                 friend = @friends.delete_if {|i| i.id == id } 
    966                                 post generate_prefix(friend), PART, main_channel, "" 
     993                                @friends.delete_if do |friend| 
     994                                        if friend.id == id 
     995                                                post generate_prefix(friend), PART, main_channel, "" 
     996                                        end 
     997                                end 
    967998                        end 
    968999 
    9691000                        new_ids -= friend_ids 
    9701001                        unless new_ids.empty? 
    971                                 new_friends = page("statuses/friends/#{@me.screen_name}", new_ids.size, 
    972                                                    false).reject do |friend| 
     1002                                new_friends = page("statuses/friends/#{@me.id}", new_ids.size) 
     1003                                new_friends = new_friends.reject do |friend| 
    9731004                                        @friends.any? {|i| i.id == friend.id } 
    9741005                                end 
     1006                                join main_channel, new_friends.reverse 
    9751007                                @friends.concat new_friends 
    976                                 join main_channel, new_friends 
    9771008                        end 
    9781009                end 
     
    11631194                                raise APIFailed, res["error"] 
    11641195                        end 
    1165                         res.to_struct 
     1196                        res.to_tig_struct 
    11661197                when Net::HTTPNotModified # 304 
    11671198                        [] 
     
    11841215 
    11851216        def page(interface, max_count, authenticate = false) 
    1186                 @limit_remaining_for_ip ||= nil 
    1187                 limit = 0.9 * (@limit_remaining_for_ip || 2) 
     1217                @limit_remaining_for_ip ||= 56 
     1218                limit = 0.9 * @limit_remaining_for_ip 
    11881219                r     = [] 
     1220                cpp   = nil # counts per page 
    11891221                1.upto(limit) do |num| 
    11901222                        ret = api(interface, { :page => num }, { :authenticate => authenticate }) 
    1191                         count_per_page ||= ret.size 
     1223                        cpp ||= ret.size 
    11921224                        r.concat ret 
    1193                         if ret.size != count_per_page or 
    1194                            num >= max_count / count_per_page.to_f or 
    1195                            r.empty? 
    1196                                 break 
    1197                         end 
     1225                        break if ret.empty? or num >= max_count / cpp.to_f or 
     1226                                 ret.size != cpp or r.size >= max_count 
    11981227                end 
    11991228                r 
    12001229        end 
    12011230 
    1202         def message(sender, target, str) 
    1203                 #str.gsub!(/&#(x)?([0-9a-f]+);/i) do 
    1204                 #       [$1 ? $2.hex : $2.to_i].pack("U") 
    1205                 #end 
    1206                 screen_name = sender.screen_name 
    1207                 sender.screen_name = @nicknames[screen_name] || screen_name 
    1208                 prefix = generate_prefix(sender) 
     1231        def message(struct, target, tid =nil, str = nil) 
     1232                unless str 
     1233                        str = struct.is_a?(Status) ? struct.text : struct.status.text 
     1234                        str = "#{str} #{colored_tid(tid)}" if tid 
     1235                end 
     1236                user        = (struct.is_a?(User) ? struct : struct.user).dup 
     1237                screen_name = user.screen_name 
     1238                user.screen_name = @nicknames[screen_name] || screen_name 
     1239                prefix = generate_prefix(user) 
     1240                str    = generate_status_message(str) 
     1241 
    12091242                post prefix, PRIVMSG, target, str 
    12101243        end 
    12111244 
    12121245        def log(str) 
    1213                 str.gsub!(/\r\n|[\r\n]/, " ") 
    1214                 post server_name, NOTICE, main_channel, str 
     1246                post server_name, NOTICE, main_channel, str.gsub(/\r\n|[\r\n]/, " ") 
    12151247        end 
    12161248 
     
    14241456 
    14251457class Array 
    1426         def to_struct 
     1458        def to_tig_struct 
    14271459                map do |v| 
    1428                         v.respond_to?(:to_struct) ? v.to_struct : v 
     1460                        v.respond_to?(:to_tig_struct) ? v.to_tig_struct : v 
    14291461                end 
    14301462        end 
     
    14321464 
    14331465class Hash 
    1434         def to_struct 
     1466        def to_tig_struct 
    14351467                if empty? 
    14361468                        #warn "" if $VERBOSE 
     
    14401472 
    14411473                struct = case 
     1474                        #when keys.all? {|k| TwitterIrcGateway::User.members.include? k } # Ruby 1.9 
    14421475                        when keys.all? {|k| TwitterIrcGateway::User.members.map {|m| m.to_s }.include? k } 
    14431476                                TwitterIrcGateway::User.new 
     
    14501483                end 
    14511484                each do |k, v| 
    1452                         struct[k.to_sym] = v.respond_to?(:to_struct) ? v.to_struct : v 
     1485                        struct[k.to_sym] = v.respond_to?(:to_tig_struct) ? v.to_tig_struct : v 
    14531486                end 
    14541487                struct