net-irc 0.0.3 → 0.0.4

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/ChangeLog CHANGED
@@ -1,3 +1,10 @@
1
+ 2008-06-28 cho45
2
+
3
+ * [interface]:
4
+ Change mode character to symbol.
5
+ * [new]:
6
+ Seperate each class to some files.
7
+
1
8
  2008-06-14 cho45
2
9
 
3
10
  * [bug]:
@@ -0,0 +1,265 @@
1
+ #!/usr/bin/env ruby
2
+ =begin
3
+
4
+
5
+ ## Licence
6
+
7
+ Ruby's by cho45
8
+
9
+ =end
10
+
11
+ $LOAD_PATH << "lib"
12
+ $LOAD_PATH << "../lib"
13
+
14
+ $KCODE = "u" # json use this
15
+
16
+ require "rubygems"
17
+ require "json"
18
+ require "net/irc"
19
+ require "mechanize"
20
+ require "sdbm"
21
+ require "tmpdir"
22
+ require "nkf"
23
+
24
+ class HatenaStarStream < Net::IRC::Server::Session
25
+ def server_name
26
+ "hatenastarstream"
27
+ end
28
+
29
+ def server_version
30
+ "0.0.0"
31
+ end
32
+
33
+ def main_channel
34
+ "#star"
35
+ end
36
+
37
+ def initialize(*args)
38
+ super
39
+ @ua = WWW::Mechanize.new
40
+ @ua.max_history = 1
41
+ end
42
+
43
+ def on_user(m)
44
+ super
45
+ post @prefix, JOIN, main_channel
46
+ post server_name, MODE, main_channel, "+o", @prefix.nick
47
+
48
+ @real, *@opts = @opts.name || @real.split(/\s+/)
49
+ @opts ||= []
50
+
51
+ start_observer
52
+ end
53
+
54
+ def on_disconnected
55
+ @observer.kill rescue nil
56
+ end
57
+
58
+ def on_privmsg(m)
59
+ @ua.instance_eval do
60
+ get "http://h.hatena.ne.jp/"
61
+ form = page.forms.find {|f| f.action == "/entry" }
62
+ form["body"] = m[1]
63
+ submit form
64
+ end
65
+ post server_name, NOTICE, main_channel, "posted"
66
+ rescue Exception => e
67
+ log e.inspect
68
+ end
69
+
70
+ def on_ctcp(target, message)
71
+ end
72
+
73
+ def on_whois(m)
74
+ end
75
+
76
+ def on_who(m)
77
+ end
78
+
79
+ def on_join(m)
80
+ end
81
+
82
+ def on_part(m)
83
+ end
84
+
85
+ private
86
+ def start_observer
87
+ @observer = Thread.start do
88
+ Thread.abort_on_exception = true
89
+ loop do
90
+ begin
91
+ login
92
+ @log.info "getting report..."
93
+ @ua.get("http://s.hatena.ne.jp/#{@real}/report")
94
+ entries = @ua.page.root.search("#main span.entry-title a").map {|a|
95
+ a[:href]
96
+ }
97
+
98
+ @log.info "getting stars... #{entries.length}"
99
+ stars = retrive_stars(entries)
100
+
101
+ db = SDBM.open("#{Dir.tmpdir}/#{@real}.db", 0666)
102
+ entries.reverse_each do |entry|
103
+ next if stars[entry].empty?
104
+ s, quoted = stars[entry].select {|star|
105
+ id = "#{entry}::#{star.values_at("name", "quote").inspect}"
106
+ if db.include?(id)
107
+ false
108
+ else
109
+ db[id] = "1"
110
+ true
111
+ end
112
+ }.partition {|star| star["quote"].empty? }
113
+ post server_name, NOTICE, main_channel, "#{entry} #{title(entry)}" if s.length + quoted.length > 0
114
+ post server_name, NOTICE, main_channel, s.map {|star| "id:#{star["name"]}" }.join(" ") unless s.empty?
115
+
116
+ quoted.each do |star|
117
+ post server_name, NOTICE, main_channel, "id:#{star["name"]} '#{star["quote"]}'"
118
+ end
119
+ end
120
+
121
+ rescue Exception => e
122
+ @log.error e.inspect
123
+ ensure
124
+ db.close rescue nil
125
+ end
126
+ sleep 60 * 5
127
+ end
128
+ end
129
+ end
130
+
131
+ def retrive_stars(entries, n=0)
132
+ uri = "http://s.hatena.ne.jp/entries.json?"
133
+ while uri.length < 1800 and n < entries.length
134
+ uri << "uri=#{URI.escape(entries[n], /[^-.!~*'()\w]/n)}&"
135
+ n += 1
136
+ end
137
+ ret = JSON.load(@ua.get(uri).body)["entries"].inject({}) {|r,i|
138
+ if i["stars"].any? {|star| star.kind_of? Numeric }
139
+ i = JSON.load(@ua.get("http://s.hatena.ne.jp/entry.json?uri=#{URI.escape(i["uri"])}").body)["entries"].first
140
+ end
141
+ r.update(i["uri"] => i["stars"])
142
+ }
143
+ if n < entries.length
144
+ ret.update retrive_stars(entries, n)
145
+ end
146
+ ret
147
+ end
148
+
149
+ def title(url)
150
+ uri = URI(url)
151
+ @ua.get(uri)
152
+
153
+ text = ""
154
+ case
155
+ when uri.fragment
156
+ fragment = @ua.page.root.at("//*[@name = '#{uri.fragment}']") || @ua.page.root.at("//*[@id = '#{uri.fragment}']")
157
+
158
+ text = fragment.inner_text + fragment.following.text + fragment.parent.following.text
159
+ when uri.to_s =~ %r|^http://h.hatena.ne.jp/[^/]+/\d+|
160
+ text = @ua.page.root.at("#main .entries .entry .list-body div.body").inner_text
161
+ else
162
+ text = @ua.page.root.at("//title").inner_text
163
+ end
164
+ text.gsub!(/\s+/, " ")
165
+ text.strip!
166
+ NKF.nkf("-w", text).split(//)[0..30].join
167
+ rescue Exception => e
168
+ @log.debug ["title:", e.inspect]
169
+ ""
170
+ end
171
+
172
+ def login
173
+ @log.info "logging in as #{@real}"
174
+ @ua.get "https://www.hatena.ne.jp/login?backurl=http%3A%2F%2Fd.hatena.ne.jp%2F"
175
+ return if @ua.page.forms.empty?
176
+
177
+ form = @ua.page.forms.first
178
+ form["name"] = @real
179
+ form["password"] = @pass
180
+
181
+ @ua.submit(form)
182
+
183
+ unless @ua.page.forms.empty?
184
+ post server_name, ERR_PASSWDMISMATCH, ":Password incorrect"
185
+ finish
186
+ end
187
+ end
188
+ end
189
+
190
+ if __FILE__ == $0
191
+ require "optparse"
192
+
193
+ opts = {
194
+ :port => 16700,
195
+ :host => "localhost",
196
+ :log => nil,
197
+ :debug => false,
198
+ :foreground => false,
199
+ }
200
+
201
+ OptionParser.new do |parser|
202
+ parser.instance_eval do
203
+ self.banner = <<-EOB.gsub(/^\t+/, "")
204
+ Usage: #{$0} [opts]
205
+
206
+ EOB
207
+
208
+ separator ""
209
+
210
+ separator "Options:"
211
+ on("-p", "--port [PORT=#{opts[:port]}]", "port number to listen") do |port|
212
+ opts[:port] = port
213
+ end
214
+
215
+ on("-h", "--host [HOST=#{opts[:host]}]", "host name or IP address to listen") do |host|
216
+ opts[:host] = host
217
+ end
218
+
219
+ on("-l", "--log LOG", "log file") do |log|
220
+ opts[:log] = log
221
+ end
222
+
223
+ on("--debug", "Enable debug mode") do |debug|
224
+ opts[:log] = $stdout
225
+ opts[:debug] = true
226
+ end
227
+
228
+ on("-f", "--foreground", "run foreground") do |foreground|
229
+ opts[:log] = $stdout
230
+ opts[:foreground] = true
231
+ end
232
+
233
+ parse!(ARGV)
234
+ end
235
+ end
236
+
237
+ opts[:logger] = Logger.new(opts[:log], "daily")
238
+ opts[:logger].level = opts[:debug] ? Logger::DEBUG : Logger::INFO
239
+
240
+ def daemonize(foreground=false)
241
+ trap("SIGINT") { exit! 0 }
242
+ trap("SIGTERM") { exit! 0 }
243
+ trap("SIGHUP") { exit! 0 }
244
+ return yield if $DEBUG || foreground
245
+ Process.fork do
246
+ Process.setsid
247
+ Dir.chdir "/"
248
+ File.open("/dev/null") {|f|
249
+ STDIN.reopen f
250
+ STDOUT.reopen f
251
+ STDERR.reopen f
252
+ }
253
+ yield
254
+ end
255
+ exit! 0
256
+ end
257
+
258
+ daemonize(opts[:debug] || opts[:foreground]) do
259
+ Net::IRC::Server.new(opts[:host], opts[:port], HatenaStarStream, opts).start
260
+ end
261
+ end
262
+
263
+ # Local Variables:
264
+ # coding: utf-8
265
+ # End:
data/examples/lig.rb CHANGED
@@ -266,6 +266,9 @@ class LingrIrcGateway < Net::IRC::Server::Session
266
266
  unless e.code == 102
267
267
  log "Error: #{e.code}: #{e.message}"
268
268
  log "Coundn't say to #{target}."
269
+
270
+ @channels.delete(channel.downcase)
271
+ post prefix, PART, channel, "Parted"
269
272
  end
270
273
  end
271
274
 
data/examples/mixi.rb ADDED
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env ruby
2
+ =begin
3
+
4
+
5
+ ## Licence
6
+
7
+ Ruby's by cho45
8
+
9
+ =end
10
+
11
+ $LOAD_PATH << "lib"
12
+ $LOAD_PATH << "../lib"
13
+
14
+ $KCODE = "u" # json use this
15
+
16
+ require "rubygems"
17
+ require "json"
18
+ require "net/irc"
19
+ require "mechanize"
20
+
21
+ # Mixi from mixi.vim by ujihisa!
22
+ class Mixi
23
+ def initialize(email, password, mixi_premium = false, image_dir = '~/.vim/mixi_images')
24
+ require 'kconv'
25
+ require 'rubygems'
26
+ require 'mechanize'
27
+
28
+ @image_dir = File.expand_path image_dir
29
+ @email, @password, @mixi_premium =
30
+ email, password, mixi_premium
31
+ end
32
+
33
+ def post(title, body, images)
34
+ @agent = WWW::Mechanize.new
35
+ @agent.user_agent_alias = 'Mac Safari'
36
+ page = @agent.get 'http://mixi.jp/home.pl'
37
+ form = page.forms[0]
38
+ form.email = @email
39
+ form.password = @password
40
+ @agent.submit form
41
+
42
+ page = @agent.get "http://mixi.jp/home.pl"
43
+ page = @agent.get page.links[18].uri
44
+ form = page.forms[(@mixi_premium ? 1 : 0)]
45
+ form.diary_title = title
46
+ form.diary_body = self.class.magic_body(body)
47
+ get_image images
48
+ images[0, 3].each_with_index do |img, i|
49
+ if /darwin/ =~ RUBY_PLATFORM && /\.png$/i =~ img
50
+ imgjpg = '/tmp/mixi-vim-' << File.basename(img).sub(/\.png$/i, '.jpg')
51
+ system "sips -s format jpeg --out #{imgjpg} #{img} > /dev/null 2>&1"
52
+ img = imgjpg
53
+ end
54
+ form.file_uploads[i].file_name = img
55
+ end
56
+ page = @agent.submit form
57
+ page = @agent.submit page.forms[0]
58
+ end
59
+
60
+ def get_latest
61
+ page = @agent.get 'http://mixi.jp/list_diary.pl'
62
+ ["http://mixi.jp/" << page.links[37].uri.to_s.toutf8,
63
+ page.links[37].text.toutf8]
64
+ end
65
+
66
+ def self.magic_body(body)
67
+ body.gsub(/^( )+/) {|i| ' '.toeuc * (i.length/2) }
68
+ end
69
+
70
+ def get_image(images)
71
+ images.each_with_index do |img, i|
72
+ if img =~ %r{^http://}
73
+ path =
74
+ File.join @image_dir, i.to_s + File.extname(img)
75
+ unless File.exist? @image_dir
76
+ Dir.mkdir @image_dir
77
+ else
78
+ Dir.chdir(@image_dir) do
79
+ Dir.entries(@image_dir).
80
+ each {|f| File.unlink f if File.file? f }
81
+ end
82
+ end
83
+ system "wget -O #{path} #{img} > /dev/null 2>&1"
84
+ if File.exist? path and !File.zero? path
85
+ images[i] = path
86
+ else
87
+ images.delete_at i
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ class MixiDiary < Net::IRC::Server::Session
95
+ def server_name
96
+ "mixi"
97
+ end
98
+
99
+ def server_version
100
+ "0.0.0"
101
+ end
102
+
103
+ def main_channel
104
+ "#mixi"
105
+ end
106
+
107
+ def initialize(*args)
108
+ super
109
+ @ua = WWW::Mechanize.new
110
+ end
111
+
112
+ def on_user(m)
113
+ super
114
+ post @prefix, JOIN, main_channel
115
+ post server_name, MODE, main_channel, "+o", @prefix.nick
116
+
117
+ @real, *@opts = @opts.name || @real.split(/\s+/)
118
+ @opts ||= []
119
+
120
+ @mixi = Mixi.new(@real, @pass)
121
+ @cont = []
122
+ end
123
+
124
+ def on_disconnected
125
+ @observer.kill rescue nil
126
+ end
127
+
128
+ def on_privmsg(m)
129
+ super
130
+
131
+ case m[1]
132
+ when "."
133
+ title, body = *@cont
134
+ @mixi.post ">_<× < #{title}".toeuc, body.toeuc, []
135
+ @mixi.get_latest.each do |line|
136
+ post server_name, NOTICE, main_channel, line.chomp
137
+ end
138
+ when " "
139
+ @cont.clear
140
+ else
141
+ @cont << m[1]
142
+ end
143
+ end
144
+
145
+ def on_ctcp(target, message)
146
+ end
147
+
148
+ def on_whois(m)
149
+ end
150
+
151
+ def on_who(m)
152
+ end
153
+
154
+ def on_join(m)
155
+ end
156
+
157
+ def on_part(m)
158
+ end
159
+ end
160
+
161
+ if __FILE__ == $0
162
+ require "optparse"
163
+
164
+ opts = {
165
+ :port => 16701,
166
+ :host => "localhost",
167
+ :log => nil,
168
+ :debug => false,
169
+ :foreground => false,
170
+ }
171
+
172
+ OptionParser.new do |parser|
173
+ parser.instance_eval do
174
+ self.banner = <<-EOB.gsub(/^\t+/, "")
175
+ Usage: #{$0} [opts]
176
+
177
+ EOB
178
+
179
+ separator ""
180
+
181
+ separator "Options:"
182
+ on("-p", "--port [PORT=#{opts[:port]}]", "port number to listen") do |port|
183
+ opts[:port] = port
184
+ end
185
+
186
+ on("-h", "--host [HOST=#{opts[:host]}]", "host name or IP address to listen") do |host|
187
+ opts[:host] = host
188
+ end
189
+
190
+ on("-l", "--log LOG", "log file") do |log|
191
+ opts[:log] = log
192
+ end
193
+
194
+ on("--debug", "Enable debug mode") do |debug|
195
+ opts[:log] = $stdout
196
+ opts[:debug] = true
197
+ end
198
+
199
+ on("-f", "--foreground", "run foreground") do |foreground|
200
+ opts[:log] = $stdout
201
+ opts[:foreground] = true
202
+ end
203
+
204
+ parse!(ARGV)
205
+ end
206
+ end
207
+
208
+ opts[:logger] = Logger.new(opts[:log], "daily")
209
+ opts[:logger].level = opts[:debug] ? Logger::DEBUG : Logger::INFO
210
+
211
+ def daemonize(foreground=false)
212
+ trap("SIGINT") { exit! 0 }
213
+ trap("SIGTERM") { exit! 0 }
214
+ trap("SIGHUP") { exit! 0 }
215
+ return yield if $DEBUG || foreground
216
+ Process.fork do
217
+ Process.setsid
218
+ Dir.chdir "/"
219
+ File.open("/dev/null") {|f|
220
+ STDIN.reopen f
221
+ STDOUT.reopen f
222
+ STDERR.reopen f
223
+ }
224
+ yield
225
+ end
226
+ exit! 0
227
+ end
228
+
229
+ daemonize(opts[:debug] || opts[:foreground]) do
230
+ Net::IRC::Server.new(opts[:host], opts[:port], MixiDiary, opts).start
231
+ end
232
+ end
233
+
234
+ # Local Variables:
235
+ # coding: utf-8
236
+ # End: