View this PageEdit this Page (locked)Uploads to this PageVersions of this PageHomeRecent ChangesSearchHelp Guide

SwikiRssFeed

These are my suggestion for someone's wish "It would be a real time saver if Swiki had the ability to create a RSS feed."

Tip #1: Creating a new swiki providing RSS feed


Download: rssdoc.tar.gz

Example: http://linux.dnip.net/public/rss http://211.252.155.107:8888/squeak/rss

  1. Create a new swiki named, for example, "rssdoc"
  2. Using SwikiBrowser, add following templates for new "rssdoc" swiki:
    1. addresses(book)-rss
    2. actions(book)-description
    3. actions(book)-url
    4. actions(page)-description
    5. actions(page)-iso8601Date
    6. actions(page)-timeStamp
  3. Create a new swiki inheriting rssdoc (which in turn inherits from 'refs' swiki). Or you can modify an existing swiki's parent as 'rssdoc' using SwikiBrowser
  4. Now you can address like "http://yourserver/yourswiki/rss" to get RSS feed of your 'Recent Changes'

addresses(book)-rss

| formatter testDate sortedPages item test selectedPages | response at: 'contentType' put: 'text/xml'. formatter _ BookTemplateFormatter swikiFormatter. testDate _ Date today subtractDays: 8. sortedPages _ (book pages asSortedCollection: [:x :y | (x date = y date) ifTrue: [x time > y time] ifFalse: [x date > y date]]) asOrderedCollection. item _ 1. [(test _ sortedPages at: item ifAbsent: [nil]) ifNil: [false] ifNotNil: [test date > testDate]] whileTrue: [item _ item + 1]. item _ item - 1. (item < 5) ifTrue: [(sortedPages size < 5) ifTrue: [selectedPages _ sortedPages] ifFalse: [selectedPages _ sortedPages copyFrom: 1 to: 5]] ifFalse: [(item < 30) ifTrue: [selectedPages _ sortedPages copyFrom: 1 to: item] ifFalse: [selectedPages _ sortedPages copyFrom: 1 to: 30]]. TextFormatter crToCrlf: ( String streamContents: [ :strm | " RSS std header " strm nextPutAll: '<?xml version="1.0" encoding="euc-kr"?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"> <channel> '. " RSS site info " strm nextPutAll: ( formatter format: ' <title><?bookName?></title> <link><?url?></link> <description><?description?></description> ' request: request response: response shelf: shelf book: book ). " ========================================= " " RSS pages info " selectedPages do: [:page | strm nextPutAll: ( formatter format: '<item> <title><?name?></title> <link><?url?>#<?timeStamp?></link> <description><?description?></description> <category><?bookName?></category> <dc:date><?iso8601Date?></dc:date> </item> ' request: request response: response shelf: shelf book: book page: page ) ]. " ========================================= " " RSS std trailer " strm nextPutAll: ' </channel> </rss> '. ] )

actions(book)-description

(book settingsAt: 'description')

actions(book)-url

'http://', (request raw header at: 'host'), (request referenceShelf: shelf book: book)

actions(page)-description

| contents | " apply asString handle dictionary type text " contents _ (page showFormat: page text asString request: request response: response shelf: shelf book: book) findTokens: (' <>&;',String crlf) keep: '<>&;'. String streamContents: [ :strm | | i cnt seekLtEnd seekAmpEnd | i _ 1. cnt _ 0. seekLtEnd _ false. seekAmpEnd _ false. [ (i <= contents size) and: [ cnt < 50 ] ] whileTrue: [ | tok | tok _ contents at: i. ('<' = tok) ifTrue: [ seekLtEnd _ true. ] ifFalse: [ ('&' = tok) ifTrue: [ seekAmpEnd _ true. ] ifFalse: [ seekLtEnd ifTrue: [ ('>' = tok) ifTrue: [ seekLtEnd _ false. ] ] ifFalse: [ seekAmpEnd ifTrue: [ (';' = tok) ifTrue: [ seekAmpEnd _ false. ] ] ifFalse: [ strm nextPutAll: tok; nextPut: $ . cnt _ cnt + 1 ] ] ] ]. i _ i + 1. ] ]

