nadoka 0.8.6 → 0.9.0
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/nadoka.gemspec +0 -2
- data/nadoka.rb +12 -0
- data/ndk/config.rb +3 -2
- data/ndk/version.rb +1 -1
- data/plugins/crubybot.nb +93 -0
- data/plugins/googlebot.nb +40 -2
- data/plugins/opensearchbot.nb +8 -8
- data/plugins/titlebot.nb +19 -19
- data/rice/irc.rb +1 -0
- metadata +4 -4
- data/plugins/translatebot.nb +0 -301
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4e8bf1dc42176c81751ad4d20bd178cda8b2ee5
|
4
|
+
data.tar.gz: be2444c5552d37730987a6ddae9b12a1c5b1acf3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 549e67f5bc2f14276fb5fc53fe92e06bcc9ed567230bd17fcbe0bff71633941e427d9529a4140d70f3bd0626d6578de98ebf441c660ebbe0317391732cb39007
|
7
|
+
data.tar.gz: 163d7ef0eb1462044f393da222d377d86fbfe4831ab834796dd2f07cbffb15a0e6dab8699b7adfae8efdfb47044f1321ba1fc6e58cf5df963669e6165c16af61
|
data/README.md
CHANGED
@@ -5,6 +5,7 @@ Written by SASADA Koichi <ko1 at atdot.net>
|
|
5
5
|
[](http://badge.fury.io/rb/nadoka)
|
6
6
|
[](https://travis-ci.org/nadoka/nadoka)
|
7
7
|
[](https://codeclimate.com/github/nadoka/nadoka)
|
8
|
+
[](https://bitdeli.com/free "Bitdeli Badge")
|
8
9
|
|
9
10
|
## What's this?
|
10
11
|
|
@@ -22,5 +23,4 @@ You can do with this software:
|
|
22
23
|
See Web pages:
|
23
24
|
|
24
25
|
- https://github.com/nadoka/nadoka
|
25
|
-
- http://rubyforge.org/projects/nadoka/
|
26
26
|
- http://www.atdot.net/nadoka/
|
data/nadoka.gemspec
CHANGED
@@ -16,8 +16,6 @@ Gem::Specification.new do |s|
|
|
16
16
|
older proxy written in Perl.
|
17
17
|
}.tr_s(" \n", " ").strip
|
18
18
|
|
19
|
-
s.rubyforge_project = "nadoka"
|
20
|
-
|
21
19
|
s.files = `git ls-files`.split("\n")
|
22
20
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
21
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
data/nadoka.rb
CHANGED
@@ -45,6 +45,7 @@ unless defined? Process.daemon
|
|
45
45
|
end
|
46
46
|
|
47
47
|
rcfile = nil
|
48
|
+
pidfile = nil
|
48
49
|
daemon = false
|
49
50
|
optparse = OptionParser.new{|opts|
|
50
51
|
opts.banner = "Usage: ruby #{$0} [options]"
|
@@ -70,6 +71,9 @@ optparse = OptionParser.new{|opts|
|
|
70
71
|
opts.on("--daemon", "run as daemon"){
|
71
72
|
daemon = true
|
72
73
|
}
|
74
|
+
opts.on("--pid [PIDFILE]", "Put process pid into PIDFILE"){|f|
|
75
|
+
pidfile = f
|
76
|
+
}
|
73
77
|
|
74
78
|
opts.separator ""
|
75
79
|
opts.separator "Common options:"
|
@@ -95,6 +99,10 @@ if daemon
|
|
95
99
|
Process.daemon
|
96
100
|
end
|
97
101
|
|
102
|
+
if pidfile
|
103
|
+
open(pidfile, "w") {|f| f.puts Process.pid }
|
104
|
+
end
|
105
|
+
|
98
106
|
begin
|
99
107
|
GC.start
|
100
108
|
Nadoka::NDK_Server.new(rcfile).start
|
@@ -111,5 +119,9 @@ rescue Exception => e
|
|
111
119
|
}
|
112
120
|
end
|
113
121
|
|
122
|
+
if pidfile
|
123
|
+
File.unlink(pidfile)
|
124
|
+
end
|
125
|
+
|
114
126
|
end
|
115
127
|
|
data/ndk/config.rb
CHANGED
@@ -506,9 +506,10 @@ module Nadoka
|
|
506
506
|
else
|
507
507
|
if m = msgobj[$1.intern]
|
508
508
|
if m.respond_to?(:force_encoding)
|
509
|
-
m.force_encoding(Encoding::ASCII_8BIT)
|
509
|
+
m.dup.force_encoding(Encoding::ASCII_8BIT)
|
510
|
+
else
|
511
|
+
m
|
510
512
|
end
|
511
|
-
m
|
512
513
|
else
|
513
514
|
"!!unknown attribute: #{$1}!!"
|
514
515
|
end
|
data/ndk/version.rb
CHANGED
data/plugins/crubybot.nb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# -*-ruby-*-
|
2
|
+
require 'ffi/clang'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
# dependency:
|
6
|
+
# * ffi-clang.gem
|
7
|
+
# * libclang
|
8
|
+
# * lang/clang34 in FreeBSD ports
|
9
|
+
# * llvm of homebrew
|
10
|
+
#
|
11
|
+
# example setting:
|
12
|
+
# {
|
13
|
+
# :name => :CRubyBot,
|
14
|
+
# :channels => [ "#ruby-ja" ],
|
15
|
+
# :ruby_srcdir => '/path/of/ruby/src',
|
16
|
+
# }
|
17
|
+
#
|
18
|
+
class CRubyBot < Nadoka::NDK_Bot
|
19
|
+
def bot_initialize
|
20
|
+
if @bot_config.key?(:channels)
|
21
|
+
channels = '\A(?:' + @bot_config[:channels].collect{|ch|
|
22
|
+
Regexp.quote(ch)
|
23
|
+
}.join('|') + ')\z'
|
24
|
+
@available_channel = Regexp.compile(channels)
|
25
|
+
else
|
26
|
+
@available_channel = @bot_config.fetch(:ch, //)
|
27
|
+
end
|
28
|
+
unless @ruby_srcdir = @bot_config[:ruby_srcdir]
|
29
|
+
raise "ruby_srcdir is not specified"
|
30
|
+
end
|
31
|
+
unless Dir.exist?(@ruby_srcdir)
|
32
|
+
raise "ruby_srcdir(#{@ruby_srcdir}) does not exist"
|
33
|
+
end
|
34
|
+
@ruby_srcdir << '/' if @ruby_srcdir[-1] != '/'
|
35
|
+
@translation_unit = nil
|
36
|
+
@translation_unit_rev = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def bot_state
|
40
|
+
"<#{self.class.to_s}>"
|
41
|
+
end
|
42
|
+
|
43
|
+
def translation_unit
|
44
|
+
rev = IO.read("#@ruby_srcdir/revision.h").to_s[/\d+/].to_i
|
45
|
+
return @translation_unit if @translation_unit_rev == rev
|
46
|
+
ary = Dir[File.join @ruby_srcdir, "*.c"]
|
47
|
+
f = Tempfile.open(["crubybot-ruby", ".c"])
|
48
|
+
ary = Dir[File.join @ruby_srcdir, "*.c"]
|
49
|
+
ary << File.join(@ruby_srcdir, "win32/win32.c")
|
50
|
+
ary.each do |fn|
|
51
|
+
f.puts %[#include "#{fn}"]
|
52
|
+
end
|
53
|
+
f.flush
|
54
|
+
index = FFI::Clang::Index.new
|
55
|
+
@translation_unit = index.parse_translation_unit(f.path, "-I#{@ruby_srcdir}/include")
|
56
|
+
@translation_unit_rev = rev
|
57
|
+
f.close(true)
|
58
|
+
@translation_unit
|
59
|
+
end
|
60
|
+
|
61
|
+
def find_def(name, kind)
|
62
|
+
translation_unit.cursor.visit_children do |cursor, parent|
|
63
|
+
if cursor.kind == kind && cursor.definition? && cursor.spelling == name
|
64
|
+
loc = cursor.location
|
65
|
+
path = loc.file
|
66
|
+
if path.start_with?(@ruby_srcdir)
|
67
|
+
return [path[@ruby_srcdir.size..-1], loc.line]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
next :recurse
|
71
|
+
end
|
72
|
+
return nil
|
73
|
+
end
|
74
|
+
|
75
|
+
def on_privmsg(client, ch, message)
|
76
|
+
return unless @available_channel === ch
|
77
|
+
case message
|
78
|
+
when /\A\S*(struct|fun\w*)\s+(\w+)/
|
79
|
+
kind1 = $1
|
80
|
+
name = $2
|
81
|
+
kind = case kind1
|
82
|
+
when "struct"
|
83
|
+
:cursor_struct
|
84
|
+
when /\Afun/
|
85
|
+
:cursor_function
|
86
|
+
end
|
87
|
+
path, line = find_def(name, kind)
|
88
|
+
return unless path
|
89
|
+
send_notice(ch, "crubybot: #{kind1} #{name} at " \
|
90
|
+
"https://github.com/ruby/ruby/blob/trunk/#{path}#L#{line}")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/plugins/googlebot.nb
CHANGED
@@ -68,6 +68,23 @@ rescue LoadError
|
|
68
68
|
require 'json'
|
69
69
|
end
|
70
70
|
|
71
|
+
if __FILE__ == $0
|
72
|
+
# for test
|
73
|
+
module Nadoka
|
74
|
+
class NDK_Bot
|
75
|
+
def bot_init_utils
|
76
|
+
end
|
77
|
+
def initialize
|
78
|
+
@bot_config = Hash.new
|
79
|
+
@bot_config[:headers] = {
|
80
|
+
"User-Agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:27.0) Gecko/20100101 Firefox/27.0",
|
81
|
+
}
|
82
|
+
bot_initialize
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
71
88
|
class GoogleBot < Nadoka::NDK_Bot
|
72
89
|
def bot_initialize
|
73
90
|
bot_init_utils
|
@@ -174,10 +191,11 @@ class GoogleBot < Nadoka::NDK_Bot
|
|
174
191
|
|
175
192
|
def google_calc exp
|
176
193
|
@logger.slog("google_calc<#{exp.dump}")
|
177
|
-
uri = "
|
194
|
+
uri = "https://www.google.co.jp/search?ie=UTF8&oe=UTF-8&q=#{CGI.escape(exp)}"
|
178
195
|
html = open(uri, @headers) do |f|
|
179
196
|
f.read
|
180
197
|
end
|
198
|
+
open("g.html", "wb") { |f| f.write html } if $DEBUG
|
181
199
|
if /class=r [^<>]+><b>(.+?)<\/b>/u =~ html
|
182
200
|
result = $1
|
183
201
|
# @logger.slog("google_calc>#{result.dump}")
|
@@ -194,7 +212,7 @@ class GoogleBot < Nadoka::NDK_Bot
|
|
194
212
|
result.gsub!(/ /u, " ")
|
195
213
|
result.gsub!(/\s+/, " ")
|
196
214
|
return result
|
197
|
-
elsif /<div class="leg_calc
|
215
|
+
elsif /<div class="leg_calc[^<>]*>(?:<div[^<>]*>)+([^<>]+)<\/div><div[^<>]*>([^<>]+)</u =~ html
|
198
216
|
result = "#{$1} #{$2}"
|
199
217
|
#@logger.slog("google_calc>#{result.dump}")
|
200
218
|
return result
|
@@ -376,3 +394,23 @@ class GoogleBot < Nadoka::NDK_Bot
|
|
376
394
|
end
|
377
395
|
end
|
378
396
|
end
|
397
|
+
|
398
|
+
if __FILE__ == $0
|
399
|
+
if ARGV.empty?
|
400
|
+
puts "ad hoc test usage:"
|
401
|
+
puts " ruby -vd plugins/googlebot.nb 'gc>1+1'"
|
402
|
+
puts " ruby -vd plugins/googlebot.nb 'gc>1ドルを円で'"
|
403
|
+
end
|
404
|
+
require 'logger'
|
405
|
+
google_bot = GoogleBot.new
|
406
|
+
google_bot.instance_eval do
|
407
|
+
@logger = Object.new
|
408
|
+
def @logger.slog(log)
|
409
|
+
STDERR.puts "slog>#{log}"
|
410
|
+
end
|
411
|
+
end
|
412
|
+
ARGV.each do |arg|
|
413
|
+
puts arg
|
414
|
+
puts google_bot.dispatch_command(arg)
|
415
|
+
end
|
416
|
+
end
|
data/plugins/opensearchbot.nb
CHANGED
@@ -25,7 +25,7 @@
|
|
25
25
|
:name => :OpenSearchBot,
|
26
26
|
:bot_name => 'bing',
|
27
27
|
:ch => //,
|
28
|
-
:referer => '
|
28
|
+
:referer => 'https://github.com/nadoka/nadoka',
|
29
29
|
:ch_kcode => :jis,
|
30
30
|
:html => 'http://www.bing.com/search?q={searchTerms}',
|
31
31
|
:rss => 'http://api.search.live.com/rss.aspx?source=web&query={searchTerms}'
|
@@ -37,7 +37,7 @@
|
|
37
37
|
:bot_name => 'googlecode',
|
38
38
|
:ch => //,
|
39
39
|
:ch_kcode => :jis,
|
40
|
-
:referer => '
|
40
|
+
:referer => 'https://github.com/nadoka/nadoka',
|
41
41
|
# Google Code Search Data API (Deprecated)
|
42
42
|
# http://code.google.com/intl/ja/apis/codesearch/docs/2.0/developers_guide.h
|
43
43
|
tml
|
@@ -49,7 +49,7 @@ tml
|
|
49
49
|
:name => :OpenSearchBot,
|
50
50
|
:bot_name => 'koders',
|
51
51
|
:ch => //,
|
52
|
-
:referer => '
|
52
|
+
:referer => 'https://github.com/nadoka/nadoka',
|
53
53
|
:ch_kcode => :jis,
|
54
54
|
# http://www.koders.com/search/KodersDescriptionOS1_1.xml
|
55
55
|
:html => 'http://www.koders.com/?s={searchTerms}',
|
@@ -67,7 +67,7 @@ class OpenSearch
|
|
67
67
|
def initialize(options)
|
68
68
|
@html = options[:html]
|
69
69
|
@rss = options[:rss]
|
70
|
-
@referer = options[:referer] || '
|
70
|
+
@referer = options[:referer] || 'https://github.com/nadoka/nadoka'
|
71
71
|
end
|
72
72
|
|
73
73
|
def result(key)
|
@@ -89,25 +89,25 @@ end
|
|
89
89
|
if __FILE__ == $0
|
90
90
|
h = {
|
91
91
|
'bing' => {
|
92
|
-
:referer => '
|
92
|
+
:referer => 'https://github.com/nadoka/nadoka',
|
93
93
|
:html => 'http://www.bing.com/search?q={searchTerms}',
|
94
94
|
:rss => 'http://api.search.live.com/rss.aspx?source=web&query={searchTerms}',
|
95
95
|
},
|
96
96
|
'googlecode' => {
|
97
|
-
:referer => '
|
97
|
+
:referer => 'https://github.com/nadoka/nadoka',
|
98
98
|
# Google Code Search Data API (Deprecated)
|
99
99
|
# http://code.google.com/intl/ja/apis/codesearch/docs/2.0/developers_guide.html
|
100
100
|
:html => 'http://www.google.com/codesearch?q={searchTerms}',
|
101
101
|
:rss => 'http://www.google.com/codesearch/feeds/search?q={searchTerms}',
|
102
102
|
},
|
103
103
|
'koders' => {
|
104
|
-
:referer => '
|
104
|
+
:referer => 'https://github.com/nadoka/nadoka',
|
105
105
|
# http://www.koders.com/search/KodersDescriptionOS1_1.xml
|
106
106
|
:html => 'http://www.koders.com/?s={searchTerms}',
|
107
107
|
:rss => 'http://www.koders.com/?s={searchTerms}&results=code&output=rss&OSversion=1.1',
|
108
108
|
},
|
109
109
|
'youtube' => {
|
110
|
-
:referer => '
|
110
|
+
:referer => 'https://github.com/nadoka/nadoka',
|
111
111
|
:html => 'http://www.youtube.com/results?search_query={searchTerms}',
|
112
112
|
:rss => 'http://gdata.youtube.com/feeds/api/videos?q={searchTerms}',
|
113
113
|
},
|
data/plugins/titlebot.nb
CHANGED
@@ -33,6 +33,7 @@ rescue LoadError
|
|
33
33
|
end
|
34
34
|
require 'nkf'
|
35
35
|
require 'open-uri'
|
36
|
+
require 'tempfile'
|
36
37
|
require 'timeout'
|
37
38
|
require 'tmpdir'
|
38
39
|
|
@@ -148,28 +149,13 @@ module URL2Title
|
|
148
149
|
title = tweet unless tweet.empty?
|
149
150
|
end
|
150
151
|
end
|
151
|
-
when /\A(?:github\.com)\z/
|
152
|
-
# ignore og:title
|
153
|
-
if title
|
154
|
-
title = title.gsub(/\xC2\xB8/u, "-")
|
155
|
-
end
|
156
152
|
else
|
157
153
|
if defined?(::Nokogiri)
|
158
154
|
doc ||= Nokogiri::HTML(body, uri.to_s, 'utf-8')
|
159
|
-
og_title = doc.xpath("//meta[@property='og:title'][1]/@content")
|
160
|
-
unless og_title.empty?
|
161
|
-
# title is escaped string when get by regexp
|
162
|
-
title = CGI.escapeHTML(og_title.text)
|
163
|
-
end
|
164
|
-
elsif /<meta property="og:title" content="(.+?)">/ =~ body
|
165
|
-
title = $1
|
166
|
-
end
|
167
|
-
if defined?(::Nokogiri)
|
168
|
-
doc ||= Nokogiri::HTML(body, uri.to_s, 'utf-8')
|
169
|
-
og_title = doc.xpath("//meta[@property='og:title']/@content")
|
155
|
+
og_title = doc.xpath("//meta[@property='og:title'][1]/@content").text
|
170
156
|
unless og_title.empty?
|
171
157
|
# title is escaped string when get by regexp
|
172
|
-
title = CGI.escapeHTML(og_title
|
158
|
+
title = CGI.escapeHTML(og_title)
|
173
159
|
end
|
174
160
|
elsif /<meta property="og:title" content="(.+?)">/ =~ body
|
175
161
|
title = $1
|
@@ -210,6 +196,14 @@ module URL2Title
|
|
210
196
|
return info
|
211
197
|
else
|
212
198
|
info[:title] = "(unknown image format)"
|
199
|
+
temp = Tempfile.new("titlebot", :encoding => 'ascii-8bit')
|
200
|
+
begin
|
201
|
+
temp.write(body)
|
202
|
+
temp.close
|
203
|
+
info[:title] = `identify '#{temp.path}'`.sub(/\A#{Regexp.quote(temp.path)}/, '').strip
|
204
|
+
ensure
|
205
|
+
temp.unlink
|
206
|
+
end
|
213
207
|
return info
|
214
208
|
end
|
215
209
|
else
|
@@ -246,10 +240,14 @@ module URL2Title
|
|
246
240
|
end
|
247
241
|
end
|
248
242
|
|
243
|
+
def cleanup(title)
|
244
|
+
title.gsub(/ | | |\u{A0}/i, ' ')
|
245
|
+
end
|
246
|
+
|
249
247
|
def url2title(url, headers)
|
250
248
|
url = prepare_url(url)
|
251
249
|
info = get_title(url, headers)
|
252
|
-
info[:title] = truncate(info[:title])
|
250
|
+
info[:title] = truncate(cleanup(info[:title]))
|
253
251
|
info
|
254
252
|
end
|
255
253
|
end
|
@@ -257,7 +255,7 @@ end
|
|
257
255
|
if __FILE__ == $0
|
258
256
|
require File.expand_path('../../ndk/version', __FILE__)
|
259
257
|
def u2t(url)
|
260
|
-
firefox = "Mozilla/5.0 (
|
258
|
+
firefox = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:25.0) Gecko/20100101 Firefox/25.0"
|
261
259
|
ua = "NadokaTitleBot/#{Nadoka::VERSION}"
|
262
260
|
headers = {
|
263
261
|
"User-Agent" => "#{firefox} Ruby/#{RUBY_VERSION} #{ua}",
|
@@ -295,6 +293,7 @@ class TitleBot < Nadoka::NDK_Bot
|
|
295
293
|
@same_bot = @bot_config.fetch(:same_bot, /(?!)/)
|
296
294
|
@nkf_options = @bot_config.fetch(:nkf, "--oc=CP50221 --ic=UTF-8 --fb-xml")
|
297
295
|
@timeout = @bot_config.fetch(:timeout, 10)
|
296
|
+
@skip_nkf_msg = @bot_config.fetch(:skip_nkf_msg, false)
|
298
297
|
@fragment_size_range = @bot_config.fetch(:fragment_size_range, 5..100)
|
299
298
|
@headers = @bot_config.fetch(:headers, {})
|
300
299
|
end
|
@@ -310,6 +309,7 @@ class TitleBot < Nadoka::NDK_Bot
|
|
310
309
|
def on_privmsg prefix, ch, msg
|
311
310
|
return unless @available_channel === ch
|
312
311
|
|
312
|
+
msg = NKF.nkf('-w', msg) unless @skip_nkf_msg
|
313
313
|
case msg
|
314
314
|
when /^\S+>/
|
315
315
|
# ignore messages to other bots
|
data/rice/irc.rb
CHANGED
@@ -740,6 +740,7 @@ E
|
|
740
740
|
252,RPL_LUSEROP 253,RPL_LUSERUNKNOWN 254,RPL_LUSERCHANNELS
|
741
741
|
255,RPL_LUSERME 256,RPL_ADMINME 257,RPL_ADMINLOC1
|
742
742
|
258,RPL_ADMINLOC2 259,RPL_ADMINEMAIL 263,RPL_TRYAGAIN
|
743
|
+
265,RPL_LOCALUSERS 266,RPL_GLOBALUSERS
|
743
744
|
401,ERR_NOSUCHNICK 402,ERR_NOSUCHSERVER 403,ERR_NOSUCHCHANNEL
|
744
745
|
404,ERR_CANNOTSENDTOCHAN 405,ERR_TOOMANYCHANNELS
|
745
746
|
406,ERR_WASNOSUCHNICK 407,ERR_TOOMANYTARGETS
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nadoka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kazuhiro NISHIYAMA
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-06-29 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Nadoka is a tool for monitoring and logging IRC conversations and responding
|
15
15
|
to specially formatted requests. You define and customize these responses in Ruby.
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- plugins/checkbot.nb
|
50
50
|
- plugins/codesearchbot.nb
|
51
51
|
- plugins/cronbot.nb
|
52
|
+
- plugins/crubybot.nb
|
52
53
|
- plugins/dictbot.nb
|
53
54
|
- plugins/drbcl.rb
|
54
55
|
- plugins/drbot.nb
|
@@ -73,7 +74,6 @@ files:
|
|
73
74
|
- plugins/tenkibot.nb
|
74
75
|
- plugins/timestampbot.nb
|
75
76
|
- plugins/titlebot.nb
|
76
|
-
- plugins/translatebot.nb
|
77
77
|
- plugins/twitterbot.nb
|
78
78
|
- plugins/weba.nb
|
79
79
|
- plugins/xibot.nb
|
@@ -96,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: '0'
|
98
98
|
requirements: []
|
99
|
-
rubyforge_project:
|
99
|
+
rubyforge_project:
|
100
100
|
rubygems_version: 2.0.3
|
101
101
|
signing_key:
|
102
102
|
specification_version: 4
|
data/plugins/translatebot.nb
DELETED
@@ -1,301 +0,0 @@
|
|
1
|
-
# -*-ruby-*-
|
2
|
-
#
|
3
|
-
# Copyright (c) 2010 SASADA Koichi <ko1 at atdot.net>
|
4
|
-
#
|
5
|
-
# This program is free software with ABSOLUTELY NO WARRANTY.
|
6
|
-
# You can re-distribute and/or modify this program under
|
7
|
-
# the same terms of the Ruby's license.
|
8
|
-
#
|
9
|
-
|
10
|
-
=begin
|
11
|
-
|
12
|
-
== Usage with irc client
|
13
|
-
|
14
|
-
trans> hello
|
15
|
-
-> translate hello as a English to Japanese.
|
16
|
-
|
17
|
-
trans:ja> hello
|
18
|
-
-> ditto.
|
19
|
-
|
20
|
-
trans:en,ja> hello
|
21
|
-
-> ditto.
|
22
|
-
|
23
|
-
trans:(([lang_from],)[lang_to])> [phrase]
|
24
|
-
-> translate [phrase] as lang_from to lang_to.
|
25
|
-
|
26
|
-
transj> [phrase]
|
27
|
-
-> translate to Japanese
|
28
|
-
|
29
|
-
transe> [phrase]
|
30
|
-
-> translate to English
|
31
|
-
|
32
|
-
== Configuration:
|
33
|
-
|
34
|
-
BotConfig = [
|
35
|
-
{
|
36
|
-
:name => :TranslateBot,
|
37
|
-
:ch => /.*/,
|
38
|
-
:referer => 'http://rubyforge.org/projects/nadoka/',
|
39
|
-
# Register URL at http://code.google.com/intl/ja/apis/ajaxsearch/signup.html
|
40
|
-
# and set your URL to :referer and your API key to :api_key if you want.
|
41
|
-
:to_lang => 'ja',
|
42
|
-
:to_lang2 => 'en',
|
43
|
-
:ch_kcode => :tojis,
|
44
|
-
},
|
45
|
-
]
|
46
|
-
|
47
|
-
=end
|
48
|
-
|
49
|
-
require 'iconv'
|
50
|
-
require 'kconv'
|
51
|
-
require 'shellwords'
|
52
|
-
require 'cgi'
|
53
|
-
require 'open-uri'
|
54
|
-
begin
|
55
|
-
require 'json'
|
56
|
-
rescue LoadError
|
57
|
-
require 'rubygems'
|
58
|
-
require 'json'
|
59
|
-
end
|
60
|
-
|
61
|
-
class TranslateBot < Nadoka::NDK_Bot
|
62
|
-
def bot_initialize
|
63
|
-
@available_channel = @bot_config[:ch] || /.*/
|
64
|
-
@search_default_lang = (@bot_config[:search_default_lang] || 'ja').sub(/^lang_/, '')
|
65
|
-
@referer = @bot_config[:referer] || 'http://rubyforge.org/projects/nadoka/'
|
66
|
-
@ch_kcode = @bot_config.fetch(:ch_kcode, :tojis)
|
67
|
-
@to_lang = @bot_config.fetch(:to_lang, 'ja')
|
68
|
-
@to_lang2 = @bot_config.fetch(:to_lang2, 'en')
|
69
|
-
@bing_appid = @bot_config.fetch(:bing_appid, nil)
|
70
|
-
end
|
71
|
-
|
72
|
-
def on_privmsg prefix, ch, msg
|
73
|
-
if @available_channel === ch and /^tr/ =~ msg
|
74
|
-
if response = dispatch_command(msg)
|
75
|
-
response.each{|r|
|
76
|
-
send_notice(ch, r) if r
|
77
|
-
}
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
SHORT_LANG = {'e' => 'en', 'j' => 'ja'}
|
83
|
-
|
84
|
-
def dispatch_command msg
|
85
|
-
begin
|
86
|
-
case msg
|
87
|
-
when /^trans(?:late)?(:(.*?))?>\s*(.+)/o
|
88
|
-
translate($3, *parse_trans_option($2, $3))
|
89
|
-
when /^trans([ej])>\s*(.+)/o
|
90
|
-
translate($2, nil, SHORT_LANG[$1])
|
91
|
-
when /^trans(?:late)?r(:(.*?))?>\s*(.+)/o
|
92
|
-
translate_r($3, *parse_trans_option($2, $3))
|
93
|
-
when /^translang>(.+)/
|
94
|
-
lang = $1.strip
|
95
|
-
desc = 'Unknown. See http://code.google.com/intl/ja/apis/ajaxlanguage/documentation/reference.html#LangNameArray'
|
96
|
-
r = LANGUAGE_MAP_S2L.fetch(lang.downcase,
|
97
|
-
LANGUAGE_MAP.fetch(lang.upcase, desc))
|
98
|
-
"translang> #{lang} = #{r}"
|
99
|
-
end
|
100
|
-
rescue Exception => e
|
101
|
-
"translate bot: #{e.message}"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def detect_lang str
|
106
|
-
uri = "http://ajax.googleapis.com/ajax/services/language/detect?v=1.0&q="
|
107
|
-
uri << CGI.escape(str.toutf8)
|
108
|
-
|
109
|
-
result = open(uri, "Referer" => @referer) do |f|
|
110
|
-
JSON.parse(f.read)
|
111
|
-
end
|
112
|
-
|
113
|
-
if result["responseData"]
|
114
|
-
result["responseData"]["language"]
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def parse_trans_option opt, str
|
119
|
-
case opt
|
120
|
-
when nil
|
121
|
-
from_lang = detect_lang(str)
|
122
|
-
to_lang = @to_lang
|
123
|
-
if to_lang == from_lang
|
124
|
-
to_lang = @to_lang2
|
125
|
-
end
|
126
|
-
[from_lang, to_lang]
|
127
|
-
when /\A([\w\-]+)[, \>]([\w\-]+)\z/
|
128
|
-
[$1, $2]
|
129
|
-
when /\A([\w\-]+)\z/
|
130
|
-
[nil, $1]
|
131
|
-
else
|
132
|
-
raise "can't parse translation option: #{opt}"
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def translate phrase, from_lang, to_lang
|
137
|
-
r = []
|
138
|
-
|
139
|
-
gr = translate_ggl(phrase, from_lang, to_lang)
|
140
|
-
r << "g:translate bot (#{gr[1]}): #{gr[0]}"
|
141
|
-
|
142
|
-
if @bing_appid
|
143
|
-
mr = translate_ms(phrase, from_lang, to_lang) if @bing_appid
|
144
|
-
r << "m:translate bot (#{mr[1]}): #{mr[0]}"
|
145
|
-
end
|
146
|
-
r
|
147
|
-
end
|
148
|
-
|
149
|
-
def translate_r phrase, from_lang, to_lang
|
150
|
-
rs = []
|
151
|
-
%w(ggl ms).each{|system|
|
152
|
-
r = send("translate_#{system}", phrase, from_lang, to_lang)
|
153
|
-
from_lang = r[2]
|
154
|
-
first = r[0]
|
155
|
-
if from_lang
|
156
|
-
r = send("translate_#{system}", r[0], to_lang, from_lang)
|
157
|
-
rs << "#{system.split(//)[0]}:trans_r (#{from_lang}>#{to_lang}>#{from_lang}): #{r[0]} (#{first})"
|
158
|
-
end
|
159
|
-
}
|
160
|
-
rs
|
161
|
-
end
|
162
|
-
|
163
|
-
|
164
|
-
def translate_ggl(phrase, from_lang, to_lang)
|
165
|
-
uri = 'http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q='
|
166
|
-
uri << CGI.escape(phrase.toutf8)
|
167
|
-
uri << "&langpair=#{from_lang}%7C#{to_lang}"
|
168
|
-
|
169
|
-
result = open(uri, "Referer" => @referer) do |f|
|
170
|
-
JSON.parse(f.read)
|
171
|
-
end
|
172
|
-
|
173
|
-
if result["responseData"]
|
174
|
-
text = CGI.unescapeHTML(result["responseData"]["translatedText"])
|
175
|
-
text = text.send(@ch_kcode) if @ch_kcode
|
176
|
-
from_lang ||= result["responseData"]["detectedSourceLanguage"]
|
177
|
-
opts = "#{from_lang}>#{to_lang}"
|
178
|
-
[text, opts, from_lang]
|
179
|
-
else
|
180
|
-
opts = "#{from_lang ? "from #{from_lang} to " : ''}#{to_lang}"
|
181
|
-
["#{result["responseDetails"]} (#{uri})", opts]
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
## ms translate
|
186
|
-
|
187
|
-
def get_result_ms result
|
188
|
-
# puts result
|
189
|
-
doc = REXML::Document.new(result)
|
190
|
-
doc.elements.map{|e| e.text}[0]
|
191
|
-
end
|
192
|
-
|
193
|
-
def translate_ms phrase, from_lang, to_lang
|
194
|
-
api_url = 'http://api.microsofttranslator.com/V2/Http.svc/Translate'
|
195
|
-
uri = "#{api_url}?appId=#{@bing_appid}&text=#{CGI.escape(phrase.toutf8)}&to=#{CGI.escape(to_lang)}"
|
196
|
-
begin
|
197
|
-
text = get_result_ms open(uri, "Referer" => @referer).read
|
198
|
-
text = text.send(@ch_kcode) if @ch_kcode
|
199
|
-
opts = "#{from_lang}>#{to_lang}"
|
200
|
-
[text, opts, from_lang]
|
201
|
-
rescue OpenURI::HTTPError => e
|
202
|
-
opts = "#{from_lang ? "from #{from_lang} to " : ''}#{to_lang}"
|
203
|
-
["#{e.message} (uri)", opts]
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
# copy from http://code.google.com/intl/ja/apis/ajaxlanguage/documentation/reference.html
|
208
|
-
LANGUAGE_MAP = {
|
209
|
-
'AFRIKAANS' => 'af',
|
210
|
-
'ALBANIAN' => 'sq',
|
211
|
-
'AMHARIC' => 'am',
|
212
|
-
'ARABIC' => 'ar',
|
213
|
-
'ARMENIAN' => 'hy',
|
214
|
-
'AZERBAIJANI' => 'az',
|
215
|
-
'BASQUE' => 'eu',
|
216
|
-
'BELARUSIAN' => 'be',
|
217
|
-
'BENGALI' => 'bn',
|
218
|
-
'BIHARI' => 'bh',
|
219
|
-
'BULGARIAN' => 'bg',
|
220
|
-
'BURMESE' => 'my',
|
221
|
-
'CATALAN' => 'ca',
|
222
|
-
'CHEROKEE' => 'chr',
|
223
|
-
'CHINESE' => 'zh',
|
224
|
-
'CHINESE_SIMPLIFIED' => 'zh-CN',
|
225
|
-
'CHINESE_TRADITIONAL' => 'zh-TW',
|
226
|
-
'CROATIAN' => 'hr',
|
227
|
-
'CZECH' => 'cs',
|
228
|
-
'DANISH' => 'da',
|
229
|
-
'DHIVEHI' => 'dv',
|
230
|
-
'DUTCH'=> 'nl',
|
231
|
-
'ENGLISH' => 'en',
|
232
|
-
'ESPERANTO' => 'eo',
|
233
|
-
'ESTONIAN' => 'et',
|
234
|
-
'FILIPINO' => 'tl',
|
235
|
-
'FINNISH' => 'fi',
|
236
|
-
'FRENCH' => 'fr',
|
237
|
-
'GALICIAN' => 'gl',
|
238
|
-
'GEORGIAN' => 'ka',
|
239
|
-
'GERMAN' => 'de',
|
240
|
-
'GREEK' => 'el',
|
241
|
-
'GUARANI' => 'gn',
|
242
|
-
'GUJARATI' => 'gu',
|
243
|
-
'HEBREW' => 'iw',
|
244
|
-
'HINDI' => 'hi',
|
245
|
-
'HUNGARIAN' => 'hu',
|
246
|
-
'ICELANDIC' => 'is',
|
247
|
-
'INDONESIAN' => 'id',
|
248
|
-
'INUKTITUT' => 'iu',
|
249
|
-
'ITALIAN' => 'it',
|
250
|
-
'JAPANESE' => 'ja',
|
251
|
-
'KANNADA' => 'kn',
|
252
|
-
'KAZAKH' => 'kk',
|
253
|
-
'KHMER' => 'km',
|
254
|
-
'KOREAN' => 'ko',
|
255
|
-
'KURDISH'=> 'ku',
|
256
|
-
'KYRGYZ'=> 'ky',
|
257
|
-
'LAOTHIAN'=> 'lo',
|
258
|
-
'LATVIAN' => 'lv',
|
259
|
-
'LITHUANIAN' => 'lt',
|
260
|
-
'MACEDONIAN' => 'mk',
|
261
|
-
'MALAY' => 'ms',
|
262
|
-
'MALAYALAM' => 'ml',
|
263
|
-
'MALTESE' => 'mt',
|
264
|
-
'MARATHI' => 'mr',
|
265
|
-
'MONGOLIAN' => 'mn',
|
266
|
-
'NEPALI' => 'ne',
|
267
|
-
'NORWEGIAN' => 'no',
|
268
|
-
'ORIYA' => 'or',
|
269
|
-
'PASHTO' => 'ps',
|
270
|
-
'PERSIAN' => 'fa',
|
271
|
-
'POLISH' => 'pl',
|
272
|
-
'PORTUGUESE' => 'pt-PT',
|
273
|
-
'PUNJABI' => 'pa',
|
274
|
-
'ROMANIAN' => 'ro',
|
275
|
-
'RUSSIAN' => 'ru',
|
276
|
-
'SANSKRIT' => 'sa',
|
277
|
-
'SERBIAN' => 'sr',
|
278
|
-
'SINDHI' => 'sd',
|
279
|
-
'SINHALESE' => 'si',
|
280
|
-
'SLOVAK' => 'sk',
|
281
|
-
'SLOVENIAN' => 'sl',
|
282
|
-
'SPANISH' => 'es',
|
283
|
-
'SWAHILI' => 'sw',
|
284
|
-
'SWEDISH' => 'sv',
|
285
|
-
'TAJIK' => 'tg',
|
286
|
-
'TAMIL' => 'ta',
|
287
|
-
'TAGALOG' => 'tl',
|
288
|
-
'TELUGU' => 'te',
|
289
|
-
'THAI' => 'th',
|
290
|
-
'TIBETAN' => 'bo',
|
291
|
-
'TURKISH' => 'tr',
|
292
|
-
'UKRAINIAN' => 'uk',
|
293
|
-
'URDU' => 'ur',
|
294
|
-
'UZBEK' => 'uz',
|
295
|
-
'UIGHUR' => 'ug',
|
296
|
-
'VIETNAMESE' => 'vi',
|
297
|
-
'UNKNOWN' => ''
|
298
|
-
}
|
299
|
-
|
300
|
-
LANGUAGE_MAP_S2L = LANGUAGE_MAP.invert
|
301
|
-
end
|