feeds.lua

changeset 3
ab02540afcf3
parent 0
319733864f05
child 5
58d3cecc68b7
equal deleted inserted replaced
2:c04d4fd34685 3:ab02540afcf3
1 local io = io; 1 local io, string = io, string;
2 local error = error;
3 local print = print;
4
2 local http = require "socket.http"; 5 local http = require "socket.http";
3 local st = require "stanza"; 6 local st = require "stanza";
4 local new_stream = require "xmppstream".new; 7 local new_stream = require "xmppstream".new;
5 8
6 local xmlns_atom = "http://www.w3.org/2005/Atom"; 9 local xmlns_atom = "http://www.w3.org/2005/Atom";
7 10
8 module "feeds" 11 module "feeds"
9 12
13 local translate_entry = {};
14
15 function translate_entry.atom(feed, stanza)
16 if stanza.name == "entry" then
17 feed[#feed+1] = stanza;
18 else
19 feed[stanza.name] = stanza:get_text();
20 end
21 end
22
23 -- RSS->Atom translator
24
25 -- Helpers to translate item child elements
26 local rss2atom = {};
27 function rss2atom.title(atom_entry, tag)
28 atom_entry:tag("title"):text(tag:get_text()):up();
29 end
30
31 function rss2atom.link(atom_entry, tag)
32 atom_entry:tag("link", { href = tag:get_text() }):up();
33 end
34
35 function rss2atom.author(atom_entry, tag)
36 atom_entry:tag("author")
37 :tag("email"):text(tag:get_text()):up()
38 :up();
39 end
40
41 function rss2atom.guid(atom_entry, tag)
42 atom_entry:tag("id"):text(tag:get_text()):up();
43 end
44
45 function rss2atom.category(atom_entry, tag)
46 atom_entry:tag("category", { term = tag:get_text(), scheme = tag.attr.domain }):up();
47 end
48
49 function rss2atom.description(atom_entry, tag)
50 atom_entry:tag("summary"):text(tag:get_text()):up();
51 end
52
53 local months = {
54 jan = "01", feb = "02", mar = "03", apr = "04", may = "05", jun = "06";
55 jul = "07", aug = "08", sep = "09", oct = "10", nov = "11", dec = "12";
56 };
57
58 function rss2atom.pubDate(atom_entry, tag)
59 local pubdate = tag:get_text():gsub("^%a+,", ""):gsub("^%s*", "");
60 local date, month, year, hour, minute, second, zone =
61 pubdate:match("^(%d%d?) (%a+) (%d+) (%d+):(%d+):?(%d*) ?(.*)$");
62 if not date then return; end
63 if #date == 1 then
64 date = "0"..date;
65 end
66 month = months[month:sub(1,3):lower()];
67 if #year == 2 then -- GAH!
68 if tonumber(year) > 80 then
69 year = "19"..year;
70 else
71 year = "20"..year;
72 end
73 end
74 if zone == "UT" or zone == "GMT" then zone = "Z"; end
75 if #second == 0 then
76 second = "00";
77 end
78 local date_string = string.format("%s-%s-%sT%s:%s:%s%s", year, month, date, hour, minute, second, zone);
79 atom_entry:tag("published"):text(date_string):up();
80 end
81
82 -- Translate a single item to atom
83 function translate_entry.rss(feed, stanza)
84 if stanza.name == "item" then
85 local atom_entry = st.stanza("entry", { xmlns = xmlns_atom });
86 for tag in stanza:childtags() do
87 local translator = rss2atom[tag.name];
88 if translator then
89 translator(atom_entry, tag);
90 end
91 end
92 translate_entry.atom(feed, atom_entry:reset());
93 else
94 translate_entry.atom(feed, stanza);
95 end
96 end
97
10 local function new_feed_stream(feed) 98 local function new_feed_stream(feed)
11 local callbacks = { 99 local callbacks = {
12 default_ns = xmlns_atom; 100 streamopened = function (feed, attr, name)
13 stream_ns = xmlns_atom; stream_tag = "feed"; 101 if name == "feed" and attr.xmlns == xmlns_atom then
14 102 feed.type = "atom";
15 streamopened = function (feed, attr) 103 feed.xmlns = xmlns_atom;
16 feed.notopen = nil; 104 feed.notopen = nil;
105 elseif name == "rss" and attr.xmlns == "" then
106 feed.type = "rss";
107 feed.xmlns = "";
108 -- Don't open until channel
109 elseif feed.type == "rss" and name == "channel" and attr.xmlns == feed.xmlns then
110 feed.notopen = nil;
111 else
112 error("Unsupported feed type: <"
113 ..name
114 ..(attr.xmlns and (" xmlns='"..attr.xmlns.."'") or "")
115 ..">"
116 );
117 end
17 end; 118 end;
18 119
19 streamclosed = function (feed) 120 streamclosed = function (feed)
20 end; 121 end;
21 122
22 handlestanza = function (feed, stanza) 123 handlestanza = function (feed, stanza)
23 -- Skip tags not in the feed's default namespace 124 -- Skip tags not in the feed's default namespace
24 if stanza.attr.xmlns ~= nil then 125 if stanza.attr.xmlns ~= feed.xmlns then
25 return; 126 return;
26 end 127 end
27 128
28 if stanza.name == "entry" then 129 translate_entry[feed.type](feed, stanza);
29 feed[#feed+1] = stanza; 130 end;
30 else 131
31 feed[stanza.name] = stanza:get_text(); 132 error = function (feed, err, d)
32 end 133 error(err..": "..d);
33 end; 134 end;
34 }; 135 };
35 136
36 return new_stream(feed, callbacks); 137 return new_stream(feed, callbacks);
37 end 138 end

mercurial