Skip to content
Snippets Groups Projects
Commit be205948 authored by echicken's avatar echicken
Browse files

Rewritten.

Provides a 'Feed' object, which loads an RSS or Atom feed and provides an API for accessing the details of channels/feeds and their items/entries.
parent 312bafb9
Branches
Tags
No related merge requests found
load("http.js"); /* Provides the Feed object, representing a loaded RSS or Atom feed.
var getFeed = function(url) { Usage Example:
var httpRequest = new HTTPRequest();
var response = httpRequest.Get(url);
if(
typeof response == "undefined"
||
response === null
||
response == ""
) {
throw "Empty response";
}
response = response.replace(/^<\?xml.*\?>/g, "");
response = response.replace(/<feed.*>/g, "<feed>");
response = response.replace(/<\/?rss.*>/g, "");
return new XML(response);
}
var objectsMatch = function(obj1, obj2) { load("sbbsdefs.js");
for(var property in obj1) { load("rss-atom.js");
if(!obj2.hasOwnProperty(property) || obj1[property] != obj2[property]) console.clear(BG_BLACK|LIGHTGRAY);
return false; var f = new Feed("http://bbs.electronicchicken.com/rss/bullshitrss.xml");
} for(var c = 0; c < f.channels.length; c++) {
for(var property in obj2) { console.putmsg(f.channels[c].title + "\r\n");
if(!obj1.hasOwnProperty(property)) console.putmsg(f.channels[c].updated + "\r\n");
return false; for(var i = 0; i < f.channels[c].items.length; i++) {
} console.putmsg(f.channels[c].items[i].title + "\r\n");
return true; console.putmsg(f.channels[c].items[i].author + "\r\n");
} console.putmsg(f.channels[c].items[i].date + "\r\n");
console.putmsg(f.channels[c].items[i].body + "\r\n");
var RSS = function(url) { console.putmsg("---\r\n");
var updated = false;
this.__defineGetter__(
"updated",
function() {
var ret = updated;
if(updated)
updated = false;
return ret;
} }
); console.putmsg("---\r\n");
this.properties = {
title : "",
link : "",
description : "",
language : "",
copyright : "",
managingEditor : "",
webMaster : "",
pubDate : "",
lastBuildDate : "",
category : "",
generator : "",
docs : "",
cloud : "",
ttl : "",
image : "",
rating : "",
textInput : "",
skipHours : "",
skipDays : "",
url : (typeof url == "undefined") ? "" : url
};
var Item = function(xmlObj) {
this.properties = {
title : "",
link : "",
description : "",
author : "",
category : "",
comments : "",
enclosure : "",
guid : "",
pubDate : "",
source : ""
};
for each(var element in xmlObj) {
if(element.name() == "pubDate") {
var d = new Date(element.toString());
this.properties[element.name()] = d.getTime() * .001;
} else {
this.properties[element.name()] = element;
}
}
if(this.properties.title == "" && this.properties.description == "")
throw "Invalid feed item";
} }
console.pause();
Properties:
Feed.channels (Array)
An array of 'Channel' objects, representing an RSS <channel />
or an Atom <feed />. (In most cases, you'll be dealing with
Feed.channels[0].)
Methods:
Feed.load();
Loads the feed via HTTP. This is called automatically upon
instantiation, however it is available as a public method if
you wish to reload the feed at any time.
Channel objects:
Each element in a Feed's 'channels' array is a Channel object. This
object represents an RSS channel or an Atom feed.
this.items = []; Properties:
this.load = function() { Channel.title (String)
if(this.properties.url == "")
throw "Feed URL not supplied"; The title of the channel/feed.
var feed = getFeed(this.properties.url);
for each(var element in feed) { Channel.description (String)
if(element.name() == "item") {
var item = new Item(element); The RSS <description /> or Atom <subtitle /> of this channel/feed.
var add = true;
for(var i = 0; i < this.items.length; i++) { Channel.link (String)
if(!objectsMatch(this.items[i].properties, item.properties))
continue; The <link /> of this channel/feed. (Note: this needs to be cleaned
add = false; up a bit. Presently if there are multiple <link /> elements, their
break; values will be concatenated into a single string.
}
if(add) { Channel.updated (String)
this.items.push(item);
updated = true; The RSS <lastBuildDate /> or Atom <updated /> value for this
} channel/feed. (Just a string for now.)
} else {
this.properties[element.name()] = element; Channel.items (Array)
}
} An array of Item objects, representing the articles/entries in the
channel/feed.
if(
this.properties.title == "" Item objects:
||
this.properties.link == "" Each element in a Feed's 'channels' array's 'items' array is an Item
|| object. This object represents an RSS <item /> or Atom <entry />.
this.properties.description == ""
) { Properties:
throw "Invalid feed";
} Item.id (String)
A unique identifier for this item. (RSS <guid />, Atom <id />)
Item.title (String)
The title of this item.
Item.date (String)
The date this item was last updated. (Just a string for now.)
Item.author (String)
The author of this item.
Item.body (String)
The RSS <description /> or Atom <summary /> for this item/entry.
Item.link (String)
The <link /> value for this item. (This needs cleaning up. If
there are multiple <link /> elements, their values are joined
into a single string.)
Item.extra (Object)
If the item/entry contains additional elements not provided for
above, they are tacked on to this object in case you may need
to access them. Presumably these will all be E4X XML objects.
*/
load("http.js");
// Hacky e4x namespace weirdness
var toLocal = function(xmlObject) {
for each(var element in xmlObject) {
element.setName(element.localName());
toLocal(element);
} }
} }
var Atom = function(url) { var Feed = function(url) {
var updated = false; var Item = function(xmlObject) {
this.__defineGetter__(
"updated", this.id = "";
function() { this.title = "";
var ret = updated; this.date = "";
if(updated) this.author = "";
updated = false; this.body = "";
return ret; this.link = "";
this.extra = {};
for each(var element in xmlObject) {
if(element.name() == "guid" || element.name() == "id")
this.id = element;
else if(element.name() == "title")
this.title = element;
else if(element.name() == "pubDate" || element.name() == "updated")
this.date = element;
else if(element.name() == "author")
this.author = element.text(); // To do: deal with Atom-style <author>
else if(element.name() == "description" || element.name() == "summary")
this.body = element;
else if(element.name() == "link")
this.link = element.text(); // To do: deal with multiple links
else
this.extra[element.name()] = element;
} }
);
this.properties = {
id : "",
title : "",
updated : "",
author : "",
link : "",
category : "",
contributor : "",
generator : "",
icon : "",
logo : "",
rights : "",
subtitle : "",
url : (typeof url == "undefined") ? "" : url
};
var toTimestamp = function(datestr) {
var yy = datestr.substring(0,4);
var mo = datestr.substring(5,7);
var dd = datestr.substring(8,10);
var hh = datestr.substring(11,13);
var mi = datestr.substring(14,16);
var ss = datestr.substring(17,19);
var tzs = datestr.substring(19,20);
// var tzhh = datestr.substring(20,22);
// var tzmi = datestr.substring(23,25);
var myutc = Date.UTC(yy-0,mo-1,dd-0,hh-0,mi-0,ss-0);
// var tzos = (tzs+(tzhh * 60 + tzmi * 1)) * 60000;
// var d = new Date(myutc-tzos);
var d = new Date(myutc);
return d.getTime() * .001;
} }
var Entry = function(xmlObj) { var Channel = function(xmlObject) {
this.properties = { this.title = "a";
id : "", this.description = "";
title : "", this.link = "";
updated : "", this.updated = "";
author : "", this.items = [];
content : "",
link : "", if(typeof xmlObject.title != "undefined")
summary : "", this.title = xmlObject.title;
category : "",
contributor : "", if(typeof xmlObject.description != "undefined")
published : "", this.description = xmlObject.description;
source : "", else if(typeof xmlObject.subtitle != "undefined")
rights : "" this.description = xmlObject.subtitle;
};
// To do: deal with multiple links
for each(var element in xmlObj) { if(typeof xmlObject.link != "undefined")
if(element.name() == "link" && element.hasOwnProperty("@href")) this.link = xmlObject.link.text();
this.properties[element.name()] = element.@href;
else if(element.name() == "updated" || element.name() == "published") if(typeof xmlObject.lastBuildDate != "undefined")
this.properties[element.name()] = toTimestamp(element.toString()); this.updated = xmlObject.lastBuildDate;
else else if(typeof xmlObject.updated != "undefined")
this.properties[element.name()] = element; this.updated = xmlObject.updated;
var items = xmlObject.elements("item");
for each(var item in items) {
this.items.push(new Item(item));
} }
if( var entries = xmlObject.elements("entry");
this.properties.id == "" for each(var entry in entries) {
|| this.items.push(new Item(entry));
this.properties.title == ""
||
this.properties.description == ""
) {
throw "Invalid feed item";
} }
} }
this.entries = []; this.channels = [];
this.load = function() { this.load = function() {
if(typeof this.properties.url == "undefined") var httpRequest = new HTTPRequest();
throw "Feed URL not supplied"; var response = httpRequest.Get(url);
var feed = getFeed(this.properties.url); if(typeof response == "undefined" || response == "")
for each(var element in feed) { throw "Empty response from server.";
if(element.name() == "entry") {
var entry = new Entry(element); var feed = new XML(response.replace(/^<\?xml.*\?>/g, ""));
var add = true; toLocal(feed); // This is shitty
for(var e = 0; e < this.entries.length; e++) { switch(feed.localName()) {
if(!objectsMatch(this.entries[e].properties, entry.properties)) case "rss":
continue; var channels = feed.elements("channel");
add = false; for each(var element in channels)
break; this.channels.push(new Channel(element));
} break;
if(add) { case "feed":
this.entries.push(new Entry(element)); this.channels.push(new Channel(feed));
updated = true; break;
} default:
} else if(element.name() == "updated") { break;
this.properties[element.name()] = toTimestamp(element);
} else {
this.properties[element.name()] = element;
}
}
if(
this.properties.id == ""
||
this.properties.title == ""
||
this.properties.updated == ""
) {
throw "Invalid feed";
} }
} }
} this.load();
\ No newline at end of file
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment