| 1 | #!/usr/bin/env ruby |
|---|
| 2 | # -*- coding: utf-8 -*- |
|---|
| 3 | require "rubygems" |
|---|
| 4 | require "json" |
|---|
| 5 | require "open-uri" |
|---|
| 6 | require "twbot" |
|---|
| 7 | |
|---|
| 8 | require "twsearch" |
|---|
| 9 | require "twsearch-def" |
|---|
| 10 | require "tinyurl" |
|---|
| 11 | |
|---|
| 12 | require 'net/http' |
|---|
| 13 | Net::HTTP.version_1_2 |
|---|
| 14 | |
|---|
| 15 | MARKS = '['+Regexp.quote(' ():;<>[]{|}')+']|'+( |
|---|
| 16 | %w'〔 〕 《 》 ( ) [ ] { } 〈 〉 「 」 『 』 【 】 < > ≪ ≫ : ; |'.join('|')) |
|---|
| 17 | EXCLUDED_USER = %w{ |
|---|
| 18 | 47news 2NN googlenewsjp headline kagawa_news moviewalker ryukyushimpo |
|---|
| 19 | net_newsj gizmodojapan favoratory j_np bitexblog hrsmtwt |
|---|
| 20 | bombtter bombtter_raw tetsuwo_bot zerotter suzakutter meitantei_bot |
|---|
| 21 | muskabot drizzlebot zetsubot matsuokabot nyabomb now_ hatena_b |
|---|
| 22 | } |
|---|
| 23 | |
|---|
| 24 | def tweet2id(url) |
|---|
| 25 | if url =~ /^http:\/\/twitter\.com\/[0-9A-Z_a-z]+\/status(?:es)?\/(\d+)$/ |
|---|
| 26 | $1.to_i |
|---|
| 27 | else |
|---|
| 28 | nil |
|---|
| 29 | end |
|---|
| 30 | end |
|---|
| 31 | |
|---|
| 32 | class String |
|---|
| 33 | def strip_all |
|---|
| 34 | res = self.dup |
|---|
| 35 | res = $' if res =~ /\A(?:\s| )+/ |
|---|
| 36 | res = $` if res =~ /(?:\s| )+\z/ |
|---|
| 37 | res |
|---|
| 38 | end |
|---|
| 39 | end |
|---|
| 40 | |
|---|
| 41 | class SokuhoBot < TwBot |
|---|
| 42 | def load_data |
|---|
| 43 | result = [] |
|---|
| 44 | |
|---|
| 45 | @config['search'] ||= {} |
|---|
| 46 | tsu = TwitterSearch::Updater.new(TWS_engines, @config['search']) |
|---|
| 47 | data, conf, error = tsu.search('速報') |
|---|
| 48 | error.each_pair do |name, status| |
|---|
| 49 | @logmsg += "[Error in loading from search engine: #{name}]\n#{status}\n" |
|---|
| 50 | end |
|---|
| 51 | @config['search'] = conf |
|---|
| 52 | |
|---|
| 53 | # 古いデータの削除 |
|---|
| 54 | return [] if data.empty? |
|---|
| 55 | |
|---|
| 56 | data.each do |x| |
|---|
| 57 | # 先頭が「【速報】」のような形になっているか判定 |
|---|
| 58 | if x["text"] =~ /\A(?:#{MARKS})*速報(?:#{MARKS})/ |
|---|
| 59 | # 有効な速報postであるか判定 |
|---|
| 60 | value = $'.strip_all |
|---|
| 61 | |
|---|
| 62 | next if value =~ /\A(?:#{MARKS}| |\s)+\z/ |
|---|
| 63 | next if EXCLUDED_USER.include?(x['user']) |
|---|
| 64 | |
|---|
| 65 | # 発言URLをtinyurlで短縮 |
|---|
| 66 | # (Twitterが自動短縮しようとする場合のみ) |
|---|
| 67 | permalink = nil |
|---|
| 68 | begin |
|---|
| 69 | # Twitterが自動短縮しない場合はそのまま利用 |
|---|
| 70 | raise unless x['link'].index("_") |
|---|
| 71 | |
|---|
| 72 | # tinyurlで短縮 |
|---|
| 73 | tinyurl_key = TinyURL.convert(x['link']) |
|---|
| 74 | rescue Exception => e |
|---|
| 75 | # tinyurlが利用出来ないか、する必要がなかった場合 |
|---|
| 76 | permalink = x['link'] |
|---|
| 77 | else |
|---|
| 78 | # tinyurlを利用出来た場合 |
|---|
| 79 | permalink = "http://tinyurl.com/#{tinyurl_key}" |
|---|
| 80 | end |
|---|
| 81 | |
|---|
| 82 | # 発言を生成 |
|---|
| 83 | message = "[#{permalink} #{x['user']}より速報] #{value}" |
|---|
| 84 | message += " -b" if message.index("爆発しろ") |
|---|
| 85 | |
|---|
| 86 | # Reverse order so results are sorted by original order |
|---|
| 87 | result.unshift TwBot.remove_reply(message) |
|---|
| 88 | end |
|---|
| 89 | end |
|---|
| 90 | |
|---|
| 91 | @logmsg = "#{result.size} messages added." |
|---|
| 92 | result |
|---|
| 93 | end |
|---|
| 94 | end |
|---|
| 95 | |
|---|
| 96 | SELFDIR = File.dirname(__FILE__) |
|---|
| 97 | ARGV.each do |mode| |
|---|
| 98 | #SokuhoBot.new mode, "#{SELFDIR}/config.yml", "#{SELFDIR}/error.log", '', false, true |
|---|
| 99 | SokuhoBot.new mode, "#{SELFDIR}/config.yml", "#{SELFDIR}/error.log" |
|---|
| 100 | end |
|---|
| 101 | if ARGV.empty? |
|---|
| 102 | open "#{SELFDIR}/error.log", "w" do |file| |
|---|
| 103 | STDERR.puts "No mode specified!" |
|---|
| 104 | file.puts "No mode specified!" |
|---|
| 105 | end |
|---|
| 106 | end |
|---|
| 107 | |
|---|
| 108 | |
|---|
| 109 | |
|---|