UNO plugin: give cards to correct player at endgame
[rbot] / data / rbot / plugins / freshmeat.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: Freshmeat plugin for rbot
5
6 require 'rexml/document'
7
8 class FreshmeatPlugin < Plugin
9   include REXML
10   def help(plugin, topic="")
11     "freshmeat search [<max>=4] <string> => search freshmeat for <string>, freshmeat [<max>=4] => return up to <max> freshmeat headlines"
12   end
13
14   REL_ENTRY = %r{<a href="/(release)s/(\d+)/"><font color="#000000">(.*?)</font></a>}
15   PRJ_ENTRY = %r{<a href="/(project)s/(\S+?)/"><b>(.*?)</b></a>}
16
17   # This method defines a filter for fm pages. It's needed because the generic
18   # summarization grabs a comment, not the actual article.
19   #
20   def freshmeat_filter(s)
21     loc = Utils.check_location(s, /freshmeat\.net/)
22     return nil unless loc
23     entries = []
24     s[:text].scan(/#{REL_ENTRY}|#{PRJ_ENTRY}/) { |m|
25       entry = {
26         :type => ($1 || $4).dup,
27         :code => ($2 || $5).dup,
28         :name => ($3 || $6).dup
29       }
30       entries << entry
31     }
32     return nil if entries.empty?
33     title = s[:text].ircify_html_title
34     content = entries.inject([]) { |l, e| l << e[:name] }.join(" | ")
35     return {:title => title, :content => content}
36   end
37
38   def initialize
39     super
40     @bot.register_filter(:freshmeat, :htmlinfo) { |s| freshmeat_filter(s) }
41   end
42
43   def search_freshmeat(m, params)
44     max = params[:limit].to_i
45     search = params[:search].to_s
46     max = 8 if max > 8
47     xml = @bot.httputil.get("http://freshmeat.net/search-xml/?orderby=locate_projectname_full_DESC&q=#{CGI.escape(search)}")
48     unless xml
49       m.reply "search for #{search} failed"
50       return
51     end
52     doc = nil
53     begin
54       doc = Document.new xml
55     rescue
56       debug xml
57       error $!
58     end
59     unless doc
60       m.reply "search for #{search} failed"
61       return
62     end
63     matches = Array.new
64     max_width = 250
65     title_width = 0
66     url_width = 0
67     done = 0
68     doc.elements.each("*/match") {|e|
69       name = e.elements["projectname_short"].text
70       url = "http://freshmeat.net/projects/#{name}/"
71       desc = e.elements["desc_short"].text
72       title = e.elements["projectname_full"].text
73       #title_width = title.length if title.length > title_width
74       url_width = url.length if url.length > url_width
75       matches << [title, url, desc]
76       done += 1
77       break if done >= max
78     }
79     if matches.length == 0
80       m.reply "not found: #{search}"
81     end
82     matches.each {|mat|
83       title = mat[0]
84       url = mat[1]
85       desc = mat[2]
86       desc.gsub!(/(.{#{max_width - 3 - url_width}}).*/, '\1..')
87       reply = sprintf("%s | %s", url.ljust(url_width), desc)
88       m.reply reply
89     }
90   end
91   
92   def freshmeat(m, params)
93     max = params[:limit].to_i
94     max = 8 if max > 8
95     begin
96       xml = @bot.httputil.get('http://freshmeat.net/backend/fm-releases-global.xml')
97       unless xml
98         m.reply "freshmeat news parse failed"
99         return
100       end
101       doc = Document.new xml
102       unless doc
103         m.reply "freshmeat news parse failed"
104         return
105       end
106     rescue
107       m.reply "freshmeat news parse failed"
108       return
109     end
110
111     matches = Array.new
112     max_width = 60
113     title_width = 0
114     done = 0
115     doc.elements.each("*/channel/item") {|e|
116       desc = e.elements["description"].text.ircify_html
117       title = e.elements["title"].text.ircify_html
118       #title.gsub!(/\s+\(.*\)\s*$/, "")
119       title.strip!
120       title_width = title.length if title.length > title_width
121       matches << [title, desc]
122       done += 1
123       break if done >= max
124     }
125     matches.each {|mat|
126       title = mat[0]
127       #desc = mat[1]
128       #desc.gsub!(/(.{#{max_width - 3 - title_width}}).*/, '\1..')
129       #reply = sprintf("%#{title_width}s | %s", title, desc)
130       m.reply title
131     }
132   end
133 end
134 plugin = FreshmeatPlugin.new
135 plugin.map 'freshmeat search :limit *search', :action => 'search_freshmeat',
136             :defaults => {:limit => 4}, :requirements => {:limit => /^\d+$/}
137 plugin.map 'freshmeat :limit', :defaults => {:limit => 4}, 
138                                :requirements => {:limit => /^\d+$/}