+ # Auxiliary method used to collect two lines for rss output filters,
+ # running substitutions against DataStream _s_ optionally joined
+ # with hash _h_
+ def make_stream(line1, line2, s, h={})
+ ss = s.merge(h)
+ DataStream.new([line1, line2].compact.join("\n") % ss, ss)
+ end
+
+ # Define default RSS filters
+ #
+ # TODO: load personal ones
+ def define_filters
+ @outkey = :"rss.out"
+ @bot.register_filter(:headlines, @outkey) { |s|
+ line1 = (s[:handle].empty? ? "%{date}" : "%{handle}") << "%{title}"
+ make_stream(line1, nil, s)
+ }
+ @bot.register_filter(:blog, @outkey) { |s|
+ author = s[:author] ? (s[:author] + " ") : ""
+ abt = s[:category] ? "about #{s[:category]} " : ""
+ line1 = "%{handle}%{date}%{author}blogged %{abt}at %{link}"
+ line2 = "%{handle}%{title} - %{desc}"
+ make_stream(line1, line2, s, :author => author, :abt => abt)
+ }
+ @bot.register_filter(:photoblog, @outkey) { |s|
+ author = s[:author] ? (s[:author] + " ") : ""
+ abt = s[:category] ? "under #{s[:category]} " : ""
+ line1 = "%{handle}%{date}%{author}added an image %{abt}at %{link}"
+ line2 = "%{handle}%{title} - %{desc}"
+ make_stream(line1, line2, s, :author => author, :abt => abt)
+ }
+ @bot.register_filter(:news, @outkey) { |s|
+ line1 = "%{handle}%{date}%{title}%{at}%{link}" % s
+ line2 = "%{handle}%{date}%{desc}" % s
+ make_stream(line1, line2, s)
+ }
+ @bot.register_filter(:git, @outkey) { |s|
+ author = s[:author].sub(/@\S+?\s*>/, "@...>") + " " if s[:author]
+ line1 = "%{handle}%{date}%{author}committed %{title}%{at}%{link}"
+ make_stream(line1, nil, s, :author => author)
+ }
+ @bot.register_filter(:forum, @outkey) { |s|
+ line1 = "%{handle}%{date}%{title}%{at}%{link}"
+ make_stream(line1, nil, s)
+ }
+ @bot.register_filter(:wiki, @outkey) { |s|
+ line1 = "%{handle}%{date}%{title}%{at}%{link}"
+ line1 << "has been edited by %{author}. %{desc}"
+ make_stream(line1, nil, s)
+ }
+ @bot.register_filter(:gmane, @outkey) { |s|
+ line1 = "%{handle}%{date}Message %{title} sent by %{author}. %{desc}"
+ make_stream(line1, nil, s)
+ }
+ @bot.register_filter(:trac, @outkey) { |s|
+ author = s[:author].sub(/@\S+?\s*>/, "@...>") + ": " if s[:author]
+ line1 = "%{handle}%{date}%{author}%{title}%{at}%{link}"
+ line2 = nil
+ unless s[:item].title =~ /^(?:Changeset \[(?:[\da-f]+)\]|\(git commit\))/
+ line2 = "%{handle}%{date}%{desc}"
+ end
+ make_stream(line1, line2, s, :author => author)
+ }
+ @bot.register_filter(:"/.", @outkey) { |s|
+ dept = "(from the #{s[:item].slash_department} dept) " rescue nil
+ sec = " in section #{s[:item].slash_section}" rescue nil
+ line1 = "%{handle}%{date}%{dept}%{title}%{at}%{link} "
+ line1 << "(posted by %{author}%{sec})"
+ make_stream(line1, nil, s, :dept => dept, :sec => sec)
+ }
+ @bot.register_filter(:default, @outkey) { |s|
+ line1 = "%{handle}%{date}%{title}%{at}%{link}"
+ line1 << " (by %{author})" if s[:author]
+ make_stream(line1, nil, s)
+ }
+
+ # Define an HTML info filter too
+ @bot.register_filter(:rss, :htmlinfo) { |s| htmlinfo_filter(s) }
+
+ # This is the output format used by the input filter
+ @bot.register_filter(:htmlinfo, @outkey) { |s|
+ line1 = "%{title}%{at}%{link}"
+ make_stream(line1, nil, s)
+ }
+ end
+
+ FEED_NS = %r{xmlns.*http://(purl\.org/rss|www.w3c.org/1999/02/22-rdf)}
+ def htmlinfo_filter(s)
+ return nil unless s[:headers] and s[:headers]['x-rbot-location']
+ return nil unless s[:headers]['content-type'].first.match(/xml|rss|atom|rdf/i) or
+ (s[:text].include?("<rdf:RDF") and s[:text].include?("<channel")) or
+ s[:text].include?("<rss") or s[:text].include?("<feed") or
+ s[:text].match(FEED_NS)
+ blob = RssBlob.new(s[:headers]['x-rbot-location'],"", :htmlinfo)
+ unless (fetchRss(blob, nil) and parseRss(blob, nil) rescue nil)
+ debug "#{s.pretty_inspect} is not an RSS feed, despite the appearances"
+ return nil
+ end
+ output = []
+ blob.items.each { |it|
+ output << printFormattedRss(blob, it)[:text]
+ }
+ return {:title => blob.title, :content => output.join(" | ")}
+ end
+
+ # Display the known rss types
+ def rss_types(m, params)
+ ar = @bot.filter_names(@outkey)
+ ar.delete(:default)
+ m.reply ar.map { |k| k.to_s }.sort!.join(", ")
+ end
+