actions(page)-iso8601Date

" dc:date format (iso8601) example: 2003-10-15T10:03:33+09:00 " ((page date) printFormat: #(3 2 1 $- 1 1 2)), 'T', ((page time) print24), '+00:00'

actions(page)-timeStamp

(TimeStamp date: (page date) time: (page time)) asSeconds asString

Tip #2: Using a perl CGI script converting swiki "Recent changes" page into RSS format


Download swiki-to-rss.pl

Get swiki-to-rss.pl and rename it to swiki-to-rss.cgi if needed. Install it as a CGI script for your apache or other legacy web-server.

To access RSS summary of any swiki you want, access this CGI script like this:

http://yourserver/cgi-bin/swiki-to-rss.cgi?proto=<proto>&host=<host>&port=<port>&swiki=<swiki>&lang=<lang>&enc=<enc>&tzo=<offset>[&cronly=1]

For Example:

http://yourserver/cgi-bin/swiki-to-rss.cgi?host=minnow.cc.gatech.edu&swiki=squeak http://yourserver/cgi-bin/swiki-to-rss.cgi?host=minnow.cc.gatech.edu&swiki=swiki

swiki-to-rss.pl looks like:

#!/usr/bin/env perl use CGI qw/:standard/; use Net::HTTP; use Date::Format; use Date::Parse; #use 5.8.0; #use strict; use Encode; use Encode::Alias; $debug = 0; $query_string = $ENV{QUERY_STRING}; $script_descr = "Swiki-to-rss.cgi v0.1"; $agent_string = "Swiki-to-RSS/0.1"; $ttl = 60; # refresh interval in unit of minutes sub usage_and_exit { local($msg) = shift; print header( -type=>'text/plain' ); print $msg,"\n"; print "Usage: swiki-to-rss.cgi?proto=<proto>&host=<host>&port=<port>&swiki=<swiki>&lang=<lang>&enc=<enc>&tzo=<tz-offset>\n"; print "tz-offset must be in unit of hours (plus or minus)\n"; exit 0; } sub tzo_to_tz { local $o = shift; sprintf("%s%02d00",($o>0)?"-":"+",abs($o)); } sub tzo_to_8601tz { local $o = shift; sprintf("%s%02d:00",($o>0)?"-":"+",abs($o)); } sub time_to_rfc822 { local $t = shift; time2str("%a, %d %b %y %H:%M:%S %Z",$t,"GMT"); } sub time_to_iso8601 { local $t = shift; local $z = shift; time2str("%Y-%m-%dT%H:%M:%S",$t,&tzo_to_tz($z)).&tzo_to_8601tz($z); } sub escape_line { local $l = shift; local %escape = ('<'=>'&lt;', '>'=>'&gt;', '&'=>'&amp;', '"'=>'&quot;'); local $escape_re = join '|' => keys %escape; $l =~ s/($escape_re)/$escape{$1}/g; $l; } $host = param('host'); $swiki = param('swiki'); print STDERR "host=$host, swiki=$swiki" if $debug; (!defined($host) || !defined($swiki)) &amp; &usage_and_exit("\`host' and \`swiki' should be specified"); $proto = param(proto) || "http"; $port = param('port'); $lang = param('lang') || "en"; $enc = param('enc'); $tzo = param('tzo') || "5"; $port = ":${port}" if defined($port); $tz = &tzo_to_tz($tzo); $remote = $ENV{HTTP_X_FORWARDED_FOR}; if ( !defined($remote) || $remote =~ m/^127\./ || $remote =~ m/^10\./ || $remote =~ m/^192\.168\./ || $remote =~ m/^169\.254\./ ) { $remote = $ENV{REMOTE_ADDR}; } my $s = Net::HTTP->new(Host => "${host}${port}") || &usage_and_exit("Cannot connect [${host}${port}]"); $s->write_request(GET => "/${swiki}/recent", 'User-Agent' => ${agent_string}, 'X-forwarded-for' => $remote ); my($code, $mess, %h) = $s->read_response_headers; if (200 != $code) { &usage_and_exit("${code}: ${mess}: Cannot fetch [${proto}://${host}${port}/${swiki}/recent]"); } $out = qq`<?xml version="1.0" encoding="utf-8"?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"> `; $contents = ""; while (1) { my $buf; my $n = $s->read_entity_body($buf, 1024); #die "read failed: $!" unless defined $n; last unless $n; $contents .= $buf; } #print STDERR $contents if $debug; @Contents = split(/[\r\n]+/,$contents); #print STDERR join('##',@Contents) if $debug; foreach $n (@Contents) { # print STDERR "<!-- ",&escape_line($_)," -->\n" if ($body_open &amp; $debug); if (!$body_open) { $body_open = ($n =~ m`^<body`); if ($n =~ m`<title>(.*)</title>`) { $title = $0; $ctitle = "<title>$title</title>" if defined($title); $http_hdrs = join("^",%h); $http_hkeys = join("^",keys(%h)); $http_hvals = join("^",values(%h)); $ctype = $h{"Content-type"}; if ($ctype =~ m/;\s*charset=\"?([^\"]+)\"?/) { $enc = $1; } $out .= qq` <!-- HTTP HEADERS=${http_hdrs} --> <!-- keys=${http_hkeys} --> <!-- vals=${http_hvals} --> <!-- Content-type=${ctype} --> <!-- enc=${enc} --> <channel> ${ctitle} <link>${proto}://${host}${port}/${swiki}</link> <description>${title}</description> <language>${lang}</language> <generator>${script_descr}</generator> <ttl>${ttl}</ttl> <!-- Start Parsing ${fetch}${filter} --> `; } } else { if ($n =~ m`<h3>([0-9]+)\s(\S+)\s([0-9]+)</h3>`) { $dts = "$1 $2 $3"; } if ($n =~ m`<li><a href="/(\S+)/([0-9]+)">(.*)</a>\s+at\s+(.*\s+[ap]m)(\s+by\s+(\S+))?\s$`) { $iswiki=$1; $item=$2; $ititle=$3; $timestring = $4; $author = $6; $authorfield = defined($author) ? "<author>${author}</author>" : ""; # for <dc:date>${gt}${toff}</dc:date> $tmsrc = "${dts} ${timestring} ${tz}"; $tm = str2time($tmsrc,$tz); $tm8601 = &time_to_iso8601($tm,$tzo); $tm822 = &time_to_rfc822($tm); $ilink = "${proto}://${host}${port}/${iswiki}/${item}"; # Feedreader hack. (which do not considers guid to check updated item) $ilink .= "#${tm}" if ($ENV{'HTTP_USER_AGENT'} =~ m`^Feedreader`); $guid = "${proto}://${host}${port}/${iswiki}/${item}#${tm}"; $out .= qq`<item> <!-- ${tmsrc} --> <title>${ititle}</title> <link>${ilink}</link> <!-- <description>${ititle}</description> --> <category>${swiki}</category> ${authorfield} <!-- <source url="${query_string}">${script_descr}</source> --> <guid isPermaLink="true">${guid}</guid> <pubDate>${tm822}</pubDate> <dc:date>${tm8601}</dc:date> </item> `; } } } $out .= qq` </channel> </rss> `; if (defined($enc)) { Encode::from_to($out, $enc, "utf-8", 0); } print header( -type=>'text/xml', -charset=>'utf-8', -pragma=>'no-cache', -cache_control=>'no-cache', -expires=>'0', # -content_length=>length($out) ); $\ = "\r\n"; print $out; 0;

My wish is that these will be helpful for someone. :-) –shr

Link to this Page

  • Swiki Wishlist last edited on 5 November 2006 at 10:01 pm by penguin.cc.gatech.edu