| 1 | # show photo image on Flickr.com |
|---|
| 2 | # |
|---|
| 3 | # usage: |
|---|
| 4 | # flickr(photo_id[, size[, place]]) |
|---|
| 5 | # - photo_id: The id of the photo to show. |
|---|
| 6 | # - size: Size of photo. (optional) |
|---|
| 7 | # Choose from square, thumbnail, small, medium, or large. |
|---|
| 8 | # - place: class name of img element. default is 'flickr'. |
|---|
| 9 | # |
|---|
| 10 | # flickr_left(photo_id[, size]) |
|---|
| 11 | # |
|---|
| 12 | # flickr_right(photo_id[, size]) |
|---|
| 13 | # |
|---|
| 14 | # options configurable through settings: |
|---|
| 15 | # @conf['flickr.apikey'] : a key for access Flickr API |
|---|
| 16 | # @conf['flickr.default_size'] : default image size |
|---|
| 17 | # |
|---|
| 18 | # Copyright (c) MATSUOKA Kohei <http://www.machu.jp/> |
|---|
| 19 | # Distributed under the GPL |
|---|
| 20 | # |
|---|
| 21 | require 'open-uri' |
|---|
| 22 | require 'digest/md5' |
|---|
| 23 | require 'rexml/document' |
|---|
| 24 | |
|---|
| 25 | def flickr(photo_id, size = nil, place = 'flickr') |
|---|
| 26 | unless @conf['flickr.apikey'] || @conf['flickr.apikey'].empty? |
|---|
| 27 | return '[ERROR] flickr.rb: API Key is not specified.' |
|---|
| 28 | end |
|---|
| 29 | size ||= @conf['flickr.default_size'] || 'small' |
|---|
| 30 | size = 'small' if @conf.iphone? |
|---|
| 31 | photo = flickr_photo_info(photo_id.to_s, size) |
|---|
| 32 | unless photo |
|---|
| 33 | return '[ERROR] flickr.rb: failed to get photo.' |
|---|
| 34 | end |
|---|
| 35 | |
|---|
| 36 | if @cgi.mobile_agent? |
|---|
| 37 | body = %Q|<a href="#{photo[:src]}">#{photo[:title]}</a>| |
|---|
| 38 | else |
|---|
| 39 | body = %Q|<a href="#{photo[:page]}"><img title="#{photo[:title]}" alt="#{photo[:title]}" src="#{photo[:src]}" class="#{place}"| |
|---|
| 40 | unless @conf.iphone? |
|---|
| 41 | body << %Q| width="#{photo[:width]}"| if photo[:width] |
|---|
| 42 | body << %Q| height="#{photo[:height]}"| if photo[:height] |
|---|
| 43 | end |
|---|
| 44 | body << %Q|></a>| |
|---|
| 45 | end |
|---|
| 46 | |
|---|
| 47 | body |
|---|
| 48 | end |
|---|
| 49 | |
|---|
| 50 | def flickr_left(photo_id, size = nil) |
|---|
| 51 | flickr(photo_id, size, 'left') |
|---|
| 52 | end |
|---|
| 53 | |
|---|
| 54 | def flickr_right(photo_id, size = nil) |
|---|
| 55 | flickr(photo_id, size, 'right') |
|---|
| 56 | end |
|---|
| 57 | |
|---|
| 58 | def flickr_photo_info(photo_id, size) |
|---|
| 59 | photo = {} |
|---|
| 60 | |
|---|
| 61 | begin |
|---|
| 62 | flickr_open('flickr.photos.getInfo', photo_id) {|f| |
|---|
| 63 | res = REXML::Document.new(f) |
|---|
| 64 | photo[:page] = res.elements['//rsp/photo/urls/url'].text |
|---|
| 65 | photo[:title] = res.elements['//rsp/photo/title'].text |
|---|
| 66 | } |
|---|
| 67 | flickr_open('flickr.photos.getSizes', photo_id) {|f| |
|---|
| 68 | res = REXML::Document.new(f) |
|---|
| 69 | res.elements.each('//rsp/sizes/size') do |s| |
|---|
| 70 | if s.attributes['label'].downcase == size.downcase |
|---|
| 71 | photo[:src] = s.attributes['source'] |
|---|
| 72 | photo[:width] = s.attributes['width'] |
|---|
| 73 | photo[:height] = s.attributes['height'] |
|---|
| 74 | end |
|---|
| 75 | end |
|---|
| 76 | } |
|---|
| 77 | rescue Exception => e |
|---|
| 78 | return nil |
|---|
| 79 | end |
|---|
| 80 | photo |
|---|
| 81 | end |
|---|
| 82 | |
|---|
| 83 | def flickr_open(method, photo_id) |
|---|
| 84 | cache_dir = "#{@cache_path}/flickr" |
|---|
| 85 | Dir::mkdir(cache_dir) unless File::directory?(cache_dir) |
|---|
| 86 | |
|---|
| 87 | file = "#{cache_dir}/#{photo_id}.#{method}" |
|---|
| 88 | unless File.exist?(file) |
|---|
| 89 | req = Flickr::Request.new(@conf['flickr.apikey']) |
|---|
| 90 | req['method'] = method |
|---|
| 91 | req['photo_id'] = photo_id |
|---|
| 92 | begin |
|---|
| 93 | timeout(5) do |
|---|
| 94 | open(file, 'w') {|fout| |
|---|
| 95 | req.open.each {|line| fout.puts line } |
|---|
| 96 | } |
|---|
| 97 | end |
|---|
| 98 | rescue TimeoutError => e |
|---|
| 99 | File.delete(file) |
|---|
| 100 | raise e |
|---|
| 101 | end |
|---|
| 102 | end |
|---|
| 103 | open(file) {|f| yield f } |
|---|
| 104 | end |
|---|
| 105 | |
|---|
| 106 | # delete cache files |
|---|
| 107 | def flickr_clear_cache |
|---|
| 108 | cache_dir = "#{@cache_path}/flickr" |
|---|
| 109 | Dir.glob("#{cache_dir}/*.flickr.photos.{getInfo,getSizes}") do |cache| |
|---|
| 110 | # File.unlink(cache) |
|---|
| 111 | File.rename(cache, "#{cache}.org") |
|---|
| 112 | end |
|---|
| 113 | end |
|---|
| 114 | |
|---|
| 115 | FLICKER_FORM_PID = 'plugin_flickr_pid' |
|---|
| 116 | add_edit_proc do |date| |
|---|
| 117 | photo_id = @cgi.params[FLICKER_FORM_PID][0] or next |
|---|
| 118 | |
|---|
| 119 | # this code was from image.rb |
|---|
| 120 | case @conf.style.downcase.sub( /\Ablog/, '' ) |
|---|
| 121 | when "wiki", "markdown" |
|---|
| 122 | ptag1 = "{{" |
|---|
| 123 | ptag2 = "}}" |
|---|
| 124 | when "rd" |
|---|
| 125 | ptag1 = "((%" |
|---|
| 126 | ptag2 = "%))" |
|---|
| 127 | else |
|---|
| 128 | ptag1 = "<%=" |
|---|
| 129 | ptag2 = "%>" |
|---|
| 130 | end |
|---|
| 131 | |
|---|
| 132 | ptag = %Q|#{ptag1}flickr #{photo_id}#{ptag2}| |
|---|
| 133 | photo = flickr_photo_info(photo_id.to_s, 'thumbnail') |
|---|
| 134 | flickr_image = %Q|<img title="#{photo[:title]}" alt="#{photo[:title]}" src="#{photo[:src]}">| |
|---|
| 135 | |
|---|
| 136 | <<-FORM |
|---|
| 137 | <h3 class="subtitle">Flickr</h3> |
|---|
| 138 | <input type="hidden" name="#{FLICKER_FORM_PID}" value="#{photo_id}"> |
|---|
| 139 | <div class="field title"> |
|---|
| 140 | #{flickr_image} |
|---|
| 141 | <input type="button" onclick="flickr_edit_insert("#{ptag}")" value="#{@flickr_label_form_add}"> |
|---|
| 142 | </div> |
|---|
| 143 | <script type="text/javascript"><!-- |
|---|
| 144 | function flickr_edit_insert(photo_id) { |
|---|
| 145 | window.document.forms[0].body.value += photo_id; |
|---|
| 146 | } |
|---|
| 147 | //--> |
|---|
| 148 | </script> |
|---|
| 149 | FORM |
|---|
| 150 | end |
|---|
| 151 | |
|---|
| 152 | def flickr_slideshow(tag, id = nil) |
|---|
| 153 | id ||= @conf['flickr.id'] |
|---|
| 154 | return unless id |
|---|
| 155 | %Q|<iframe align="center" src="http://www.flickr.com/slideShow/index.gne?user_id=#{id}&tags=#{tag}" frameBorder="0" width="500" scrolling="no" height="500"></iframe>| |
|---|
| 156 | end |
|---|
| 157 | |
|---|
| 158 | def flickr_slideshow_by_set(set_id) |
|---|
| 159 | return unless set_id |
|---|
| 160 | %Q|<iframe align="center" src="http://www.flickr.com/slideShow/index.gne?set_id=#{set_id}" frameBorder="0" width="500" scrolling="no" height="500"></iframe>| |
|---|
| 161 | end |
|---|
| 162 | |
|---|
| 163 | module Flickr |
|---|
| 164 | class Request < Hash |
|---|
| 165 | def initialize(api_key, secret = nil) |
|---|
| 166 | self['api_key'] = api_key |
|---|
| 167 | @secret = secret |
|---|
| 168 | end |
|---|
| 169 | |
|---|
| 170 | def open(*param, &block) |
|---|
| 171 | Kernel::open(query, *param, &block) |
|---|
| 172 | end |
|---|
| 173 | |
|---|
| 174 | def query |
|---|
| 175 | sign = @secret ? "&api_sig=#{signature}" : '' |
|---|
| 176 | base_url + sort.map{|key, val| "#{key}=#{val}" }.join('&') + sign |
|---|
| 177 | end |
|---|
| 178 | |
|---|
| 179 | def signature |
|---|
| 180 | data = sort.map{|key, val| "#{key}#{val}" }.join |
|---|
| 181 | Digest::MD5.hexdigest("#{@secret}#{data}") |
|---|
| 182 | end |
|---|
| 183 | |
|---|
| 184 | def base_url |
|---|
| 185 | 'http://api.flickr.com/services/rest/?' |
|---|
| 186 | end |
|---|
| 187 | end |
|---|
| 188 | |
|---|
| 189 | class RequestAuth < Request |
|---|
| 190 | def base_url |
|---|
| 191 | 'http://www.flickr.com/services/auth/?' |
|---|
| 192 | end |
|---|
| 193 | end |
|---|
| 194 | end |
|---|