]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - data/rbot/plugins/rss.rb
uno plugin: fix check for card presence
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / rss.rb
index 3b8e8c7dcc51c8a2cda6a4df493eae357b8cd470..1d141f3b10dff1e4ecd521630ae0ae58fd90d400 100644 (file)
@@ -284,10 +284,121 @@ class RSSFeedsPlugin < Plugin
     end
   end
 
+  # 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(: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} @ %{link}" % s
+      line2 = "%{handle}%{date}%{desc}" % s
+      make_stream(line1, line2, s)
+    }
+    @bot.register_filter(:git, @outkey) { |s|
+      author = s[:author] ? (s[:author] + " ") : ""
+      line1 = "%{handle}%{date}%{author}committed %{title} @ %{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} @ %{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
+
   attr_reader :feeds
 
   def initialize
     super
+
+    define_filters
+
     if @registry.has_key?(:feeds)
       # When migrating from Ruby 1.8.5 to 1.8.6, dumped Mutexes may render the
       # data unrestorable. If this happens, we patch the data, thus allowing
@@ -402,8 +513,10 @@ class RSSFeedsPlugin < Plugin
       "rss who watches #{Bold}handle#{Bold}: lists watches for rss #{Bold}handle#{Bold}"
     when "rewatch"
       "rss rewatch : restart threads that watch for changes in watched rss"
+    when "types"
+      "rss types : show the rss types for which an output format existi (all other types will use the default one)"
     else
-      "manage RSS feeds: rss show|list|watched|add|change|del(ete)|rm|(force)replace|watch|unwatch|rmwatch|rewatch|who watches"
+      "manage RSS feeds: rss types|show|list|watched|add|change|del(ete)|rm|(force)replace|watch|unwatch|rmwatch|rewatch|who watches"
     end
   end
 
@@ -690,7 +803,7 @@ class RSSFeedsPlugin < Plugin
     if params and handle = params[:handle]
       feed = @feeds.fetch(handle.downcase, nil)
       if feed
-        @bot.timer.reschedule(@watch[feed.handle], 0)
+        @bot.timer.reschedule(@watch[feed.handle], (params[:delay] || 0).to_f)
         m.okay if m
       else
         m.reply _("no such feed %{handle}") % { :handle => handle } if m
@@ -832,7 +945,7 @@ class RSSFeedsPlugin < Plugin
   def printFormattedRss(feed, item, opts=nil)
     debug item
     places = feed.watchers
-    handle = "::#{feed.handle}:: "
+    handle = feed.handle.empty? ? "" : "::#{feed.handle}:: "
     date = String.new
     if opts
       places = opts[:places] if opts.key?(:places)
@@ -893,7 +1006,7 @@ class RSSFeedsPlugin < Plugin
       desc = item.content_encoded.ircify_html(desc_opt)
     elsif item.respond_to?(:description) && item.description
       desc = item.description.ircify_html(desc_opt)
-    else
+    elsif item.respond_to?(:content) && item.content
       if item.content.type == "html"
         desc = item.content.content.ircify_html(desc_opt)
       else
@@ -902,6 +1015,8 @@ class RSSFeedsPlugin < Plugin
           desc = desc.slice(0, desc_opt[:limit]) + "#{Reverse}...#{Reverse}"
         end
       end
+    else
+      desc = "(?)"
     end
 
     link = item.link.href rescue item.link.chomp rescue nil
@@ -914,47 +1029,19 @@ class RSSFeedsPlugin < Plugin
 
     at = ((item.title && item.link) ? ' @ ' : '')
 
-    case feed.type
-    when 'blog'
-      author += " " if author
-      abt = category ? "about #{category} " : ""
-      line1 = "#{handle}#{date}#{author}blogged #{abt}at #{link}"
-      line2 = "#{handle}#{title} - #{desc}"
-    when 'photoblog'
-      author += " " if author
-      abt = category ? "under #{category} " : ""
-      line1 = "#{handle}#{date}#{author}added an image #{abt}at #{link}"
-      line2 = "#{handle}#{title} - #{desc}"
-    when 'news'
-      line1 = "#{handle}#{date}#{title} @ #{link}"
-      line2 = line2 = "#{handle}#{date}#{desc}"
-    when 'git'
-      author += " " if author
-      line1 = "#{handle}#{date}#{author}commited #{title} @ #{link}"
-    when 'forum'
-      line1 = "#{handle}#{date}#{title}#{at}#{link}"
-    when 'wiki'
-      line1 = "#{handle}#{date}#{title}#{at}#{link} has been edited by #{author}. #{desc}"
-    when 'gmane'
-      line1 = "#{handle}#{date}Message #{title} sent by #{author}. #{desc}"
-    when 'trac'
-      line1 = "#{handle}#{date}#{title} @ #{link}"
-      unless item.title =~ /^(?:Changeset \[(?:[\da-f]+)\]|\(git commit\))/
-        line2 = "#{handle}#{date}#{desc}"
-      end
-    when '/.'
-      dept = "(from the #{item.slash_department} dept) " rescue nil
-      sec = " in section #{item.slash_section}" rescue nil
+    key = @bot.global_filter_name(feed.type, @outkey)
+    key = @bot.global_filter_name(:default, @outkey) unless @bot.has_filter?(key)
+
+    output = @bot.filter(key, :item => item, :handle => handle, :date => date,
+                         :title => title, :desc => desc, :link => link,
+                         :category => category, :author => author, :at => at)
+
+    return output if places.empty?
 
-      line1 = "#{handle}#{date}#{dept}#{title}#{at}#{link} (posted by #{author}#{sec})"
-    else
-      line1 = "#{handle}#{date}#{title}#{at}#{link}"
-      line1 << " (by #{author})" if author
-    end
     places.each { |loc|
-      @bot.say loc, line1, :overlong => :truncate
-      next unless line2
-      @bot.say loc, line2, :overlong => :truncate
+      output.to_s.each_line { |line|
+        @bot.say loc, line, :overlong => :truncate
+      }
     }
   end
 
@@ -1024,13 +1111,13 @@ class RSSFeedsPlugin < Plugin
           return nil
         end
         if rss.respond_to? :channel
-          rss.channel.title ||= "Unknown"
+          rss.channel.title ||= "(?)"
           title = rss.channel.title
         else
           title = rss.title.content
         end
         rss.items.each do |item|
-          item.title ||= "Unknown"
+          item.title ||= "(?)"
           items << item
         end
       end
@@ -1103,5 +1190,7 @@ plugin.map 'rss unwatch :handle [in :chan]',
   :action => 'unwatch_rss'
 plugin.map 'rss rmwatch :handle [in :chan]',
   :action => 'unwatch_rss'
-plugin.map 'rss rewatch [:handle]',
+plugin.map 'rss rewatch [:handle] [:delay]',
   :action => 'rewatch_rss'
+plugin.map 'rss types',
+  :action => 'rss_types'