mitten 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +25 -0
- data/LICENSE +21 -0
- data/README.rdoc +93 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/bin/daemon +8 -0
- data/bin/server +10 -0
- data/configs/example_environment.yaml +28 -0
- data/configs/time_call.yaml +14 -0
- data/example/sample.rb +13 -0
- data/lib/mitten.rb +133 -0
- data/lib/plugin.rb +37 -0
- data/lib/utils.rb +21 -0
- data/mitten.gemspec +84 -0
- data/plugins/amazon_search.rb +62 -0
- data/plugins/bmi.rb +48 -0
- data/plugins/codepad.rb +63 -0
- data/plugins/fortune.rb +40 -0
- data/plugins/gasoline.rb +46 -0
- data/plugins/gmail.rb +59 -0
- data/plugins/google_profile.rb +37 -0
- data/plugins/google_transit.rb +56 -0
- data/plugins/google_weather.rb +34 -0
- data/plugins/mixi_voice.rb +139 -0
- data/plugins/nanapi.rb +31 -0
- data/plugins/newspaper_headlines.rb +48 -0
- data/plugins/openpne_new_diary_check.rb +60 -0
- data/plugins/ramen.rb +33 -0
- data/plugins/rate.rb +31 -0
- data/plugins/screen_time_search.rb +96 -0
- data/plugins/sun_sign_astrology.rb +63 -0
- data/plugins/time_call.rb +25 -0
- data/plugins/tweet.rb +32 -0
- data/plugins/typhoon.rb +37 -0
- data/plugins/uri_shorten.rb +23 -0
- data/spec/mitten_spec.rb +11 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- metadata +105 -0
data/plugins/codepad.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class CodePad < Mitten::Plugin
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
|
8
|
+
@agent = Mechanize.new
|
9
|
+
proxy = ENV['https_proxy'] || ENV['http_proxy']
|
10
|
+
if proxy
|
11
|
+
proxy = URI.parse(proxy)
|
12
|
+
@agent.set_proxy(proxy.host, proxy.port)
|
13
|
+
end
|
14
|
+
@prefixes = ['C', 'Haskell', 'Lua', 'OCaml', 'PHP', 'Perl', 'Python', 'Ruby', 'Scheme']
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_privmsg(prefix, channel, message)
|
18
|
+
@language, @code = nil, nil
|
19
|
+
@prefixes.select do |item|
|
20
|
+
if message =~ Regexp.new("^#{item}:(.+)$")
|
21
|
+
@language = item
|
22
|
+
@code = $1.gsub('\\', '').strip
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
unless @language == nil
|
27
|
+
notice(channel, @language)
|
28
|
+
notice(channel, run_code)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def run_code
|
35
|
+
output = nil
|
36
|
+
|
37
|
+
begin
|
38
|
+
@agent.get('http://codepad.org/') do |run_page|
|
39
|
+
result = run_page.form_with(:action => '/') do |f|
|
40
|
+
f.radiobutton_with(:value => @language).check
|
41
|
+
f.code = code_prefix(@language) + @code
|
42
|
+
end.submit
|
43
|
+
doc = Nokogiri::HTML(result.body)
|
44
|
+
output = (doc/'pre').last.text
|
45
|
+
end
|
46
|
+
output
|
47
|
+
rescue Exception
|
48
|
+
'なんかだめー/(^o^)\'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def code_prefix(language)
|
53
|
+
prefix = ''
|
54
|
+
case language
|
55
|
+
when 'C'
|
56
|
+
prefix = "#include <stdio.h>\n"
|
57
|
+
when 'PHP'
|
58
|
+
prefix = "<?php \n"
|
59
|
+
else
|
60
|
+
prefix
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/plugins/fortune.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class Fortune < Mitten::Plugin
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
|
8
|
+
@sex = {
|
9
|
+
:male => 'http://legacy.fortune.yahoo.co.jp/fortune/bin/omikuji?sex=m',
|
10
|
+
:female => 'http://legacy.fortune.yahoo.co.jp/fortune/bin/omikuji?sex=f'
|
11
|
+
}
|
12
|
+
@prefix = @config['prefix'] || 'おみくじ'
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_privmsg(prefix, channel, message)
|
16
|
+
case message
|
17
|
+
when /^#{@prefix}/
|
18
|
+
notice(channel, read_fortune)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def read_fortune
|
25
|
+
html = Nokogiri::HTML(open(@sex.values.choice).read)
|
26
|
+
fortunes = {}
|
27
|
+
message = ''
|
28
|
+
|
29
|
+
(html/'table/tr/td').each do |content|
|
30
|
+
if content.inner_text =~ /^今日のあなたの(.+?)は(.+?)。/
|
31
|
+
fortunes[$1] = $2
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
fortunes.reverse_each do |genre, fortune|
|
36
|
+
message << "#{genre}:#{fortune} "
|
37
|
+
end
|
38
|
+
"今日のあなたは #{message}こんな感じだよ♪"
|
39
|
+
end
|
40
|
+
end
|
data/plugins/gasoline.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class Gasoline < Mitten::Plugin
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
|
8
|
+
@suffix = @config['suffix'] || 'ガソリンいくら'
|
9
|
+
@base_uri = 'http://gogo.gs'
|
10
|
+
@rank_uri = @base_uri + '/rank/result/?pref=47&ws=&p_mode=0&mm=0&service%5B3%5D=3&desd=0&x=24&y=17'
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_privmsg(prefix, channel, message)
|
14
|
+
case message
|
15
|
+
when /^#{@suffix}$/
|
16
|
+
gasoline_ranking.each do |gs|
|
17
|
+
notice(channel, gs)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def gasoline_ranking
|
25
|
+
ranking = []
|
26
|
+
|
27
|
+
begin
|
28
|
+
lists = Nokogiri::HTML(open(@rank_uri).read, nil, 'EUC-JP')/'.tableType02'/'tr'
|
29
|
+
lists[2..6].each do |line|
|
30
|
+
next unless line.at('td[@colspan="5"]').nil?
|
31
|
+
|
32
|
+
rank = line.at('.crownBig001').text
|
33
|
+
price = line.at('.priceLevelBig5').text
|
34
|
+
station = line.at('strong').text
|
35
|
+
address = line.at('small').text
|
36
|
+
detail = URI.short(@base_uri + line.at('strong/a').attributes['href'])
|
37
|
+
|
38
|
+
ranking << "#{rank}位 #{price}円 #{station} #{address} (#{detail})"
|
39
|
+
end
|
40
|
+
rescue Exception => e
|
41
|
+
ranking << 'こわれたっ/(^o^)\'
|
42
|
+
end
|
43
|
+
|
44
|
+
ranking
|
45
|
+
end
|
46
|
+
end
|
data/plugins/gmail.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
=begin
|
5
|
+
|
6
|
+
ex. environment.yaml
|
7
|
+
|
8
|
+
Gmail:
|
9
|
+
sleep: 60
|
10
|
+
channel: '#Mitten@freenode'
|
11
|
+
account: 'account'
|
12
|
+
password: 'password'
|
13
|
+
|
14
|
+
=end
|
15
|
+
class Gmail < Mitten::Plugin
|
16
|
+
def initialize(*args)
|
17
|
+
super
|
18
|
+
|
19
|
+
@account = @config['account']
|
20
|
+
@password = @config['password']
|
21
|
+
|
22
|
+
proxy = ENV['https_proxy'] || ENV['http_proxy']
|
23
|
+
if proxy
|
24
|
+
@https = Net::HTTP::Proxy(URI.parse(proxy).host, URI.parse(proxy).port).new('mail.google.com', 443)
|
25
|
+
else
|
26
|
+
@https = Net::HTTP.new('mail.google.com', 443)
|
27
|
+
end
|
28
|
+
@mail_cache = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def before_hook
|
32
|
+
login
|
33
|
+
end
|
34
|
+
|
35
|
+
def login
|
36
|
+
@https.use_ssl = true
|
37
|
+
@https.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
38
|
+
@request = Net::HTTP::Get.new('/mail/feed/atom')
|
39
|
+
@request.basic_auth(@account, @password)
|
40
|
+
end
|
41
|
+
|
42
|
+
def main
|
43
|
+
mail_list = Nokogiri::XML(@https.request(@request).body)
|
44
|
+
(mail_list/'entry').each do |entry|
|
45
|
+
id = entry.at('id').content
|
46
|
+
unless @mail_cache.key? id
|
47
|
+
@mail_cache[id] = true
|
48
|
+
title = entry.at('title').text
|
49
|
+
name = entry.at('name').text
|
50
|
+
link = entry.at('link')['href']
|
51
|
+
|
52
|
+
@channels.each do |channel|
|
53
|
+
notice(channel, "Gmail: (#{name}) #{title} #{URI.short(link)}")
|
54
|
+
sleep 5
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
class GoogleProfile < Mitten::Plugin
|
4
|
+
def initialize(*args)
|
5
|
+
super
|
6
|
+
|
7
|
+
@suffix = @config['suffix'] || 'のプロフィールが知りたい'
|
8
|
+
@limit = @config['limit'] || 3
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_privmsg(prefix, channel, message)
|
12
|
+
case message
|
13
|
+
when /^(.+?)#{@suffix}/
|
14
|
+
get_profile($1).each { |profile| notice(channel, profile) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def get_profile(target)
|
21
|
+
profiles = []
|
22
|
+
uri = URI.escape("http://www.google.com/profiles?q=#{target}")
|
23
|
+
result = Nokogiri::HTML(Kconv.toutf8(open(uri).read))/'div.profile-result'
|
24
|
+
|
25
|
+
unless result.count == 0
|
26
|
+
result[0...@limit].each do |profile|
|
27
|
+
detail = profile.at('div.profile-result-text-block').text
|
28
|
+
uri = URI.short("http://www.google.com#{profile.at('a')['href']}")
|
29
|
+
|
30
|
+
profiles << "#{detail} (#{uri})"
|
31
|
+
end
|
32
|
+
else
|
33
|
+
profiles << 'そんな人いにゃい o(>_<)o'
|
34
|
+
end
|
35
|
+
profiles
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class GoogleTransit < Mitten::Plugin
|
5
|
+
def on_privmsg(prefix, channel, message)
|
6
|
+
case message
|
7
|
+
when /^(.+)から(.+)(へ|まで|に)行.+/
|
8
|
+
search_route($1, $2).each { |route| notice(channel, route) }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def search_route(search_from, search_to)
|
15
|
+
from = URI.escape(search_from.toutf8)
|
16
|
+
to = URI.escape(search_to.toutf8)
|
17
|
+
query = "http://maps.google.co.jp/maps?f=q&source=s_q&hl=ja&geocode=&q=from%3A+#{from}+to%3A+#{to}"
|
18
|
+
|
19
|
+
begin
|
20
|
+
html = Nokogiri::HTML(open(query).read)
|
21
|
+
route = html/'#transit_route_0'
|
22
|
+
|
23
|
+
unless route.empty?
|
24
|
+
start_place = (html/'#ddw_addr_area_0/#sxaddr/div.sa').text.toutf8
|
25
|
+
end_place = (html/'#ddw_addr_area_1/#sxaddr/div.sa').text.toutf8
|
26
|
+
time = (html/'#transit_route_0').search('span.ts_jtime').text.toutf8
|
27
|
+
cost = (html/'#transit_route_0').search('span.ts_routecost').text.toutf8
|
28
|
+
|
29
|
+
messages = ["#{start_place} から #{end_place} へ行くにはね,"]
|
30
|
+
messages << "だいたい #{time} で #{cost} ぐらいかかるみたい!"
|
31
|
+
|
32
|
+
(route/'table.ts_step').each_with_index do |step, counter|
|
33
|
+
counter += 1
|
34
|
+
longline = (step/'span.longline').text.toutf8
|
35
|
+
action = (step/'span.action').text.toutf8
|
36
|
+
|
37
|
+
unless longline.empty?
|
38
|
+
locations = step/'span.location'
|
39
|
+
|
40
|
+
messages << "#{counter} : #{action} で「#{longline}」に乗る"
|
41
|
+
messages << " [発] #{locations[0].text.toutf8}"
|
42
|
+
messages << " [着] #{locations[1].text.toutf8}"
|
43
|
+
else
|
44
|
+
location = (step/'span.location').text.toutf8
|
45
|
+
messages << "#{counter} : #{location} #{action}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
messages << "詳しくはここ見てね♪ (#{URI.short(query)})"
|
49
|
+
else
|
50
|
+
'/(^o^)\ 迷子!'
|
51
|
+
end
|
52
|
+
rescue Exception
|
53
|
+
'/(^o^)\ 迷子!'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
class GoogleWeather < Mitten::Plugin
|
4
|
+
def initialize(*args)
|
5
|
+
super
|
6
|
+
|
7
|
+
@suffix = @config['suffix'] || 'の天気教えて'
|
8
|
+
@indexes = {'今日の' => 0, '明日の' => 1, '明後日の' => 2, '明々後日の' => 3}
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_privmsg(prefix, channel, message)
|
12
|
+
case message
|
13
|
+
when /^(.+?の|)(.+?)#{@suffix}/
|
14
|
+
option = '今日の'
|
15
|
+
option = $1 unless $1 == ''
|
16
|
+
keyword = $2
|
17
|
+
|
18
|
+
notice(channel, get_weather(keyword, option))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def get_weather(keyword, option)
|
25
|
+
uri = URI.escape("http://www.google.co.jp/search?q=#{keyword}+週間天気")
|
26
|
+
html = Nokogiri::HTML(Kconv.toutf8(open(uri).read))
|
27
|
+
|
28
|
+
city = (html/'h3.r/b').first.text
|
29
|
+
weather = ((html/'div[@align="center"]')/'img')[@indexes[option]]['title']
|
30
|
+
temperature = ((html/'div[@align="center"]')/'nobr')[@indexes[option]].text
|
31
|
+
|
32
|
+
"#{option}#{city}の天気は #{weather} だよっ [#{temperature}] (#{URI.short(uri)})"
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'mechanize'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
=begin
|
6
|
+
|
7
|
+
ex. environment.yaml
|
8
|
+
|
9
|
+
MixiVoice:
|
10
|
+
sleep: 60
|
11
|
+
channel: '#Mitten@freenode'
|
12
|
+
email: 'email'
|
13
|
+
password: 'password'
|
14
|
+
|
15
|
+
=end
|
16
|
+
class MixiVoice < Mitten::Plugin
|
17
|
+
MIXI_LOGIN_URI = 'http://mixi.jp'
|
18
|
+
RECENT_VOICE_URI = MIXI_LOGIN_URI + '/recent_echo.pl'
|
19
|
+
|
20
|
+
def initialize(*args)
|
21
|
+
super
|
22
|
+
|
23
|
+
@email = @config['email']
|
24
|
+
@password = @config['password']
|
25
|
+
@nickname = @config['nickname']
|
26
|
+
|
27
|
+
@agent = Mechanize.new
|
28
|
+
if ENV['http_proxy']
|
29
|
+
proxy = URI.parse(ENV['http_proxy'])
|
30
|
+
@agent.set_proxy(proxy.host, proxy.port)
|
31
|
+
end
|
32
|
+
|
33
|
+
@caches = []
|
34
|
+
end
|
35
|
+
|
36
|
+
def before_hook
|
37
|
+
login
|
38
|
+
@identity = get_identity
|
39
|
+
end
|
40
|
+
|
41
|
+
def login
|
42
|
+
@agent.get MIXI_LOGIN_URI do |login_page|
|
43
|
+
login_page.form 'login_form' do |form|
|
44
|
+
form.email = @email
|
45
|
+
form.password = @password
|
46
|
+
end.submit
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def on_privmsg(prefix, channel, message)
|
51
|
+
if prefix =~ Regexp.new(@nickname)
|
52
|
+
case message
|
53
|
+
when /^re ([0-9]+) (.+)/
|
54
|
+
reply(channel, $1, $2)
|
55
|
+
when /^rm ([0-9]+)/
|
56
|
+
delete($1)
|
57
|
+
when /^add (.+)/
|
58
|
+
add($1)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def main
|
64
|
+
get
|
65
|
+
end
|
66
|
+
|
67
|
+
def get
|
68
|
+
voices = crawl_recent_voice
|
69
|
+
voices.sort.each do |key, voice|
|
70
|
+
if @caches.empty? or !@caches.has_key? key
|
71
|
+
@channels.each do |channel|
|
72
|
+
notice(channel, "mixi voice: [#{voice[:nickname]}]#{voice[:reply]} #{voice[:comment]} (#{key})")
|
73
|
+
sleep 5
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
@caches = voices
|
78
|
+
end
|
79
|
+
|
80
|
+
def get_identity
|
81
|
+
recent_page = @agent.get RECENT_VOICE_URI
|
82
|
+
identity = (Nokogiri::HTML(recent_page.body)/'input#post_key').first['value']
|
83
|
+
end
|
84
|
+
|
85
|
+
def reply(channel, key, voice)
|
86
|
+
if @caches.has_key? key
|
87
|
+
member_id = @caches[key][:member_id]
|
88
|
+
post_time = @caches[key][:post_time]
|
89
|
+
|
90
|
+
@agent.get RECENT_VOICE_URI do |post_page|
|
91
|
+
post_page.form_with(:action => '/add_echo.pl') do |form|
|
92
|
+
form.body = voice
|
93
|
+
form.parent_member_id = member_id
|
94
|
+
form.parent_post_time = post_time
|
95
|
+
end.submit
|
96
|
+
end
|
97
|
+
else
|
98
|
+
notice(channel, '指定された返信先が見つかりません')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def delete(post_time)
|
103
|
+
@agent.post "http://mixi.jp/delete_echo.pl?post_time=#{post_time}&post_key=#{@identity}&redirect=recent_echo"
|
104
|
+
@caches = crawl_recent_voice
|
105
|
+
end
|
106
|
+
|
107
|
+
def add(voice)
|
108
|
+
@agent.get RECENT_VOICE_URI do |post_page|
|
109
|
+
post_page.form_with(:action => 'add_echo.pl') do |form|
|
110
|
+
form.body = voice
|
111
|
+
end.submit
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def crawl_recent_voice
|
116
|
+
recent_page = @agent.get RECENT_VOICE_URI
|
117
|
+
voices = {}
|
118
|
+
|
119
|
+
(Nokogiri::HTML(recent_page.body)/'td.comment').each do |comment|
|
120
|
+
key = timestamp(comment)
|
121
|
+
voices[key] = build_voice(comment)
|
122
|
+
end
|
123
|
+
voices
|
124
|
+
end
|
125
|
+
|
126
|
+
def timestamp(comment)
|
127
|
+
comment.at('div.echo_post_time').text
|
128
|
+
end
|
129
|
+
|
130
|
+
def build_voice(comment)
|
131
|
+
{
|
132
|
+
:member_id => comment.at('div.echo_member_id').text,
|
133
|
+
:post_time => comment.at('div.echo_post_time').text,
|
134
|
+
:nickname => comment.at('div.echo_nickname').text,
|
135
|
+
:reply => ((' ' + comment.at('a').text) if comment.at('a').text =~ /^>/),
|
136
|
+
:comment => comment.at('div.echo_body').text
|
137
|
+
}
|
138
|
+
end
|
139
|
+
end
|
data/plugins/nanapi.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class Nanapi < Mitten::Plugin
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
@suffix = @config['suffix'] || 'テクニック教えて'
|
8
|
+
end
|
9
|
+
|
10
|
+
def on_privmsg(prefix, channel, message)
|
11
|
+
case message
|
12
|
+
when /^(.+)#{@suffix}$/
|
13
|
+
result = search_technique($1)
|
14
|
+
|
15
|
+
if result == nil
|
16
|
+
notice(channel, '/(^o^)\ わかにゃいっ')
|
17
|
+
else
|
18
|
+
notice(channel, result.to_s)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def search_technique(keyword)
|
26
|
+
doc = Nokogiri::XML(open("http://nanapi.jp/search/keyword:#{URI.encode(keyword)}/feed.rss").read)
|
27
|
+
item = (doc/'item').to_a.choice
|
28
|
+
|
29
|
+
"#{item.at('title').text} - #{URI.short(item.at('link').text)}" if item
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'rss'
|
3
|
+
|
4
|
+
class NewspaperHeadlines < Mitten::Plugin
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
|
8
|
+
@publishers = {
|
9
|
+
'琉球新報' => 'http://rss.ryukyushimpo.jp/rss/ryukyushimpo/index.rdf',
|
10
|
+
'沖縄タイムス' => 'http://www.okinawatimes.co.jp/rss/20/index.xml',
|
11
|
+
'読売新聞' => 'http://rss.yomiuri.co.jp/rss/yol/topstories',
|
12
|
+
'毎日新聞' => 'http://mainichi.jp/rss/etc/flash.rss',
|
13
|
+
'日経新聞' => 'http://www.nikkeibp.co.jp/rss/index.rdf',
|
14
|
+
'CNN' => 'http://headlines.yahoo.co.jp/rss/cnn_c_int.xml',
|
15
|
+
'映画ニュース' => 'http://headlines.yahoo.co.jp/rss/cine.xml',
|
16
|
+
'ITMedia' => 'http://headlines.yahoo.co.jp/rss/itmedia_n.xml',
|
17
|
+
'dankogai' => 'http://blog.livedoor.jp/dankogai/index.rdf',
|
18
|
+
'インフルエンザ' => 'http://www3.asahi.com/rss/pandemicflu.rdf'
|
19
|
+
}
|
20
|
+
@limit = @config['limit'] || 3
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_privmsg(prefix, channel, publisher_name)
|
24
|
+
if publisher_name == 'ニュースリスト'
|
25
|
+
notice(channel, @publishers.keys.join(' / '))
|
26
|
+
elsif @publishers.key? publisher_name
|
27
|
+
get_headlines(@publishers[publisher_name]).each do |headline|
|
28
|
+
notice(channel, headline.to_s)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def get_headlines(publisher_uri)
|
36
|
+
rss = RSS::Parser.parse(open(publisher_uri).read, false)
|
37
|
+
rss.items.delete_if { |item| item.title =~ /(AD|PR)/ }
|
38
|
+
|
39
|
+
headlines = [rss.channel.title + ' のニュースだよ!']
|
40
|
+
rss.items[0...@limit].each do |item|
|
41
|
+
title = item.title
|
42
|
+
url = URI.short(item.link)
|
43
|
+
date = item.date.strftime("%d日 %H:%M")
|
44
|
+
headlines << "[#{date}] #{title} (#{url})"
|
45
|
+
end
|
46
|
+
headlines
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
=begin
|
5
|
+
|
6
|
+
ex. environment.yaml
|
7
|
+
|
8
|
+
OpenPNENewDiaryCheck:
|
9
|
+
sleep: 60
|
10
|
+
channel: '#Mitten@freenode'
|
11
|
+
uri : 'http://openpne.example.com'
|
12
|
+
username: 'username'
|
13
|
+
password: 'password'
|
14
|
+
|
15
|
+
=end
|
16
|
+
class OpenPNENewDiaryCheck < Mitten::Plugin
|
17
|
+
def initialize(*args)
|
18
|
+
super
|
19
|
+
|
20
|
+
@uri = @config['uri']
|
21
|
+
@username = @config['username']
|
22
|
+
@password = @config['password']
|
23
|
+
@diaries = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def before_hook
|
27
|
+
login
|
28
|
+
end
|
29
|
+
|
30
|
+
def login
|
31
|
+
@agent = Mechanize.new
|
32
|
+
@agent.get(@uri) do |login_page|
|
33
|
+
login_page.form_with(:name => 'login') do |f|
|
34
|
+
f.username = @username
|
35
|
+
f.password = @password
|
36
|
+
end.submit
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def main
|
41
|
+
diary_page = @agent.get "#{@uri}/?m=pc&a=page_h_diary_list_all"
|
42
|
+
diaries = Nokogiri::HTML(diary_page.body)/'div.item'
|
43
|
+
|
44
|
+
diaries[1...diaries.size].each do |diary|
|
45
|
+
uri = "#{@uri}/#{(diary/'td.photo/a').first.attributes['href']}"
|
46
|
+
redo if uri == nil or uri == ''
|
47
|
+
|
48
|
+
unless @diaries.has_key? uri
|
49
|
+
@diaries[uri] = true
|
50
|
+
nick = ((diary/'td').to_a)[1].text.gsub(/ \(.*\)$/, '')
|
51
|
+
title = ((diary/'td').to_a)[2].text.gsub(/ \([0-9].?\)/, '')
|
52
|
+
message = "#{nick}さんが「#{title}」を投稿しました! (#{uri})"
|
53
|
+
|
54
|
+
@channels.each do |channel|
|
55
|
+
notice(channel, message) if @diaries.size > 20
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/plugins/ramen.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class Ramen < Mitten::Plugin
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
|
8
|
+
@suffix = @config['suffix'] || 'ラーメン食わせろ'
|
9
|
+
@base_uri = 'http://ramen.tedaco.net/'
|
10
|
+
@rank_uri = @base_uri + 'index.php'
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_privmsg(prefix, channel, message)
|
14
|
+
case message
|
15
|
+
when /^#{@suffix}/
|
16
|
+
notice(channel, shop_choice)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def shop_choice
|
21
|
+
begin
|
22
|
+
list = Nokogiri::HTML(open(@rank_uri).read)/'.access_rank'
|
23
|
+
|
24
|
+
shop = list.to_a.choice
|
25
|
+
name = shop.at('a').text
|
26
|
+
detail = URI.short(@base_uri + shop.at('a').attributes['href'])
|
27
|
+
|
28
|
+
"#{name} に行けば? (#{detail})"
|
29
|
+
rescue Exception =>e
|
30
|
+
ranking << 'こわれたっ/(^o^)\'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/plugins/rate.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class Rate < Mitten::Plugin
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
@suffix = @config['suffix'] || '度判定して'
|
8
|
+
end
|
9
|
+
|
10
|
+
def on_privmsg(prefix, channel, message)
|
11
|
+
case message
|
12
|
+
when /^(.+)#{@suffix}$/
|
13
|
+
result = rating($1, prefix.nick)
|
14
|
+
|
15
|
+
if result == nil
|
16
|
+
notice(channel, '/(^o^)\ わかにゃいっ')
|
17
|
+
else
|
18
|
+
notice(channel, result.to_s)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def rating(genre, nick)
|
26
|
+
uri = "http://kistools.appspot.com/r/#{URI.encode(genre)}/#{nick}"
|
27
|
+
doc = Nokogiri::XML(open(uri).read)
|
28
|
+
|
29
|
+
(doc/'table.input_form').first.at('td').text.match(/^(.+)?です。/).to_s.strip + " (#{URI.short(uri)})"
|
30
|
+
end
|
31
|
+
end
|