]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/tumblr.rb
tumblr: escape the non-range dash in the group regex
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / tumblr.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: tumblr interface
5 #
6 # Author:: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
7 # Copyright:: (C) 2009 Giuseppe Bilotta
8 # License:: GPLv2
9 #
10 # Submit URLs to channel-specific tumblr accounts
11 #
12 # TODO support other video providers (maybe detect embed codes?)
13 # TODO support image better (e.g. pages with a single big image)
14 # TODO customize caption/description format
15 # TODO do not reblog own posts (maybe?)
16
17 require 'rexml/document'
18 require 'cgi'
19
20 class TumblrPlugin < Plugin
21   RBOT = CGI.escape("rbot #{$version.split.first}")
22   WRITE_URL = "http://www.tumblr.com/api/write"
23   REBLOG_URL = "http://www.tumblr.com/api/reblog"
24   READ_URL = "http://%{user}.tumblr.com/api/read?id=%{id}"
25   LOGIN = "email=%{email}&password=%{pwd}&group=%{group}&format=markdown&generator=" + RBOT
26   PHOTO = "&type=photo&source=%{src}&click-through-url=%{src}"
27   VIDEO = "&type=video&embed=%{src}"
28   CAPTION = "&caption=%{desc}"
29   LINK = "&type=link&url=%{src}"
30   NAME = "&name=%{name}"
31   DESC = "&description=%{desc}"
32   REBLOG = "&post-id=%{id}&reblog-key=%{reblog}"
33   COMMENT = "&comment=%{desc}"
34   TAGS = "&tags=%{tags}"
35
36   def help(plugin, topic="")
37     case topic
38     when "configure"
39       "tumblr configure [<channel>]: show credentials used for channel <channel> (default: current).    tumblr configure [<channel>] <email> <password> [<group>] => post links from channel <channel> (default: current) to group <group> (default: name of channel) using the given tumblr credentials"
40     when "deconfigure"
41       "tumblr deconfigure [<channel>]: forget credentials for channel <channel> (default: current)."
42     else
43       "post links, photos and videos to a channel-specific tumblr. topics: configure, deconfigure"
44     end
45   end
46
47   def event_url_added(url, options={})
48     return unless options.key? :channel
49     chan = options[:channel]
50     return unless @registry.key? chan
51
52     account = @registry[chan]
53
54     line = options[:ircline]
55     line = nil if line and line.empty?
56     if line and nick = options[:nick]
57       line = "<#{nick}> #{line}"
58     end
59     html_line = line ? CGI.escapeHTML(line) : line
60     tags = line ? line.scan(/\[([^\]]+)\]/).flatten : []
61
62     req = LOGIN % account
63     ready = false
64     api_url = WRITE_URL
65     tumblr = options[:htmlinfo][:headers]['x-tumblr-user'].to_s rescue nil
66     if tumblr
67       id = url.match(/\/post\/(\d+)/)
68       if id
69         id = id[1]
70
71         read_url = READ_URL % { :user => tumblr, :id => id}
72         # TODO seems to return 503 a little too frequently
73         xml = @bot.httputil.get(read_url)
74
75         if xml
76           reblog = REXML::Document.new(xml).elements["//post"].attributes["reblog-key"] rescue nil
77           if reblog and not reblog.empty?
78             api_url = REBLOG_URL
79             data = REBLOG
80             data << COMMENT
81             html_line = CGI.escapeHTML("(via <a href=%{url}>%{tumblr}</a>" % {
82               :url => url, :tumblr => tmblr
83             }) unless html_line
84             req << (data % {
85               :id => id,
86               :reblog => reblog,
87               :desc => CGI.escape(html_line)
88             })
89             ready = true
90           end
91         end
92       end
93     end
94
95     if not ready
96       type = options[:htmlinfo][:headers]['content-type'].first rescue nil
97       case type
98       when /^image\/.*/
99         data = PHOTO
100         data << CAPTION if line
101       else
102         if url.match(%r{^http://(\w+\.)?(youtube\.com/watch.*|vimeo.com/\d+)})
103           data = VIDEO
104           data << CAPTION if line
105         else
106           data = LINK
107           data << NAME if line
108         end
109       end
110       data << TAGS unless tags.empty?
111       req << (data % {
112         :src => CGI.escape(url),
113         :desc => CGI.escape(html_line),
114         :tags => CGI.escape(tags.join(',')),
115         :name => CGI.escape(line)
116       })
117     end
118
119     debug "posting #{req.inspect}"
120     resp  = @bot.httputil.post(api_url, req)
121     debug "tumblr response: #{resp.inspect}"
122   end
123
124   def configuration(m, params={})
125     channel = params[:channel] || m.channel
126     if not channel
127       m.reply _("Please specify a channel")
128       return
129     end
130     if not @registry.key? channel
131       m.reply _("No tumblr credentials set for %{chan}" % { :chan => channel })
132       return false
133     end
134
135     account = @registry[channel]
136
137     account[:pwd] = _("<hidden>") if m.public?
138     account[:chan] = channel
139
140     m.reply _("Links on %{chan} will go to %{group} using account %{email} and password %{pwd}" % account)
141   end
142
143   def deconfigure(m, params={})
144     channel = params[:channel] || m.channel
145     if not channel
146       m.reply _("Please specify a channel")
147       return
148     end
149     if not @registry.key? channel
150       m.reply _("No tumblr credentials set for %{chan}" % { :chan => channel })
151       return false
152     end
153
154     @registry.delete channel
155
156     m.reply _("Links on %{chan} will not be posted to tumblr anymore" % {:chan => channel})
157   end
158
159   def configure(m, params={})
160     channel = params[:channel] || m.channel
161     if not channel
162       m.reply _("Please specify a channel")
163       return
164     end
165     if @registry.key? channel
166       m.reply _("%{chan} already has credentials configured" % { :chan => channel })
167     else
168       group = params[:group] || Channel.npname(channel)
169       group << ".tumblr.com" unless group.match(/\.tumblr\.com/)
170       @registry[channel] = {
171         :email => CGI.escape(params[:email]),
172         :pwd => CGI.escape(params[:pwd]),
173         :group => CGI.escape(group)
174       }
175
176     end
177
178     return configuration(m, params)
179   end
180
181 end
182
183 plugin = TumblrPlugin.new
184
185 plugin.default_auth('*', false)
186
187 plugin.map 'tumblr configure [:channel]', :action => :configuration
188 plugin.map 'tumblr deconfigure [:channel]', :action => :deconfigure
189 plugin.map 'tumblr configure [:channel] :email :pwd [:group]',
190   :action => :configure,
191   :requirements => {:channel => Regexp::Irc::GEN_CHAN, :email => /\S+@\S+/, :group => /[A-Za-z\-.]+/}
192