nadoka 0.8.6 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/nadoka.png)](http://badge.fury.io/rb/nadoka)
|
6
6
|
[![Build Status](https://travis-ci.org/nadoka/nadoka.png?branch=master)](https://travis-ci.org/nadoka/nadoka)
|
7
7
|
[![Code Climate](https://codeclimate.com/github/nadoka/nadoka.png)](https://codeclimate.com/github/nadoka/nadoka)
|
8
|
+
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/nadoka/nadoka/trend.png)](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
|