X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=data%2Frbot%2Fplugins%2Frss.rb;h=f7e559f7601ed86a10a1e17c26da681e25e812cf;hb=38ce7c2531807e9575a207d9c0c7594778946c89;hp=8004cb122f8375da61c12c989846a20915343eaa;hpb=e51c1c0156538d07d1eb1bf15a334c5164401448;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/data/rbot/plugins/rss.rb b/data/rbot/plugins/rss.rb index 8004cb12..f7e559f7 100644 --- a/data/rbot/plugins/rss.rb +++ b/data/rbot/plugins/rss.rb @@ -151,6 +151,28 @@ module ::RSS SlashModel::ELEMENTS.collect! {|name| "#{SLASH_PREFIX}_#{name}"} end + if self.const_defined? :Atom + # There are improper Atom feeds around that use the non-standard + # 'modified' element instead of the correct 'updated' one. Let's + # support it too. + module Atom + class Feed + class Modified < RSS::Element + include CommonModel + include DateConstruct + end + __send__("install_have_child_element", + "modified", URI, nil, "modified", :content) + + class Entry + Modified = Feed::Modified + __send__("install_have_child_element", + "modified", URI, nil, "modified", :content) + end + end + end + end + class Element class << self def def_bang(name, chain) @@ -162,18 +184,27 @@ module ::RSS end end + # Atom categories are squashed to their label only { :link => %w{link.href link}, :guid => %w{guid.content guid}, :content => %w{content.content content}, :description => %w{description.content description}, :title => %w{title.content title}, - :category => %w{category.content category}, + :category => %w{category.content category.label category}, :dc_subject => %w{dc_subject}, :author => %w{author.name.content author.name author}, :dc_creator => %w{dc_creator} }.each { |name, chain| def_bang name, chain } + def categories! + return nil unless self.respond_to? :categories + cats = categories.map do |c| + blank2nil { c.content rescue c.label rescue c rescue nil } + end.compact + cats.empty? ? nil : cats + end + protected def blank2nil(&block) x = yield @@ -300,7 +331,7 @@ class RSSFeedsPlugin < Plugin :desc => "Whether to display links from the text of a feed item.") # Make an 'unique' ID for a given item, based on appropriate bot options - # Currently only suppored is bot.config['rss.show_updated']: when false, + # Currently only supported is bot.config['rss.show_updated']: when false, # only the guid/link is accounted for. def make_uid(item) @@ -331,10 +362,43 @@ class RSSFeedsPlugin < Plugin # Auxiliary method used to collect two lines for rss output filters, # running substitutions against DataStream _s_ optionally joined - # with hash _h_ + # with hash _h_. + # + # For substitutions, *_wrap keys can be used to alter the content of + # other nonempty keys. If the value of *_wrap is a String, it will be + # put before and after the corresponding key; if it's an Array, the first + # and second elements will be used for wrapping; if it's nil, no wrapping + # will be done (useful to override a default wrapping). + # + # For example: + # :handle_wrap => '::':: + # will wrap s[:handle] by prefixing and postfixing it with '::' + # :date_wrap => [nil, ' :: ']:: + # will put ' :: ' after s[:date] def make_stream(line1, line2, s, h={}) ss = s.merge(h) - DataStream.new([line1, line2].compact.join("\n") % ss, ss) + subs = {} + wraps = {} + ss.each do |k, v| + kk = k.to_s.chomp!('_wrap') + if kk + nk = kk.intern + case v + when String + wraps[nk] = ss[nk].wrap_nonempty(v, v) + when Array + wraps[nk] = ss[nk].wrap_nonempty(*v) + when nil + # do nothing + else + warning "ignoring #{v.inspect} wrapping of unknown class" + end unless ss[nk].nil? + else + subs[k] = v + end + end + subs.merge! wraps + DataStream.new([line1, line2].compact.join("\n") % subs, ss) end # Auxiliary method used to define rss output filters @@ -344,13 +408,31 @@ class RSSFeedsPlugin < Plugin # Define default output filters (rss types), and load custom ones. # Custom filters are looked for in the plugin's default filter locations - # and in rss/types under botclass. + # and in rss/types.rb under botclass. # Preferably, the rss_type method should be used in these files, e.g.: # rss_type :my_type do |s| # line1 = "%{handle} and some %{author} info" # make_stream(line1, nil, s) # end - # to define the new type 'my_type' + # to define the new type 'my_type'. The keys available in the DataStream + # are: + # item:: + # the actual rss item + # handle:: + # the item handle + # date:: + # the item date + # title:: + # the item title + # desc, link, category, author:: + # the item description, link, category, author + # at:: + # the string ' @ ' if the item has both an title and a link + # handle_wrap, date_wrap, title_wrap, ...:: + # these keys can be defined to wrap the corresponding elements if they + # are nonempty. By default handle is wrapped with '::', date has a ' ::' + # appended and title is enbolden + # def define_filters @outkey ||= :"rss.out" @@ -721,15 +803,28 @@ class RSSFeedsPlugin < Plugin end case params[:what].intern when :handle - new = params[:new].downcase - if @feeds.key?(new) and @feeds[new] + # preserve rename case, but beware of key + realnew = params[:new] + new = realnew.downcase + if feed.handle.downcase == new + if feed.handle == realnew + m.reply _("You want me to rename %{handle} to itself?") % { + :handle => feed.handle + } + return false + else + feed.mutex.synchronize do + feed.handle = realnew + end + end + elsif @feeds.key?(new) and @feeds[new] m.reply "There already is a feed with handle #{new}" return else feed.mutex.synchronize do @feeds[new] = feed @feeds.delete(handle) - feed.handle = new + feed.handle = realnew end handle = new end @@ -840,8 +935,8 @@ class RSSFeedsPlugin < Plugin stop_watches # Read watches from list. - watchlist.each{ |handle, feed| - watchRss(feed, m) + watchlist.each{ |hndl, fd| + watchRss(fd, m) } m.okay if m end @@ -868,7 +963,7 @@ class RSSFeedsPlugin < Plugin debug "fetching #{feed}" first_run = !feed.last_success - if (@bot.config['rss.announce_timeout'] > 0 && + if (!first_run && @bot.config['rss.announce_timeout'] > 0 && (Time.now - feed.last_success > @bot.config['rss.announce_timeout'])) debug "#{feed} wasn't polled for too long, supressing output" first_run = true @@ -982,50 +1077,45 @@ class RSSFeedsPlugin < Plugin return seconds end + def make_date(obj) + if obj.kind_of? Time + obj.strftime("%Y/%m/%d %H:%M") + else + obj.to_s + end + end + def printFormattedRss(feed, item, options={}) # debug item opts = { :places => feed.watchers, - :handle => feed.handle.empty? ? "" : "::#{feed.handle}:: ", + :handle => feed.handle, :date => false, :announce_method => @bot.config['rss.announce_method'] }.merge options - date = String.new - places = opts[:places] - handle = opts[:handle].to_s announce_method = opts[:announce_method] + handle = opts[:handle].to_s + + date = \ if opts[:date] - if item.respond_to?(:updated) - if item.updated.content.class <= Time - date = item.updated.content.strftime("%Y/%m/%d %H:%M") - else - date = item.updated.content.to_s - end + if item.respond_to?(:updated) and item.updated + make_date(item.updated.content) + elsif item.respond_to?(:modified) and item.modified + make_date(item.modified.content) elsif item.respond_to?(:source) and item.source.respond_to?(:updated) - if item.source.updated.content.class <= Time - date = item.source.updated.content.strftime("%Y/%m/%d %H:%M") - else - date = item.source.updated.content.to_s - end + make_date(item.source.updated.content) elsif item.respond_to?(:pubDate) - if item.pubDate.class <= Time - date = item.pubDate.strftime("%Y/%m/%d %H:%M") - else - date = item.pubDate.to_s - end + make_date(item.pubDate) elsif item.respond_to?(:date) - if item.date.class <= Time - date = item.date.strftime("%Y/%m/%d %H:%M") - else - date = item.date.to_s - end + make_date(item.date) else - date = "(no date)" + "(no date)" end - date << " :: " + else + String.new end tit_opt = {} @@ -1039,7 +1129,7 @@ class RSSFeedsPlugin < Plugin # visible in the URL anyway # TODO make this optional? base_title.sub!(/^Changeset \[([\da-f]{40})\]:/) { |c| "(git commit)"} if feed.type == 'trac' - title = "#{Bold}#{base_title.ircify_html(tit_opt)}#{Bold}" + title = base_title.ircify_html(tit_opt) end desc_opt = {} @@ -1068,6 +1158,7 @@ class RSSFeedsPlugin < Plugin link = item.link! link.strip! if link + categories = item.categories! category = item.category! || item.dc_subject! category.strip! if category author = item.dc_creator! || item.author! @@ -1081,9 +1172,19 @@ class RSSFeedsPlugin < Plugin 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) + stream_hash = { + :item => item, + :handle => handle, + :handle_wrap => ['::', ':: '], + :date => date, + :date_wrap => [nil, ' :: '], + :title => title, + :title_wrap => Bold, + :desc => desc, :link => link, + :categories => categories, + :category => category, :author => author, :at => at + } + output = @bot.filter(key, stream_hash) return output if places.empty?