Monday, November 08, 2010 at 12:05 AM.

on publishCategoryRss (flOnlyWriteChanges = true) {
		<<1/20/03; 5:41:21 PM by DW
			<<Set a "thread" global so that callback scripts can tell which category the RSS is being generated for. To get the address of the category:
				<<adrcat = ["_adrcat_"]
			<<More information about thread globals is in the comment at the head of this script:
		<<3/12/02; 2:59:11 PM by JES
			<<Implement a getUrl callback to be called by radio.weblog.writeRssFile. The callback determines the url for a given post, and returns true if the url can be determined, or false if not.
		<<1/20/02; 11:10:12 AM by DW
			<<Overhaul. Calls radio.weblog.writeRssFile to generate the RSS file. Caught a lot of inconsistencies here. Now we have one place to upgrade if we need to fix bugs or add features.
			<<Old code is here.
				<<local (xmltext = "")
				<<bundle //build xmltext
					<<local (indentlevel = 0)
					<<on add (s)
						<<xmltext = xmltext + string.filledstring ("\t", indentlevel) + s + "\r\n"
					<<add ("<?xml version=\"1.0\"?>")
					<<add ("<!-- RSS generated by Radio UserLand v" + frontier.version () + " on " + date.netstandardstring (now) + " -->")
					<<add ("<rss version=\"0.92\">"); indentlevel++
					<<add ("<channel>"); indentlevel++
					<<add ("<title>" + encode ( + ": " + adrcat^.displayName) + "</title>")
					<<add ("<link>" + htmlUrl + "</link>")
					<<if defined (adrcat^.description)
						<<add ("<description>" + encode (adrcat^.description) + "</description>")
					<<add ("<language>" + "xxx" + "</language>")
					<<add ("<copyright>" + "Copyright " + date.year () + " " + adrblog^.prefs.authorName + "</copyright>")
					<<add ("<lastBuildDate>" + date.netstandardstring (now) + "</lastBuildDate>")
					<<add ("<docs></docs>")
					<<add ("<managingEditor>" + encode (adrblog^.prefs.managingEditor) + "</managingEditor>")
					<<add ("<webMaster>" + encode (adrblog^.prefs.webmaster) + "</webMaster>")
					<<bundle //add cloud element
							<<add ("<cloud domain=\"" + server + "\" port=\"" + port + "\" path=\"" + path + "\" registerProcedure=\"" + registerProcedure + "\" protocol=\"" + protocol + "\"/>")
					<<bundle //add the items
						<<local (storyname, ctitems = 0, i)
						<<for i = sizeof (adrcat^.storylist) downto 1
							<<local (storynum = adrcat^.storylist [i])
							<<local (adrpost = @adrblog^.posts.[string.padwithzeros (storynum, 8)])
							<<if defined (adrpost^)
								<<add ("<item>"); indentlevel++
								<<add ("<description>" + encode (string (adrpost^.text)) + "</description>")
								<<if defined (adrpost^.sourceName) and defined (adrpost^.sourceUrl)
									<<add ("<source url=\"" + encode (adrpost^.sourceUrl) + "\">" + encode (adrpost^.sourceName) + "</source>")
								<<if defined (adrpost^.enclosure)
									<<if defined (adrpost^.enclosure.length) //05/28/01; JES: length may be undefined if the URL could not be read -- don't generate an error
										<<with adrpost^.enclosure
											<<add ("<enclosure url=\"" + url + "\" length=\"" + length + "\" type=\"" + type + "\"/>")
								<<add ("</item>"); indentlevel--
								<<if ++ctitems >= adrblog^.prefs.maxOutputItemsPerChannel
					<<add ("</channel>"); indentlevel--
					<<add ("</rss>"); indentlevel--
					<<xmltext = enableCurlyBraces (xmltext)
		<<12/20/01; 2:08:35 AM by JES
			<<Use file.writeTextFile instead of file.writeWholeFile to write the RSS.
		<<12/9/01; 12:42:35 PM by DW
			<<Get in synch with radio.weblog.publishRss, they have the same parts, similar values.
		<<12/7/01; 11:21:48 AM by JES
			<<Undid the last change. Category RSS files need to be stored in their own folders so that you can give them their own upstream locations by dropping a #upstream.xml in the folder.
		<<12/6/01; 11:23:56 PM by JES
			<<Changed the location of RSS files. Now they're stored in the rss folder specified in your prefs, with a filename which corresponds to adrcat^.filename, instead of storing the rss in a sub-folder named adrcat^.filename.
		<<11/14/01; 12:44:00 PM by JES
			<<Don't build the html files here. This is now done via radio.weblog.publish. Save the rss.xml file in the category's folder instead of in a file named for the category.
			<<Store the correct html and rss urls in the category's table. Use the correct html url for <link> in the xml rendering.
		<<10/28/01; 10:37:35 AM by DW
			<<Set adrcat^.htmlUrl unconditionally. For some reason it would only set the URL if it wasn't already defined. That means that if you change the location of a file, the URL wouldn't change. Watch for breakage.
		<<10/19/01; 3:09:50 AM by JES
			<<Moved changes from radio.weblog.generateOutputChannels to here. This was the correct place to make category publishing work.
		<<10/8/01; 6:40:14 PM by JES
			<<Ported from myUserLandSuite.generateOutputChannels. Removed "temporary band-aids" (yay!).
		<<Changes before 10/8/01
			<<Wednesday, December 20, 2000 at 2:00:00 PM by DW
			<<Thursday, December 28, 2000 at 4:47:53 PM by DW
				<<The <link> element in the RSS file had the incorrect filename. 
			<<1/5/01; 11:31:25 AM by DW
				<<Add support for <cloud>.
			<<1/6/01; 5:13:06 PM by DW
				<<Respect myUserLandData.prefs.maxOutputItemsPerChannel.
			<<1/13/01; 8:38:28 AM by DW
				<<Clear the dirty bit on channels after generating. This bug was causing every channel to rebuild every time one channel changed.
			<<1/21/01; 2:48:41 PM by DW
				<<Major rewrite. 
				<<Loose-end, setting the rssUrl in the category.
				<<Blog post tables need to have information for the source. Right now they don't and we don't generate the <source> element.
			<<1/22/01; 11:30:26 AM by DW
				<<Use user.playlist.prefs.wwwUpstreamFolderUrl to set the rssUrl element in every category.
			<<1/22/01; 1:18:58 PM by DW
				<<Whew! Now we write out the <souce> element. That was tricky.
			<<1/22/01; 3:22:59 PM by DW
				<<Make sure all categories have flDirty booleans. It's a temporary band-aid.
			<<1/23/01; 12:53:11 AM by DW
				<<Make sure all categories have storyList lists. It's a temporary band-aid.
			<<1/25/01; 2:20:13 PM by DW
				<<Let blog.publish do the HTML rendering.
			<<2/22/01; 9:49:31 PM by JES
				<<If this is a Mac, convert strings in the RSS XML to Latin text.
			<<3/1/01; 11:44:29 PM by JES
				<<Use instead of hard-coding 'Radu'.
			<<3/4/01; 6:38:58 PM by JES
				<<The <title> tag now contains the displayName of the category, instead of the name of its table.
			<<3/4/01; 11:44:27 PM by JES
				<<Removed \r\n from the begining of both the RSS and the HTML renderings. Set adrcat^.rss to the rendered RSS text, since it's used by myUserLandSuite.html.viewXmlSource when clicking the XML button for a category on the Categories page.
			<<5/28/01; 11:39:05 PM by JES
				<<Add <enclosure> in a try block, since if the URL could not be read, length will be undefined, which will cause an error window to continusouly, and annoyingly pop up.
	local (adrblog = radio.weblog.init ());
	local (rssfolder = radio.file.getAbsolutePath (adrblog^.prefs.rssCategoryFolderPath));
	local (htmlfolder = radio.file.getAbsolutePath (adrblog^.prefs.htmlCategoryFolderPath));
	local (adrcat, flwrite);
	for adrcat in @adrblog^.categories {
		flwrite = true;
		if flOnlyWriteChanges {
			if not adrcat^.fldirty {
				flwrite = false}};
		if flwrite {
			local (htmlurl = radio.upstream.getFileUrl (htmlfolder + adrcat^.filename + file.getpathchar ()));
			bundle { //1/20/03 by DW -- set thread global
				["_adrcat_"] = adrcat};
			adrcat^.htmlUrl = htmlurl;
			local (title = + ": " + adrcat^.displayName, description = "", language = "none");
			if defined (adrcat^.description) {
				description = adrcat^.description};
			if defined (adrcat^.language) {
				language = adrcat^.language};
			local (f = rssfolder + adrcat^.filename + file.getpathchar () + "rss.xml");
			adrcat^.rssUrl = radio.upstream.getFileUrl (f);
			on callback (adrpost) { //return true if the post is included
				return (adrcat^.storylist contains number (nameof (adrpost^)))};
			on getUrlCallback (adrpost, adrurl) { //return true if adrurl^ could be set
				return (radio.weblog.getUrlForPost (adrpost, adrurl, nameOf (adrcat^), adrblog) )};
			local (xmltext = radio.weblog.writeRssFile (f, title, htmlurl, description, language, adrcallback:@callback, adrblog:adrblog, adrGetUrlCallback:@getUrlCallback));
			wp.newtextobject (xmltext, @adrcat^.rss); //03/04/2001 JES: this is used by myUserLandSuite.html.viewXmlSource, when clicking the XML button for a category on the Categories page
			adrcat^.dateLastUpload = ();
			adrcat^.flDirty = false}}}
<<bundle //test code
	<<local (tc = clock.ticks ())
	<<weblogData.categories.test.flDirty = true
	<<publishCategoryRss ()
	<<dialog.alert (clock.ticks () - tc)

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.