wcc-rss-notificator 0.1.0
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/README.md +36 -0
- data/assets/template.d/rss-content.html.erb +93 -0
- data/assets/template.d/rss-title.plain.erb +1 -0
- data/lib/wcc-rss-notificator.rb +162 -0
- metadata +68 -0
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
wcc-rss-notificator
|
2
|
+
===================
|
3
|
+
|
4
|
+
This adds Atom feed support to [wcc](https://github.com/cmur2/wcc) encapsulated
|
5
|
+
in a separate gem.
|
6
|
+
|
7
|
+
Note: Currently there is only one feed for all users/recipients.
|
8
|
+
|
9
|
+
What you need to add to your conf.yml:
|
10
|
+
|
11
|
+
conf:
|
12
|
+
[...]
|
13
|
+
# enable rss plugin
|
14
|
+
rss: {}
|
15
|
+
|
16
|
+
recipients:
|
17
|
+
[...]
|
18
|
+
- me:
|
19
|
+
[...]
|
20
|
+
# write updates to Atom feed
|
21
|
+
- rss:
|
22
|
+
# wcc needs write permission on this file/directory:
|
23
|
+
#file: <cache.d>/atom.xml
|
24
|
+
# mandatory option! - this allows you to use different
|
25
|
+
# (or same) databases for each recipient
|
26
|
+
db_name: me
|
27
|
+
# wcc will keep the N newest entries in your feed
|
28
|
+
#num_keep: 1000
|
29
|
+
feed:
|
30
|
+
# mandatory option! - Note that this is *NOT* your feed's
|
31
|
+
# url or something, this should be just an unique identifier:
|
32
|
+
id: http://www.example.com/my-feed/
|
33
|
+
#title: Your cool feed
|
34
|
+
#subtitle: About things
|
35
|
+
#link: # this now should be the feed's url
|
36
|
+
#alternate_link: # this may be a websites url (favicon comes from here)
|
@@ -0,0 +1,93 @@
|
|
1
|
+
<style type="text/css">
|
2
|
+
.msg {
|
3
|
+
font-size: 0.98em;
|
4
|
+
}
|
5
|
+
|
6
|
+
.diff {
|
7
|
+
font-size: 12px;
|
8
|
+
font-family: 'Bitstream Vera Sans Mono','Courier',monospace;
|
9
|
+
}
|
10
|
+
|
11
|
+
.diff ul {
|
12
|
+
list-style: none;
|
13
|
+
display: table;
|
14
|
+
padding: 0;
|
15
|
+
margin: 0.5em 0 0 0.5em;
|
16
|
+
border: 1px solid #CCCCCC;
|
17
|
+
}
|
18
|
+
|
19
|
+
.diff li {
|
20
|
+
padding: 0;
|
21
|
+
display: table-row;
|
22
|
+
margin: 0;
|
23
|
+
background: #f8f8ff;
|
24
|
+
}
|
25
|
+
|
26
|
+
.diff .new, .diff .old {
|
27
|
+
color: #999;
|
28
|
+
}
|
29
|
+
|
30
|
+
.diff .ins {
|
31
|
+
background: #dfd;
|
32
|
+
}
|
33
|
+
|
34
|
+
.diff .ins .x {
|
35
|
+
background: #8f8;
|
36
|
+
margin: 0;
|
37
|
+
padding: 0;
|
38
|
+
}
|
39
|
+
|
40
|
+
.diff .del {
|
41
|
+
background: #fdd;
|
42
|
+
}
|
43
|
+
|
44
|
+
.diff .del .x {
|
45
|
+
background: #faa;
|
46
|
+
margin: 0;
|
47
|
+
padding: 0;
|
48
|
+
}
|
49
|
+
|
50
|
+
.diff .range {
|
51
|
+
background: #eaf2f5;
|
52
|
+
color: #999;
|
53
|
+
}
|
54
|
+
|
55
|
+
.diff .other {
|
56
|
+
}
|
57
|
+
</style>
|
58
|
+
|
59
|
+
<% if data.diff.nil? %>
|
60
|
+
<div class="msg">
|
61
|
+
Checked <a href="<%= data.site.uri.to_s %>"><%= data.site.uri.to_s %></a> the first time so no diff was possible.
|
62
|
+
</div>
|
63
|
+
<% else %>
|
64
|
+
<div class="msg">
|
65
|
+
Change at <a href="<%= data.site.uri.to_s %>"><%= data.site.uri.to_s %></a> - diff follows:
|
66
|
+
</div>
|
67
|
+
<div class="diff">
|
68
|
+
<ul>
|
69
|
+
<% for o in data.diff.di %>
|
70
|
+
<% if o.status == :new %>
|
71
|
+
<li class="new">+++<%= o.text %></li>
|
72
|
+
<% elsif o.status == :old %>
|
73
|
+
<li class="old">---<%= o.text %></li>
|
74
|
+
<% elsif o.status == :range %>
|
75
|
+
<li class="range">@@<%= o.text %></li>
|
76
|
+
<% elsif o.status == :ins %>
|
77
|
+
<li class="ins">+ <%= o.html_hilite_text('x').lstrip %></li>
|
78
|
+
<% elsif o.status == :del %>
|
79
|
+
<li class="del">- <%= o.html_hilite_text('x').lstrip %></li>
|
80
|
+
<% else %>
|
81
|
+
<li class="other"> <%= o.text.substring(1).lstrip %></li>
|
82
|
+
<% end %>
|
83
|
+
<% end %>
|
84
|
+
</ul>
|
85
|
+
</div>
|
86
|
+
<div>
|
87
|
+
nHunks: <%= data.diff.nhunks %>,
|
88
|
+
nIns: <%= data.diff.ninsertions %>,
|
89
|
+
nDel: <%= data.diff.ndeletions %>,
|
90
|
+
nLinesC: <%= data.diff.nlinesc %>,
|
91
|
+
nCharsC: <%= data.diff.ncharsc %>
|
92
|
+
</div>
|
93
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= data.site.uri.host %> changed
|
@@ -0,0 +1,162 @@
|
|
1
|
+
|
2
|
+
require 'rss/maker'
|
3
|
+
require 'socket' # only for getting hostname
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
class RSSNotificator
|
7
|
+
@@tpl = {}
|
8
|
+
@@shutdown_hooks = []
|
9
|
+
|
10
|
+
# TODO: can we hook into --clean?
|
11
|
+
|
12
|
+
def initialize(opts)
|
13
|
+
@dirty = false
|
14
|
+
if opts.is_a?(Hash)
|
15
|
+
@file = opts['file'] || WCC::Conf.file("atom.xml")
|
16
|
+
@db_name = opts['db_name']
|
17
|
+
@num_keep = opts['num_keep'] || 1000
|
18
|
+
@feed = {}
|
19
|
+
if opts['feed'].is_a?(Hash)
|
20
|
+
@feed = {
|
21
|
+
:title => opts['feed']['title'] || "wcc Updates Feed - #{Socket.gethostname}",
|
22
|
+
:subtitle => opts['feed']['subtitle'] || "The newest changes to your watched sites.",
|
23
|
+
:link => opts['feed']['link'],
|
24
|
+
:alt_link => opts['feed']['alternate_link'],
|
25
|
+
:id => opts['feed']['id']
|
26
|
+
}
|
27
|
+
end
|
28
|
+
if @feed[:id].nil?
|
29
|
+
raise ArgumentError, "Missing atom feed ID!"
|
30
|
+
end
|
31
|
+
if @db_name.nil?
|
32
|
+
raise ArgumentError, "Missing db name for atom feed!"
|
33
|
+
end
|
34
|
+
else
|
35
|
+
raise ArgumentError, "No options given for 'rss:' way of a recipient! Need at least db name and feed id."
|
36
|
+
end
|
37
|
+
@@shutdown_hooks << self
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_feeddb
|
41
|
+
if @feeddb.nil?
|
42
|
+
feeddb_file = WCC::Conf.file("feed-db-#{@db_name}.yml")
|
43
|
+
WCC.logger.debug "Loading feed-db '#{@db_name}' from file '#{feeddb_file}'"
|
44
|
+
if not File.exists?(feeddb_file)
|
45
|
+
WCC.logger.warn "Feed-db '#{@db_name}' does not exist, will create it on save in '#{feeddb_file}'"
|
46
|
+
@feeddb = {'feed' => []}
|
47
|
+
else
|
48
|
+
# may be false if file is empty
|
49
|
+
@feeddb = YAML.load_file(feeddb_file)
|
50
|
+
if not @feeddb.is_a?(Hash)
|
51
|
+
WCC.logger.warn "Feed-db '#{@db_name}' is corrupt, will overwrite it on save"
|
52
|
+
@feeddb = {'feed' => []}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
@feeddb
|
57
|
+
end
|
58
|
+
|
59
|
+
def notify!(data)
|
60
|
+
title = self.class.get_tpl(:title, 'rss-title.plain.erb').result(binding)
|
61
|
+
# remove trailing whitespace introduced by template
|
62
|
+
title.strip!
|
63
|
+
content = self.class.get_tpl(:content, 'rss-content.html.erb').result(binding)
|
64
|
+
id = "#{@feed['id']}item/#{Time.now.to_f}"
|
65
|
+
|
66
|
+
# append entries to class variable (not thread safe)
|
67
|
+
@dirty = true
|
68
|
+
feed = get_feeddb['feed']
|
69
|
+
feed.insert 0, {
|
70
|
+
'title' => title,
|
71
|
+
#'description' => '', # summary
|
72
|
+
'content' => content,
|
73
|
+
'link' => data.site.uri.to_s,
|
74
|
+
'id' => id,
|
75
|
+
'updated' => Time.now.to_s
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def shut_down
|
80
|
+
return unless @dirty
|
81
|
+
|
82
|
+
WCC.logger.debug "Writing feed-db '#{@db_name}' to file"
|
83
|
+
|
84
|
+
feeddb_file = WCC::Conf.file("feed-db-#{@db_name}.yml")
|
85
|
+
feeddb = get_feeddb
|
86
|
+
# auto-purge
|
87
|
+
feeddb['feed'] = feeddb['feed'].slice(0, @num_keep)
|
88
|
+
File.open(feeddb_file, 'w+') do |f| YAML.dump(feeddb, f) end
|
89
|
+
|
90
|
+
WCC.logger.info "Generating feed '#{@file}'..."
|
91
|
+
|
92
|
+
content = RSS::Maker.make('atom') do |m|
|
93
|
+
m.channel.title = @feed[:title]
|
94
|
+
m.channel.subtitle = @feed[:subtitle]
|
95
|
+
m.channel.author = "web change checker (aka wcc) #{WCC::VERSION}"
|
96
|
+
if not @feed[:link].nil?
|
97
|
+
m.channel.links.new_link do |li|
|
98
|
+
li.rel = "self"
|
99
|
+
li.type = "application/atom+xml"
|
100
|
+
li.href = @feed[:link]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
if not @feed[:alternate_link].nil?
|
104
|
+
m.channel.links.new_link do |li|
|
105
|
+
li.rel = "alternate"
|
106
|
+
li.type = "text/html"
|
107
|
+
li.href = @feed[:alternate_link]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
m.channel.id = @feed[:id]
|
111
|
+
m.channel.updated = Time.now.to_s
|
112
|
+
m.items.do_sort = true # sort items by date
|
113
|
+
|
114
|
+
# feeddb-hash to atom
|
115
|
+
feeddb['feed'].each do |e|
|
116
|
+
m.items.new_item do |i|
|
117
|
+
i.title = e['title']
|
118
|
+
#i.description = e['description']
|
119
|
+
i.content.content = e['content']
|
120
|
+
i.content.type = "html"
|
121
|
+
i.author = "wcc"
|
122
|
+
if not e['link'].nil?
|
123
|
+
i.links.new_link do |li|
|
124
|
+
li.rel = "alternate"
|
125
|
+
li.type = "text/html"
|
126
|
+
li.href = e['link']
|
127
|
+
end
|
128
|
+
end
|
129
|
+
i.id = e['id']
|
130
|
+
i.updated = e['updated']
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
File.open(@file, 'w+') do |f| f.write(content.to_s) end
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.parse_conf(conf); {} end
|
139
|
+
|
140
|
+
def self.shut_down
|
141
|
+
@@shutdown_hooks.each do |s| s.shut_down end
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.get_tpl(id, name)
|
145
|
+
if @@tpl[id].nil?
|
146
|
+
@@tpl[id] = WCC::Prog.load_template(name)
|
147
|
+
if @@tpl[id].nil?
|
148
|
+
src_path = Pathname.new(__FILE__) + "../../assets/template.d/#{name}"
|
149
|
+
t = File.open(src_path, 'r') { |f| f.read }
|
150
|
+
WCC::Prog.save_template(name, t)
|
151
|
+
# retry load
|
152
|
+
@@tpl[id] = WCC::Prog.load_template(name)
|
153
|
+
end
|
154
|
+
if @@tpl[id].nil?
|
155
|
+
@@tpl[id] = ERB.new("ERROR LOADING TEMPLATE '#{name}'!", 0, "<>")
|
156
|
+
end
|
157
|
+
end
|
158
|
+
@@tpl[id]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
WCC::Notificators.map "rss", RSSNotificator
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wcc-rss-notificator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Christian Nicolai
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-03-25 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email: chrnicolai@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- assets/template.d/rss-content.html.erb
|
31
|
+
- assets/template.d/rss-title.plain.erb
|
32
|
+
- lib/wcc-rss-notificator.rb
|
33
|
+
- README.md
|
34
|
+
homepage: https://github.com/cmur2/wcc-rss-notificator
|
35
|
+
licenses: []
|
36
|
+
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
hash: 3
|
48
|
+
segments:
|
49
|
+
- 0
|
50
|
+
version: "0"
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project: wcc-rss-notificator
|
63
|
+
rubygems_version: 1.8.6
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: RSS feed notificator plugin for wcc
|
67
|
+
test_files: []
|
68
|
+
|