bbiff 0.2.2 → 0.3.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 +11 -9
- data/lib/bbiff/bbs_reader.rb +374 -101
- data/lib/bbiff/executable.rb +16 -10
- data/lib/bbiff/res_format.rb +1 -19
- data/lib/bbiff/show.rb +1 -1
- data/lib/bbiff/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 037966c6b4adc37eb5630c02746d1c0a6ef609ed
|
4
|
+
data.tar.gz: 87886e10129ef9ae257a78c52396bc0e3324ab39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1116585b2aa1dd80258bf3e8d99bba5cac503790539faeb5e5fea99b6bfedb9ea1601b59f0b3e061264f758a0500e62ef8f611cc5a45fc99ac974703344f9c73
|
7
|
+
data.tar.gz: 7eb9d8a7d563b58cc52534604e7af91a2d40f416eb66bbe8ed5ac60cd3963030fd244d320c134e17da3c82b1b27a23aacafd0f7723f51c6e442598d89e7b3706
|
data/README.md
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
|
3
3
|
## 必要なもの
|
4
4
|
|
5
|
-
notify-send
|
5
|
+
デスクトップに通知ポップアップを表示する、notify-send コマンド。Ubuntu
|
6
|
+
では以下のようにインストールできます。
|
6
7
|
|
7
8
|
sudo apt-get install libnotify-bin
|
8
9
|
|
@@ -14,8 +15,10 @@ notify-send コマンド
|
|
14
15
|
|
15
16
|
bbiff スレッドのURL レス通知を始める番号
|
16
17
|
|
17
|
-
スレッドのURL
|
18
|
-
|
18
|
+
スレッドのURLはしたらば掲示板の場合、
|
19
|
+
`http://jbbs.shitaraba.net/bbs/read.cgi/カテゴリ/板ID/スレID/`、2ちゃ
|
20
|
+
んねる互換掲示板の場合は、`http://ホスト名/test/read.cgi/板名/スレID/`
|
21
|
+
のような形式になります。
|
19
22
|
|
20
23
|
単に
|
21
24
|
|
@@ -23,16 +26,11 @@ notify-send コマンド
|
|
23
26
|
|
24
27
|
とすると、前回監視したスレッドを監視します。
|
25
28
|
|
26
|
-
## 開発・TODO
|
27
|
-
|
28
|
-
- .travis.ymlでテストするなら要編集
|
29
|
-
- moduleの中にまとめるべきかも
|
30
|
-
|
31
29
|
## リリース
|
32
30
|
|
33
31
|
ver 0.1.0
|
34
32
|
* gem 化した。(DoG-peer さん)
|
35
|
-
|
33
|
+
|
36
34
|
ver 0.1.2
|
37
35
|
* notify-send コマンドがインストールされていない場合は echo コマンド
|
38
36
|
を利用するようにした。(raduwen さん)
|
@@ -53,6 +51,10 @@ ver 0.2.2
|
|
53
51
|
* 最後に読み込んだスレの情報が無い状態で、引数なしで bbiff を起動し
|
54
52
|
た時にエラーになっていたのを修正。
|
55
53
|
|
54
|
+
ver 0.3.0
|
55
|
+
* 2ちゃんねる互換掲示板に対応したつもり。
|
56
|
+
* 日付の相対表示を辞めた。
|
57
|
+
|
56
58
|
## 作者
|
57
59
|
|
58
60
|
予定地 <plonk@piano.email.ne.jp>
|
data/lib/bbiff/bbs_reader.rb
CHANGED
@@ -1,141 +1,414 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
require 'uri'
|
3
|
+
require 'pp' if $DEBUG
|
3
4
|
|
4
5
|
module Bbs
|
5
6
|
|
6
|
-
class
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
7
|
+
class Post
|
8
|
+
class << self
|
9
|
+
def from_s(str)
|
10
|
+
Post.new(*str.split('<>', 5))
|
11
|
+
end
|
12
|
+
end
|
13
13
|
|
14
|
-
|
15
|
-
return URI.parse("http://jbbs.shitaraba.net/bbs/rawmode.cgi/#{@カテゴリ}/#{@掲示板番号}/#{スレッド番号}/")
|
16
|
-
end
|
14
|
+
attr_reader :no, :name, :mail, :body, :date
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
def initialize(no, name, mail, date, body)
|
17
|
+
@no = no.to_i
|
18
|
+
@name = name
|
19
|
+
@mail = mail
|
20
|
+
@date = date
|
21
|
+
@body = body
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
# 削除された時のフィールドの値は、掲示板の設定によるなぁ。
|
25
|
+
# def deleted?
|
26
|
+
# @date == '<削除>'
|
27
|
+
# end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
return r.force_encoding("EUC-JP").encode("UTF-8")
|
32
|
-
end
|
29
|
+
def to_s
|
30
|
+
[no, name, mail, date, body].join('<>')
|
31
|
+
end
|
33
32
|
|
34
|
-
def thread(スレッド番号)
|
35
|
-
threads.find { |t| t.id == スレッド番号 }
|
36
33
|
end
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
35
|
+
class Downloader
|
36
|
+
class DownloadFailure < StandardError
|
37
|
+
attr_reader :response
|
38
|
+
|
39
|
+
def initialize(response)
|
40
|
+
@response = response
|
41
|
+
end
|
43
42
|
end
|
44
|
-
end
|
45
43
|
|
46
|
-
|
47
|
-
|
48
|
-
http.get(url.path)
|
49
|
-
}
|
50
|
-
return 応答.body
|
51
|
-
end
|
44
|
+
class Resource
|
45
|
+
attr_reader :data
|
52
46
|
|
53
|
-
|
47
|
+
def initialize(data)
|
48
|
+
self.data = data
|
49
|
+
end
|
54
50
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
51
|
+
def data=(new_data)
|
52
|
+
type_check(new_data)
|
53
|
+
@data = new_data.dup.freeze
|
54
|
+
end
|
61
55
|
|
62
|
-
|
63
|
-
attr_reader :no, :name, :mail, :body
|
56
|
+
private
|
64
57
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
58
|
+
# ASCII-8BIT エンコーディングの String に限定する。
|
59
|
+
def type_check(data)
|
60
|
+
unless data.is_a? String
|
61
|
+
raise TypeError, 'not a string'
|
62
|
+
end
|
63
|
+
unless data.encoding == Encoding::ASCII_8BIT
|
64
|
+
raise ArgumentError, "encoding not ASCII-8BIT (#{data.encoding})"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
69
68
|
|
70
|
-
|
71
|
-
@no = no.to_i
|
72
|
-
@name = name
|
73
|
-
@mail = mail
|
74
|
-
@date = date
|
75
|
-
@body = body
|
76
|
-
end
|
69
|
+
attr_reader :encoding
|
77
70
|
|
78
|
-
|
79
|
-
|
80
|
-
|
71
|
+
def initialize(encoding = 'UTF-8')
|
72
|
+
@encoding = encoding
|
73
|
+
@resource_cache = {}
|
74
|
+
end
|
81
75
|
|
82
|
-
|
83
|
-
|
84
|
-
|
76
|
+
# ASCII-8BIT エンコーディングの文字列を返す。
|
77
|
+
def download_binary(uri)
|
78
|
+
resource = @resource_cache[uri]
|
79
|
+
if resource
|
80
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
81
|
+
request = Net::HTTP::Get.new(uri)
|
82
|
+
request['range'] = "bytes=#{resource.data.bytesize}-"
|
83
|
+
response = http.request(request)
|
84
|
+
response.body.force_encoding('ASCII-8BIT')
|
85
|
+
pp response.code if $DEBUG
|
86
|
+
pp response.to_hash if $DEBUG
|
87
|
+
case response
|
88
|
+
when Net::HTTPPartialContent
|
89
|
+
p :partial if $DEBUG
|
90
|
+
resource.data += response.body
|
91
|
+
when Net::HTTPRequestedRangeNotSatisfiable
|
92
|
+
p :not_satisfiable if $DEBUG
|
93
|
+
# 多分DATは更新されていない
|
94
|
+
when Net::HTTPOK
|
95
|
+
p :ok if $DEBUG
|
96
|
+
@resource_cache[uri] = Resource.new(response.body)
|
97
|
+
return response.body
|
98
|
+
else
|
99
|
+
raise DownloadFailure.new(response)
|
100
|
+
end
|
101
|
+
return resource.data
|
102
|
+
end
|
103
|
+
else
|
104
|
+
p :no_resource_yet if $DEBUG
|
105
|
+
body = download_binary_nocache(uri)
|
106
|
+
@resource_cache[uri] = Resource.new(body)
|
107
|
+
return body
|
108
|
+
end
|
109
|
+
end
|
85
110
|
|
86
|
-
|
111
|
+
def download_binary_nocache(uri)
|
112
|
+
response = nil
|
113
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
114
|
+
request = Net::HTTP::Get.new(uri)
|
115
|
+
response = http.request(request)
|
116
|
+
response.body.force_encoding('ASCII-8BIT')
|
117
|
+
pp response.code if $DEBUG
|
118
|
+
pp response.to_hash if $DEBUG
|
119
|
+
case response
|
120
|
+
when Net::HTTPOK
|
121
|
+
else
|
122
|
+
raise DownloadFailure.new(response)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
return response.body
|
126
|
+
end
|
87
127
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
Time.new(y, mon, d, h, min, sec)
|
92
|
-
else
|
93
|
-
fail ArgumentError
|
128
|
+
def download_text(uri)
|
129
|
+
# dup は重要。
|
130
|
+
download_binary(uri).dup.force_encoding(encoding).encode('UTF-8')
|
94
131
|
end
|
95
132
|
end
|
96
|
-
end
|
97
133
|
|
98
|
-
class
|
99
|
-
|
134
|
+
class BoardBase
|
135
|
+
private_class_method :new
|
136
|
+
attr_reader :settings_url
|
100
137
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
138
|
+
def initialize(text_encoding)
|
139
|
+
@downloader = Downloader.new(text_encoding)
|
140
|
+
end
|
141
|
+
|
142
|
+
def thread(thread_num)
|
143
|
+
threads.find { |t| t.id == thread_num }
|
144
|
+
end
|
145
|
+
|
146
|
+
def settings
|
147
|
+
return parse_settings(download_text(@settings_url))
|
148
|
+
end
|
149
|
+
|
150
|
+
def thread_list
|
151
|
+
return download_text(@thread_list_url)
|
152
|
+
end
|
153
|
+
|
154
|
+
def dat(thread_num)
|
155
|
+
return download_text(dat_url(thread_num))
|
156
|
+
end
|
157
|
+
|
158
|
+
def threads
|
159
|
+
thread_list.each_line.map do |line|
|
160
|
+
create_thread_from_line(line)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# 抽象メソッド
|
165
|
+
def create_thread_from_line(_line)
|
166
|
+
raise 'unimplemented'
|
167
|
+
end
|
168
|
+
|
169
|
+
def dat_url(_thread_num)
|
170
|
+
raise 'unimplemented'
|
171
|
+
end
|
172
|
+
|
173
|
+
protected
|
174
|
+
|
175
|
+
def download_binary(url)
|
176
|
+
@downloader.download_binary(url)
|
177
|
+
end
|
178
|
+
|
179
|
+
def download_text(url)
|
180
|
+
@downloader.download_text(url)
|
181
|
+
end
|
182
|
+
|
183
|
+
def parse_settings(string)
|
184
|
+
string.each_line.map { |line|
|
185
|
+
line.chomp.split(/=/, 2)
|
186
|
+
}.to_h
|
187
|
+
end
|
106
188
|
end
|
107
189
|
|
108
|
-
|
109
|
-
|
190
|
+
class ThreadBase
|
191
|
+
private_class_method :new
|
192
|
+
attr_reader :board, :id, :title, :last
|
193
|
+
|
194
|
+
def initialize(board, id, title, last)
|
195
|
+
@board = board
|
196
|
+
@id = id
|
197
|
+
@title = title
|
198
|
+
@last = last
|
199
|
+
end
|
200
|
+
|
201
|
+
def dat_url
|
202
|
+
@board.dat_url(@id)
|
203
|
+
end
|
204
|
+
|
110
205
|
end
|
111
206
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
207
|
+
module Shitaraba
|
208
|
+
SHITARABA_THREAD_URL_PATTERN = %r{\Ahttp://jbbs\.shitaraba\.net/bbs/read\.cgi/(\w+)/(\d+)/(\d+)(:?|\/.*)\z}
|
209
|
+
SHITARABA_BOARD_TOP_URL_PATTERN = %r{\Ahttp://jbbs\.shitaraba\.net/(\w+)/(\d+)/?\z}
|
210
|
+
|
211
|
+
# したらば板
|
212
|
+
class Board < Bbs::BoardBase
|
213
|
+
class << self
|
214
|
+
def from_url(url)
|
215
|
+
if url.to_s =~ SHITARABA_BOARD_TOP_URL_PATTERN
|
216
|
+
category, board_num = $1, $2.to_i
|
217
|
+
return Board.send(:new, category, board_num)
|
218
|
+
elsif url.to_s =~ SHITARABA_THREAD_URL_PATTERN
|
219
|
+
category, board_num, thread_num = $1, $2.to_i, $3.to_i
|
220
|
+
return Board.send(:new, category, board_num)
|
221
|
+
else
|
222
|
+
return nil
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def initialize(category, board_num)
|
228
|
+
super('EUC-JP')
|
229
|
+
@category = category
|
230
|
+
@board_num = board_num
|
231
|
+
@settings_url = URI.parse( "http://jbbs.shitaraba.net/bbs/api/setting.cgi/#{category}/#{board_num}/" )
|
232
|
+
@thread_list_url = URI.parse( "http://jbbs.shitaraba.net/#{category}/#{board_num}/subject.txt" )
|
233
|
+
end
|
234
|
+
|
235
|
+
def dat_url(thread_num)
|
236
|
+
return URI.parse("http://jbbs.shitaraba.net/bbs/rawmode.cgi/#{@category}/#{@board_num}/#{thread_num}/")
|
237
|
+
end
|
238
|
+
|
239
|
+
def create_thread_from_line(line)
|
240
|
+
Thread.from_line(line, self)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# したらばスレッド
|
245
|
+
class Thread < Bbs::ThreadBase
|
246
|
+
class << self
|
247
|
+
def from_url(url)
|
248
|
+
if url.to_s =~ SHITARABA_THREAD_URL_PATTERN
|
249
|
+
category, board_num, thread_num = $1, $2.to_i, $3.to_i
|
250
|
+
board = Board.send(:new, category, board_num)
|
251
|
+
thread = board.thread(thread_num)
|
252
|
+
raise 'no such thread' if thread.nil?
|
253
|
+
return thread
|
254
|
+
else
|
255
|
+
return nil
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def from_line(line, board)
|
260
|
+
unless line =~ /^(\d+)\.cgi,(.+?)\((\d+)\)$/
|
261
|
+
fail 'スレ一覧のフォーマットが変です'
|
262
|
+
end
|
263
|
+
id, title, last = $1.to_i, $2, $3.to_i
|
264
|
+
Thread.send(:new, board, id, title, last)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def initialize(board, id, title, last = 1)
|
269
|
+
super
|
270
|
+
end
|
271
|
+
|
272
|
+
def posts(range)
|
273
|
+
fail ArgumentError unless range.is_a? Range
|
274
|
+
dat_for_range(range).each_line.map do |line|
|
275
|
+
post = create_post(line.chomp)
|
276
|
+
@last = [post.no, last].max
|
277
|
+
post
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
private
|
282
|
+
|
283
|
+
def create_post(line)
|
284
|
+
no, name, mail, date, body, = line.split('<>', 6)
|
285
|
+
Post.new(no, name, mail, date, body)
|
286
|
+
end
|
287
|
+
|
288
|
+
def dat_for_range(range)
|
289
|
+
if range.last == Float::INFINITY
|
290
|
+
query = "#{range.first}-"
|
291
|
+
else
|
292
|
+
query = "#{range.first}-#{range.last}"
|
293
|
+
end
|
294
|
+
url = URI(dat_url + query)
|
295
|
+
@board.send(:download_text, url)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end # Shitaraba
|
299
|
+
|
300
|
+
module Nichan
|
301
|
+
# 2ちゃん板
|
302
|
+
class Board < Bbs::BoardBase
|
303
|
+
class << self
|
304
|
+
def from_url(url)
|
305
|
+
uri = URI.parse(url)
|
306
|
+
board_name = uri.path.split('/').reject(&:empty?).first
|
307
|
+
raise 'bad url' if board_name.nil?
|
308
|
+
Board.send(:new, uri.hostname, uri.port, board_name)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def initialize(hostname, port, name)
|
313
|
+
super('CP932')
|
314
|
+
@hostname, @port, @name = hostname, port, name
|
315
|
+
|
316
|
+
@settings_url = URI.parse("http://#{hostname}:#{port}/#{name}/SETTING.TXT")
|
317
|
+
@thread_list_url = URI.parse("http://#{hostname}:#{port}/#{name}/subject.txt")
|
318
|
+
end
|
319
|
+
|
320
|
+
def dat_url(thread_num)
|
321
|
+
"http://#{@hostname}:#{@port}/#{@name}/dat/#{thread_num}.dat"
|
322
|
+
end
|
323
|
+
|
324
|
+
def create_thread_from_line(line)
|
325
|
+
Thread.from_line(line, self)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
NICHAN_THREAD_URL_PATTERN = %r{\Ahttp://[a-zA-z\-\.]+/test/read\.cgi\/(\w+)/(\d+)($|/)}
|
330
|
+
|
331
|
+
# 2ちゃんスレッド
|
332
|
+
class Thread < ThreadBase
|
333
|
+
class << self
|
334
|
+
def from_url(url)
|
335
|
+
if url.to_s =~ NICHAN_THREAD_URL_PATTERN
|
336
|
+
board_name, thread_num = $1, $2.to_i
|
337
|
+
uri = URI(url)
|
338
|
+
board = Board.send(:new, uri.hostname, uri.port, board_name)
|
339
|
+
thread = board.thread(thread_num)
|
340
|
+
raise 'no such thread' if thread.nil?
|
341
|
+
return thread
|
342
|
+
else
|
343
|
+
raise 'bad URL'
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def from_line(line, board)
|
348
|
+
unless line =~ /^(\d+)\.dat<>(.+?) \((\d+)\)$/
|
349
|
+
fail 'スレ一覧のフォーマットが変です'
|
350
|
+
end
|
351
|
+
id, title, last = $1.to_i, $2, $3.to_i
|
352
|
+
Thread.send(:new, board, id, title, last)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def initialize(board, id, title, last = 1)
|
357
|
+
super
|
118
358
|
end
|
359
|
+
|
360
|
+
def posts(range)
|
361
|
+
fail ArgumentError unless range.is_a? Range
|
362
|
+
url = URI(dat_url)
|
363
|
+
lines = @board.send(:download_text, url)
|
364
|
+
ary = []
|
365
|
+
lines.each_line.with_index(1) do |line, res_no|
|
366
|
+
next unless range.include?(res_no)
|
367
|
+
|
368
|
+
name, mail, date, body, title = line.chomp.split('<>', 5)
|
369
|
+
post = Post.new(res_no.to_s, name, mail, date, body)
|
370
|
+
ary << post
|
371
|
+
@last = [post.no, last].max
|
372
|
+
end
|
373
|
+
return ary
|
374
|
+
end
|
375
|
+
|
119
376
|
end
|
377
|
+
|
120
378
|
end
|
121
379
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
380
|
+
# Bbs.create_board(url) → Shitaraba::Board | Nichan::Board
|
381
|
+
# Bbs.create_thread(url) → Shitaraba::Thread | Nichan::Thread
|
382
|
+
|
383
|
+
BOARD_CLASSES = [Shitaraba::Board, Nichan::Board].freeze
|
384
|
+
THREAD_CLASSES = [Shitaraba::Thread, Nichan::Thread].freeze
|
385
|
+
|
386
|
+
if $DEBUG
|
387
|
+
unless BOARD_CLASSES.all? { |k| k.respond_to?(:from_url) }
|
388
|
+
raise 'unmet assumption'
|
389
|
+
end
|
390
|
+
|
391
|
+
unless THREAD_CLASSES.all? { |k| k.respond_to?(:from_url) and k.respond_to?(:from_line) }
|
392
|
+
raise 'unmet assumption'
|
127
393
|
end
|
128
|
-
url = URI(dat_url + query)
|
129
|
-
@board.ダウンロード(url).force_encoding("EUC-JP").encode("UTF-8")
|
130
394
|
end
|
131
|
-
end
|
132
395
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
396
|
+
def create_board(url)
|
397
|
+
BOARD_CLASSES.each do |klass|
|
398
|
+
board = klass.from_url(url)
|
399
|
+
return board if board
|
400
|
+
end
|
401
|
+
return nil
|
402
|
+
end
|
403
|
+
module_function :create_board
|
139
404
|
|
140
|
-
|
405
|
+
def create_thread(url)
|
406
|
+
THREAD_CLASSES.each do |klass|
|
407
|
+
thread = klass.from_url(url)
|
408
|
+
return thread if thread
|
409
|
+
end
|
410
|
+
return nil
|
411
|
+
end
|
412
|
+
module_function :create_thread
|
141
413
|
|
414
|
+
end # Bbs
|
data/lib/bbiff/executable.rb
CHANGED
@@ -67,10 +67,18 @@ class Executable
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
def get_board_settings(board)
|
71
|
+
return board.settings
|
72
|
+
rescue Bbs::Downloader::DownloadFailure => e
|
73
|
+
STDERR.puts "Warning: 以下の場所から掲示板の設定が取得できませんでした。(#{e.response.message})"
|
74
|
+
STDERR.puts board.settings_url
|
75
|
+
return {'BBS_TITLE'=>'<不明>'}
|
76
|
+
end
|
77
|
+
|
70
78
|
def start_polling(thread, start_no)
|
71
79
|
out = LineIndicator.new
|
72
80
|
delay = @settings.current['delay_seconds']
|
73
|
-
board_settings = thread.board
|
81
|
+
board_settings = get_board_settings(thread.board)
|
74
82
|
thread_stop = (board_settings['BBS_THREAD_STOP'] || '1000').to_i
|
75
83
|
|
76
84
|
puts "#{board_settings['BBS_TITLE']} − #{thread.title}(#{thread.last})"
|
@@ -104,7 +112,9 @@ class Executable
|
|
104
112
|
rescue Interrupt
|
105
113
|
STDERR.puts "\nユーザー割り込みにより停止"
|
106
114
|
rescue => e
|
107
|
-
STDERR.puts "error occured
|
115
|
+
STDERR.puts "error occured"
|
116
|
+
puts e.message
|
117
|
+
puts e.backtrace
|
108
118
|
STDERR.puts "retrying..., ^C to quit"
|
109
119
|
sleep 3
|
110
120
|
start_polling(thread, start_no)
|
@@ -129,24 +139,20 @@ EOD
|
|
129
139
|
raise UsageError
|
130
140
|
elsif ARGV.size < 1
|
131
141
|
url = @settings.current['thread_url']
|
142
|
+
thread = Bbs::create_thread(url)
|
132
143
|
else
|
133
144
|
url = ARGV[0]
|
134
145
|
|
135
|
-
|
146
|
+
begin
|
147
|
+
thread = Bbs::create_thread(url)
|
136
148
|
@settings.current['thread_url'] = url
|
137
|
-
|
149
|
+
rescue
|
138
150
|
puts "URLが変です"
|
139
151
|
usage
|
140
152
|
exit 1
|
141
153
|
end
|
142
154
|
end
|
143
155
|
|
144
|
-
if url =~ %r{\Ah?ttp://jbbs.shitaraba.net/bbs/read.cgi/(\w+)/(\d+)/(\d+)/?\z}
|
145
|
-
ita = [$1, $2.to_i]
|
146
|
-
sure = $3.to_i
|
147
|
-
end
|
148
|
-
|
149
|
-
thread = Bbs::C板.new(*ita).thread(sure)
|
150
156
|
start_no = ARGV[1] ? ARGV[1].to_i : thread.last + 1
|
151
157
|
start_polling(thread, start_no)
|
152
158
|
rescue UsageError
|
data/lib/bbiff/res_format.rb
CHANGED
@@ -23,24 +23,6 @@ def render_resno(no)
|
|
23
23
|
no.to_s
|
24
24
|
end
|
25
25
|
|
26
|
-
def render_date(t)
|
27
|
-
weekday = [*'日月火水木金土'.each_char]
|
28
|
-
delta = Time.now - t
|
29
|
-
|
30
|
-
case delta
|
31
|
-
when 0...1
|
32
|
-
"たった今"
|
33
|
-
when 1...60
|
34
|
-
"#{delta.to_i}秒前"
|
35
|
-
when 60...3600
|
36
|
-
"#{(delta / 60).to_i}分前"
|
37
|
-
when 3600...(24 * 3600)
|
38
|
-
"#{(delta / 3600).to_i}時間前"
|
39
|
-
else
|
40
|
-
"%d/%d/%d(%s) %02d:%02d:%02d" % [t.year, t.month, t.day, weekday[t.wday], t.hour, t.min, t.sec]
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
26
|
def indent(n, text)
|
45
27
|
text.each_line.map { |line| n.en + line }.join
|
46
28
|
end
|
@@ -51,7 +33,7 @@ def render_body(body)
|
|
51
33
|
end
|
52
34
|
|
53
35
|
def render_post(post)
|
54
|
-
"#{render_resno post.no}:#{render_name post.name, post.mail}:#{
|
36
|
+
"#{render_resno post.no}:#{render_name post.name, post.mail}:#{post.date}\n" \
|
55
37
|
"#{render_body post.body}"
|
56
38
|
end
|
57
39
|
|
data/lib/bbiff/show.rb
CHANGED
@@ -16,7 +16,7 @@ class Show
|
|
16
16
|
end
|
17
17
|
|
18
18
|
title = ARGV[0]
|
19
|
-
post = Bbs::Post.
|
19
|
+
post = Bbs::Post.from_s(ARGV[1])
|
20
20
|
notify_send = ENV['BBIFF_NOTIFY_SEND'] ||
|
21
21
|
(`which #{NOTIFY_SEND}` != "" ? NOTIFY_SEND : 'echo')
|
22
22
|
system("#{notify_send} #{Shellwords.escape(title)} #{Shellwords.escape(render_post(post))}")
|
data/lib/bbiff/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bbiff
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yoteichi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|