Sunday, April 10, 2011 at 1:07 AM.
radio2Suite.buildRss
on buildRss (adruser, adrfeed, maxitems=50, theDay=nil) { <<Changes <<4/9/11; 12:52:15 PM by DW <<Call the callback scripts at the end of the build. <<3/15/11; 10:33:18 AM by DW <<Get cloud prefs from the top level, not the feed. Makes no sense to have each feed specify its cloud without having a global pref. <<3/14/11; 3:52:54 PM by DW <<Support addNamespaceToRssFeed callbacks. <<3/12/11; 11:35:30 PM by DW <<If an item has an element named "thumbnail" add a media:thumbnail element, and declare the namespace at the top of the file. Fixed the names of sub-elements of microblog:archive. If we're about to output an item without a guid, synthesize one. <<3/12/11; 6:04:40 PM by DW <<The <generator> element now says Radio2 v0.51. Add a <docs> element. <<3/11/11; 4:48:16 AM by DW <<Callbacks. <<3/9/11; 1:54:53 AM by DW <<Only add the microblog:archive element if the calendar is non-empty. <<3/2/11; 7:34:05 PM by DW <<Stop the michegas with the guids and the enclosures. We have a better solution already in there. <<3/2/11; 8:04:32 AM by DW <<Cache the size and type in the stats sub-table for each item, so I don't have to get them via HTTP every time the feed is rebuilt. Cut down on network traffic. <<3/1/11; 2:02:31 PM by DW <<If guid is empty and the item has an enclosure, use its url as the guid. <<3/1/11; 8:48:23 AM by DW <<If adrfeed^.stats.htmlUrl is available use it in the channel-level link element. <<2/28/11; 3:57:54 PM by DW <<<microblog:archive> now contains <startDay> and <endDay> elements that tell when the calendar-structured archive begins and ends. <<2/28/11; 8:39:20 AM by DW <<Use radio2Suite.writeStaticFile to save the file. First support for <microblog:archive> element. Still need to establish <startDay>. <<2/25/11; 4:38:12 PM by DW <<Include the microblog namespace. <<2/24/11; 12:30:33 PM by DW <<Get guid from the item table, if it's available. If it's not, it's the same as link. <<2/22/11; 9:17:32 PM by DW <<Add optional param, theDay. If non-nil, only output items for that day, and save to a file in a calendar-structured folder. <<We ignore the maxItems param when doing a daily feed, we want to get them all, no matter what. <<No longer doing the legacy saves. Sorry to anyone who was subscribed to these feeds. <<2/18/11; 7:28:01 PM by DW <<If a shortened URL is available use it. <<2/9/11; 10:21:44 AM by DW <<Change default maxitems to 25. <<1/18/11; 7:14:48 PM by DW <<If title, link or description are empty, don't include them. <<1/13/11; 10:42:41 AM by DW <<Save the feed to the user's silo-safe bucket on S3. <<1/11/11; 11:50:23 AM by DW <<Made maxitems an optional param, defaults to 100. <<1/7/11; 9:39:41 AM by DW <<Both legacy saving options are now controlled by prefs. For everyone but me, these will always be disabled. A little bit of a mess to be cleaned up at a later date. <<12/14/10; 11:54:15 AM by DW <<Don't set the RSS url, we're making it a preference, not a stat. <<12/14/10; 11:44:08 AM by DW <<Use adrdata^.prefs.s3Path. <<12/29/09; 7:20:38 PM by DW <<Created. local (adrdata = radio2Suite.init (), rsstext = "", now = clock.now (), nownss = date.netstandardstring (now)); local (rssUrl, ctitems = 0, flMediaRssNamespace = false); radio2suite.initfeed (adrfeed); bundle { //build rsstext local (indentlevel = 0); on add (s, flskipifempty=false) { if flskipifempty { //3/11/11 by DW if sizeof (s) == 0 { return}}; rsstext = rsstext + string.filledstring ("\t", indentlevel) + s + "\r"}; on encode (s) { if system.environment.isMac { return (xml.entityEncode (latinToMac.macToLatin (s), true))} else { return (xml.entityEncode (s, true))}}; add ("<?xml version=\"1.0\"?>"); add ("<rss version=\"2.0\" xmlns:microblog=\"http://microblog.reallysimple.org/\"<%namespace%>>"); indentlevel++; add ("<channel>"); indentlevel++; bundle { //add header elements bundle { //title -- 2/22/11 by DW local (title = adrfeed^.prefs.title); if theDay != nil { title = title + " (" + date.shortstring (theDay) + ")"}; add ("<title>" + encode (title) + "</title>")}; bundle { //link -- 3/1/11 by DW local (link); if defined (adrfeed^.stats.htmlUrl) { link = adrfeed^.stats.htmlUrl} else { link = encode (adrfeed^.prefs.link)}; add ("<link>" + link + "</link>")}; add ("<description>" + encode (adrfeed^.prefs.description) + "</description>"); add ("<language>" + encode (adrfeed^.prefs.language) + "</language>"); bundle { //pubDate if theDay == nil { add ("<pubDate>" + nownss + "</pubDate>")} else { add ("<pubDate>" + date.netstandardstring (theDay) + "</pubDate>")}}; add ("<lastBuildDate>" + nownss + "</lastBuildDate>"); add ("<generator>" + radio2Info.name + " v" + radio2Info.version + "</generator>"); //3/12/11 by DW <<add ("<generator>" + frontier.getprogramname () + "</generator>") add ("<docs>http://cyber.law.harvard.edu/rss/rss.html</docs>"); //3/12/11 by DW bundle { //add cloud, 3/15/11 by DW with adrdata^.prefs.cloud { add ("<cloud domain=\"" + server + "\" port=\"" + port + "\" path=\"" + path + "\" registerProcedure=\"" + registerProcedure + "\" protocol=\"" + protocol + "\" />")}}; bundle { //archive, 2/28/11 by DW if defined (adrfeed^.stats.feedUrl) and (sizeof (adrfeed^.calendar) > 0) { on archiveDay (theDay) { local (day, month, year, hour, minute, second); date.get (theDay, @day, @month, @year, @hour, @minute, @second); return (year + "-" + string.padwithzeros (month, 2) + "-" + string.padwithzeros (day, 2))}; local (url = adrfeed^.stats.feedUrl, fname = string.lastfield (url, "/")); local (urlArchive = string.delete (url, sizeof (url) - sizeof (fname) + 1, sizeof (fname))); add ("<microblog:archive>"); indentlevel++; add ("<microblog:url>" + urlArchive + "</microblog:url>"); add ("<microblog:filename>" + fname + "</microblog:filename>"); add ("<microblog:startDay>" + archiveDay (mainresponder.calendar.getfirstday (@adrfeed^.calendar)) + "</microblog:startDay>"); add ("<microblog:endDay>" + archiveDay (mainresponder.calendar.getlastday (@adrfeed^.calendar)) + "</microblog:endDay>"); add ("</microblog:archive>"); indentlevel--}}; bundle { //callbacks, 3/11/11 by DW local (adrscript); for adrscript in @adrdata^.callbacks.addToRssChannel { while typeof (adrscript^) == addresstype { adrscript = adrscript^}; try { add (adrscript^ (adruser, adrfeed), true)}}}}; bundle { //add items local (adrcal = @adrfeed^.calendar); on visit (adritem) { local (fllinkfull = false); on addopt (name, val) { //1/18/11 by DW val = string.trimwhitespace (val); if sizeof (val) > 0 { add ("<" + name + ">" + encode (val) + "</" + name + ">")}}; add ("<item>"); indentlevel++; addopt ("title", adritem^.title); addopt ("description", adritem^.description); bundle { //link, 2/18/11 by DW if defined (adritem^.linkShortened) { addopt ("link", adritem^.linkShortened); fllinkfull = true} else { addopt ("link", adritem^.link)}}; if defined (adritem^.enclosure) { local (url = adritem^.enclosure); if sizeof (url) > 0 { local (type, length); if defined (adritem^.stats.enclosureType) { type = adritem^.stats.enclosureType; length = adritem^.stats.enclosureLength} else { tcp.httpGetTypeLength (url, @type, @length, 5); adritem^.stats.enclosureType = type; adritem^.stats.enclosureLength = length}; add ("<enclosure url=\"" + url + "\" length=\"" + length + "\" type=\"" + type + "\" />")}}; if defined (adritem^.thumbnail) { //3/12/11 by DW local (url = adritem^.thumbnail); if sizeof (url) > 0 { add ("<media:thumbnail url=\"" + url + "\" />"); flMediaRssNamespace = true}}; add ("<pubDate>" + date.netstandardstring (adritem^.when) + "</pubDate>"); bundle { //guid local (guid = ""); if defined (adritem^.guid) { //post was created on or after 2/24/11 guid = adritem^.guid} else { guid = adritem^.link}; //post was created before 2/24/11 if sizeof (guid) == 0 { //3/12/11 by DW add ("<guid isPermaLink=\"false\">" + encode (string.hashmd5 (string (adritem^.when))) + "</guid>")} else { add ("<guid>" + encode (guid) + "</guid>")}}; if fllinkfull { addopt ("microblog:linkFull", adritem^.link)}; //2/25/11 by DW bundle { //callbacks, 3/11/11 by DW local (adrscript); for adrscript in @adrdata^.callbacks.addToRssItem { while typeof (adrscript^) == addresstype { adrscript = adrscript^}; try { add (adrscript^ (adruser, adrfeed, adritem), true)}}}; add ("</item>"); indentlevel--; return (++ctitems < maxitems)}; //2/9/11 by DW if theDay == nil { mainresponder.calendar.visitReverseChronologic (adrcal, @visit)} else { local (adrday = mainresponder.calendar.getDayAddress (adrcal, theDay), i); for i = sizeof (adrday^) downto 1 { visit (@adrday^ [i])}}}; add ("</channel>"); indentlevel--; add ("</rss>"); indentlevel--}; bundle { //namespace substitution, 3/12/11 by DW local (ns = ""); if flMediaRssNamespace { ns = " xmlns:media=\"http://search.yahoo.com/mrss/\""}; bundle { //callbacks, 3/14/11 by DW local (adrscript); for adrscript in @adrdata^.callbacks.addNamespaceToRssFeed { while typeof (adrscript^) == addresstype { adrscript = adrscript^}; try { local (s = adrscript^ (adruser, adrfeed)); if sizeof (s) > 0 { ns = ns + " " + s}}}}; rsstext = string.replace (rsstext, "<%namespace%>", ns)}; bundle { //save the file if theDay == nil { local (url); url = radio2Suite.writeStaticFile (adruser, nameof (adrfeed^), rsstext, "text/plain"); //2/28/11 by DW adrfeed^.stats.feedUrl = url; adrfeed^.stats.ctSaves++; adrfeed^.stats.whenLastSave = now; bundle { //call the callbacks, 4/9/11 by DW local (adrscript); for adrscript in @adruser^.callbacks.buildRss { while typeof (adrscript^) == addresstype { adrscript = adrscript^}; try { adrscript^ (adruser, adrfeed, rsstext)}}}} else { local (replath = file.getdatepath ("/", theDay) + nameof (adrfeed^)); radio2Suite.writeStaticFile (adruser, replath, rsstext, "text/plain")}}; <<bundle //old code <<bundle //save it to S3 <<if adrdata^.prefs.s3enabled <<if theDay == nil <<local (replath = nameof (adruser^) + "/" + nameof (adrfeed^)) <<local (s3path = adrdata^.prefs.s3path + replath) <<s3.newobject (s3path, rsstext, "text/plain") <<adrfeed^.stats.feedUrl = adrdata^.prefs.s3url + replath <<adrfeed^.stats.ctSaves++ <<adrfeed^.stats.whenLastSave = now <<else <<local (s3path = adrdata^.prefs.s3path + nameof (adruser^) + "/" + file.getdatepath ("/", theDay) + nameof (adrfeed^)) <<s3.newobject (s3path, rsstext, "text/plain") <<bundle //save it to the user's S3 bucket, 1/13/11 by DW <<if adruser^.prefs.s3bucket.enabled and (adruser^.prefs.s3bucket.path != "") <<local (path = adruser^.prefs.s3bucket.path) <<if theDay == nil <<if not (path beginswith "/") <<path = "/" + path <<if not (path endswith "/") <<path = path + "/" <<s3.newobject (path + nameof (adrfeed^), rsstext, "text/plain") <<if adruser^.prefs.s3bucket.url != "" <<adrfeed^.stats.feedUrl = adruser^.prefs.s3bucket.url + nameof (adrfeed^) <<else <<adrfeed^.stats.feedUrl = "http://s3.amazonaws.com/" + path + nameof (adrfeed^) <<else <<s3.newobject (path + file.getdatepath ("/", theDay) + nameof (adrfeed^), rsstext, "text/plain") <<bundle //legacy saves, just for DW's first two feeds <<bundle //save it to S3 <<if defined (adrfeed^.prefs.s3Path) //1/7/11 by DW <<s3.newobject (adrfeed^.prefs.s3Path, rsstext) <<bundle //save in archive, 12/16/10 by DW <<local (path = adrfeed^.prefs.s3ArchivePath + file.getdatepath ("/", flLastSeparator:false) + ".xml") <<s3.newobject (path, rsstext) <<adrfeed^.stats.ctSaves++ <<adrfeed^.stats.whenLastSave = now <<bundle //save it to fresca, if enabled <<if defined (adrfeed^.prefs.fresca) <<if adrfeed^.prefs.fresca.enabled <<local (domain = adrfeed^.prefs.fresca.domain, path = adrfeed^.prefs.fresca.path) <<myServerFarmSuite.writeToFresca (domain, path + "rss.xml", rsstext) <<myServerFarmSuite.writeToFresca (domain, path + file.getdatepath ("/", flLastSeparator:false) + ".xml", rsstext) return (true)}; bundle { //test code buildRss (@config.radio2.users.dave, @config.radio2.users.dave.feeds.["linkblog.xml"])}
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.