net-irc 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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: