rss2mail 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -1
- data/lib/rss2mail/feed.rb +73 -64
- data/lib/rss2mail/rss.rb +18 -9
- data/lib/rss2mail/version.rb +1 -1
- metadata +2 -2
data/README
CHANGED
data/lib/rss2mail/feed.rb
CHANGED
@@ -25,6 +25,7 @@
|
|
25
25
|
#++
|
26
26
|
|
27
27
|
require 'erb'
|
28
|
+
require 'open3'
|
28
29
|
require 'nuggets/file/which'
|
29
30
|
require 'nuggets/string/evaluate'
|
30
31
|
|
@@ -34,9 +35,15 @@ module RSS2Mail
|
|
34
35
|
|
35
36
|
include Util
|
36
37
|
|
37
|
-
|
38
|
+
unless MAIL = File.which(mail = 'mail'.freeze)
|
39
|
+
class << MAIL; self; end.send(:define_method, :to_s) { mail }
|
40
|
+
end
|
41
|
+
|
42
|
+
HOST = ENV['HOSTNAME'] || ENV['HOST'] || %x{hostname}.chomp.freeze
|
43
|
+
|
44
|
+
FROM = "From: rss2mail@#{HOST}".freeze
|
38
45
|
|
39
|
-
|
46
|
+
KEEP = 100
|
40
47
|
|
41
48
|
def initialize(feed, options = {})
|
42
49
|
raise TypeError, "Hash expected, got #{feed.class}" unless feed.is_a?(Hash)
|
@@ -50,19 +57,21 @@ module RSS2Mail
|
|
50
57
|
@debug = options[:debug]
|
51
58
|
|
52
59
|
required = [:url, :to, :title]
|
53
|
-
required.delete_if { |
|
60
|
+
required.delete_if { |key| feed.has_key?(key) }
|
54
61
|
|
55
|
-
|
62
|
+
unless required.empty?
|
63
|
+
raise ArgumentError, "Feed incomplete: #{required.join(', ')} missing"
|
64
|
+
end
|
56
65
|
end
|
57
66
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
67
|
+
attr_reader :feed, :simple, :updated,
|
68
|
+
:reload, :verbose, :debug,
|
69
|
+
:content, :rss
|
62
70
|
|
63
|
-
|
71
|
+
def deliver(templates)
|
72
|
+
raise "Mail command not found: #{MAIL}" unless MAIL
|
64
73
|
|
65
|
-
if to.empty?
|
74
|
+
if (to = Array(feed[:to])).empty?
|
66
75
|
log 'No one to send to'
|
67
76
|
return
|
68
77
|
end
|
@@ -72,58 +81,38 @@ module RSS2Mail
|
|
72
81
|
return
|
73
82
|
end
|
74
83
|
|
75
|
-
if rss.items.empty?
|
84
|
+
if (items = rss.items).empty?
|
76
85
|
log 'No new items'
|
77
86
|
return
|
78
87
|
end
|
79
88
|
|
80
|
-
|
81
|
-
encoding
|
82
|
-
|
83
|
-
feed[:sent] ||= []
|
89
|
+
type = feed[:content_type] || 'text/html'
|
90
|
+
encoding = feed[:encoding] || 'UTF-8'
|
84
91
|
|
85
|
-
|
92
|
+
type_header = "Content-type: #{type}; charset=#{encoding}"
|
86
93
|
|
87
|
-
unless template = templates[
|
88
|
-
log "Template not found: #{
|
94
|
+
unless template = templates[type[/\/(.*)/, 1]]
|
95
|
+
log "Template not found: #{type}"
|
89
96
|
return
|
90
97
|
end
|
91
98
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
sent = 0
|
102
|
-
|
103
|
-
rss.items.each { |item|
|
104
|
-
title = item.title
|
105
|
-
link = item.link
|
106
|
-
description = item.description(feed[:unescape_html])
|
107
|
-
date = item.date
|
108
|
-
author = item.author
|
109
|
-
body = item.body(feed[:body])
|
110
|
-
subject = item.subject
|
111
|
-
|
112
|
-
log "#{title} / #{date} [#{author}]", debug
|
113
|
-
log "<#{link}>", debug
|
114
|
-
|
115
|
-
send_mail(cmd.evaluate(binding), ERB.new(template).result(binding)) {
|
116
|
-
feed[:sent] << link
|
117
|
-
sent += 1
|
99
|
+
sent = feed[:sent] ||= []
|
100
|
+
count, title = 0, feed[:title]
|
101
|
+
|
102
|
+
items.each { |item|
|
103
|
+
link, subject, body = render(feed, item, template)
|
104
|
+
|
105
|
+
send_mail(type_header, to, title, subject, body) {
|
106
|
+
sent << link
|
107
|
+
count += 1
|
118
108
|
}
|
119
109
|
}
|
120
110
|
|
121
|
-
|
122
|
-
|
123
|
-
feed[:sent].slice!(0...-100)
|
111
|
+
sent.uniq!
|
112
|
+
sent.slice!(0...-KEEP)
|
124
113
|
|
125
|
-
log "#{
|
126
|
-
|
114
|
+
log "#{count} items sent"
|
115
|
+
count
|
127
116
|
end
|
128
117
|
|
129
118
|
private
|
@@ -169,25 +158,25 @@ module RSS2Mail
|
|
169
158
|
error err, 'while getting feed'
|
170
159
|
end
|
171
160
|
|
172
|
-
|
161
|
+
content
|
173
162
|
end
|
174
163
|
|
175
164
|
def parse(reload = reload)
|
176
165
|
@rss = nil if reload
|
177
166
|
|
178
|
-
if content
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
167
|
+
if content
|
168
|
+
@rss ||= RSS.feed(content, simple) { |err|
|
169
|
+
error err, 'while parsing feed'
|
170
|
+
}
|
171
|
+
|
172
|
+
if rss && !reload
|
173
|
+
sent = feed[:sent]
|
184
174
|
|
185
|
-
|
186
|
-
@rss.items.delete_if { |item|
|
175
|
+
rss.items.delete_if { |item|
|
187
176
|
if updated && date = item.date
|
188
177
|
date <= updated
|
189
|
-
|
190
|
-
sent
|
178
|
+
elsif sent
|
179
|
+
sent.include?(item.link)
|
191
180
|
end
|
192
181
|
}
|
193
182
|
end
|
@@ -195,15 +184,35 @@ module RSS2Mail
|
|
195
184
|
log 'Nothing to parse'
|
196
185
|
end
|
197
186
|
|
198
|
-
|
187
|
+
rss
|
199
188
|
end
|
200
189
|
|
201
|
-
def
|
190
|
+
def render(feed, item, template)
|
191
|
+
title = item.title
|
192
|
+
link = item.link
|
193
|
+
description = item.description(feed[:unescape_html])
|
194
|
+
date = item.date
|
195
|
+
author = item.author
|
196
|
+
body = item.body(feed[:body])
|
197
|
+
subject = item.subject
|
198
|
+
|
199
|
+
log "#{title} / #{date} [#{author}]", debug
|
200
|
+
log "<#{link}>", debug
|
201
|
+
|
202
|
+
[link, subject, ERB.new(template).result(binding)]
|
203
|
+
end
|
204
|
+
|
205
|
+
def send_mail(type_header, to, title, subject, body)
|
202
206
|
return if debug
|
203
207
|
|
204
|
-
|
208
|
+
Open3.popen3(MAIL, '-e', '-a', type_header, '-a', FROM,
|
209
|
+
'-s', "[#{title}] #{subject}", *to) { |mail, _, _|
|
210
|
+
mail.puts body
|
211
|
+
mail.close
|
212
|
+
}
|
213
|
+
|
205
214
|
yield if block_given?
|
206
|
-
rescue Errno::EPIPE => err
|
215
|
+
rescue Errno::EPIPE, IOError => err
|
207
216
|
error err, 'while sending mail', cmd
|
208
217
|
end
|
209
218
|
|
data/lib/rss2mail/rss.rb
CHANGED
@@ -43,20 +43,28 @@ module RSS2Mail
|
|
43
43
|
|
44
44
|
include Util
|
45
45
|
|
46
|
-
|
46
|
+
SUB = {
|
47
47
|
'–' => '--',
|
48
48
|
'«' => '<<',
|
49
49
|
'&' => '&'
|
50
50
|
}
|
51
51
|
|
52
|
-
|
52
|
+
SUB_RE = Regexp.union(*SUB.keys)
|
53
53
|
|
54
|
-
|
54
|
+
KEEP = %w[a p br h1 h2 h3 h4]
|
55
55
|
|
56
|
-
|
56
|
+
class << self
|
57
|
+
|
58
|
+
def parse(url, *args)
|
59
|
+
new(open_feed(url), *args)
|
60
|
+
end
|
61
|
+
|
62
|
+
def feed(*args)
|
63
|
+
new(*args)
|
64
|
+
rescue ::SimpleRSSError, ::RSS::NotWellFormedError => err
|
65
|
+
yield err if block_given?
|
66
|
+
end
|
57
67
|
|
58
|
-
def self.parse(url, *args)
|
59
|
-
new(open_feed(url), *args)
|
60
68
|
end
|
61
69
|
|
62
70
|
def initialize(content, simple = false)
|
@@ -66,6 +74,8 @@ module RSS2Mail
|
|
66
74
|
@rss = simple ? simple_parse : parse
|
67
75
|
end
|
68
76
|
|
77
|
+
attr_reader :content, :rss
|
78
|
+
|
69
79
|
def simple?
|
70
80
|
@simple
|
71
81
|
end
|
@@ -172,7 +182,7 @@ module RSS2Mail
|
|
172
182
|
else raise ArgumentError, "don't know how to handle tag of type #{tag.class}"
|
173
183
|
end
|
174
184
|
|
175
|
-
body.gsub!(/<\/?(.*?)>/) { |m| m if
|
185
|
+
body.gsub!(/<\/?(.*?)>/) { |m| m if KEEP.include?($1.split.first.downcase) }
|
176
186
|
body.gsub!(/<a\s+href=['"](?!http:).*?>(.*?)<\/a>/mi, '\1')
|
177
187
|
|
178
188
|
encoding ? Iconv.conv('UTF-8', encoding, body) : body
|
@@ -189,8 +199,7 @@ module RSS2Mail
|
|
189
199
|
|
190
200
|
def clean_subject(str)
|
191
201
|
str.replace_diacritics!
|
192
|
-
str.gsub!(
|
193
|
-
str.gsub!(/'/, "'\\\\''")
|
202
|
+
str.gsub!(SUB_RE) { |m| SUB[m] }
|
194
203
|
str.to_ascii
|
195
204
|
end
|
196
205
|
|
data/lib/rss2mail/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rss2mail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -107,7 +107,7 @@ rdoc_options:
|
|
107
107
|
- --line-numbers
|
108
108
|
- --all
|
109
109
|
- --title
|
110
|
-
- rss2mail Application documentation (v0.1.
|
110
|
+
- rss2mail Application documentation (v0.1.3)
|
111
111
|
- --main
|
112
112
|
- README
|
113
113
|
require_paths:
|