Skip to content

Instantly share code, notes, and snippets.

@suwa320
Created September 9, 2012 10:32
Show Gist options
  • Select an option

  • Save suwa320/3683693 to your computer and use it in GitHub Desktop.

Select an option

Save suwa320/3683693 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
require 'jekyll'
require 'flickraw'
require 'fileutils'
require 'ostruct'
module Jekyll
class Site
attr_accessor :photostream, :photosets
def site_payload
{"site" => self.config.merge({
"time" => self.time,
"posts" => self.posts.sort { |a, b| b <=> a },
"pages" => self.pages,
"html_pages" => self.pages.reject { |page| !page.html? },
"photosets" => self.photosets,
"photostream" => self.photostream,
"categories" => post_attr_hash('categories'),
"tags" => post_attr_hash('tags')})}
end
end
class FlickrPhoto
@@cache_dir = nil
class << self
def cache_dir=(dir)
@@cache_dir = dir
end
def cache_dir
@@cache_dir
end
end
attr_accessor :title, :url, :source, :width, :height, :sizes
def initialize(photo)
photo = OpenStruct.new(:id => photo) if not photo.respond_to?(:id)
if not cache_enable? or not load_cache(photo.id)
load_photo(photo)
end
end
def to_liquid
ret = {
'title' => title,
'url' => url,
'source' => source,
'width' => width,
'height' => height
}
sizes.each do |k, v|
ret["#{k.gsub(/ +/, '_')}_url"] = v.url
ret["#{k.gsub(/ +/, '_')}_source"] = v.source
ret["#{k.gsub(/ +/, '_')}_width"] = v.width
ret["#{k.gsub(/ +/, '_')}_height"] = v.height
end
ret
end
private
def load_photo(photo)
attempt = 0
begin
photo = FlickrAPI.photo_info(photo.id) if not photo.title
sizes = FlickrAPI.photo_sizes(photo.id).
inject({}){|h, v| h[v.label.downcase] = v; h}
rescue Timeout::Error, Errno::ETIMEDOUT, Errno::ECONNRESET
attempt += 1
retry if attempt < 10
end
compsize = lambda {|s|
(s.width.to_i >= s.height.to_i) ?
(1024 - s.width.to_i).abs : (768 - s.height.to_i).abs
}
large = sizes.reject{|k, v| k.to_s =~ /original/i}.
min{|(ak, av), (bk, bv)| compsize.call(av) <=> compsize.call(bv)}[0]
@id = photo.id
@title = photo.title
@url = sizes[large].url
@source = sizes[large].source
@width = sizes[large].width
@height = sizes[large].height
@sizes = sizes
cache if cache_enable?
end
def load_cache(id)
cache_file = File.join(@@cache_dir, id.to_s)
if File.exist?(cache_file)
@id, @title, @url, @source,
@width, @height, @sizes = Marshal.load(open(cache_file))
else
nil
end
end
def cache_enable?
return false if not @@cache_dir
FileUtils.mkdir_p(@@cache_dir)
FileTest.directory?(@@cache_dir) and FileTest.writable?(@@cache_dir)
end
def cache
open(File.join(@@cache_dir, @id.to_s), 'w') do |f|
f.write(Marshal.dump([@id, @title, @url, @source, @width, @height, @sizes]))
end
end
end
class FlickrAPI
class << self
def setup(config)
FlickRaw.api_key = config['api_key']
FlickRaw.shared_secret = config['shared_secret']
flickr.access_token = config['auth_token']
flickr.access_secret = config['secret']
FlickrPhoto.cache_dir = config['cache_dir']
end
def photo_info(photo_id)
flickr.photos.getInfo(:photo_id => photo_id)
end
def photo_sizes(photo_id)
flickr.photos.getSizes(:photo_id => photo_id)
end
def photostream(user_id, limit = nil)
page = 1
photos = []
begin
response = flickr.people.getPublicPhotos(
:user_id => user_id,
:per_page => 500,
:page => page
)
photos += response.to_a
page += 1
end while response['pages'].to_i >= page and
((limit and photos.size < limit) or not limit)
limit ||= -1
photos = photos[0..limit].map{|v| FlickrPhoto.new(v)}
end
def photoset_list(user_id)
page = 1
sets = []
begin
response = flickr.photosets.getList(
:user_id => user_id,
:per_page => 500,
:page => page
)
sets += response.to_a
page += 1
end while response['pages'].to_i >= page
sets
end
def photoset(set_id)
flickr.photosets.getInfo(:photoset_id => set_id)
end
def photoset_photos(set)
photos = []
page = 1
begin
response = flickr.photosets.
getPhotos(:photoset_id => set.id)
photos += response.photo
page += 1
end while response['pages'].to_i >= page
photos.map{|v| FlickrPhoto.new(v)}
end
end
end
class FlickrPager < Pager
attr_accessor :all_posts
def initialize(config, page, all_posts)
config = config.dup
config['paginate'] = 1 # per_page
super config, page, all_posts
@all_posts = all_posts
end
def to_liquid
super.merge(
'previous_url' => (not previous_page) ? nil :
File.join(
all_posts[previous_page - 1].dir,
all_posts[previous_page - 1].url),
'next_url' => (not next_page) ? nil :
File.join(
all_posts[next_page - 1].dir,
all_posts[next_page - 1].url))
end
end
class FlickrPage < Page
attr_reader :dir
def initialize(site, base, dir, photos, page, title)
@site = site
@base = base
@dir = File.join(dir, page.to_s)
@name = 'index.html'
self.process(@name)
self.read_yaml(File.join(base, '_layouts'), 'flickr_page.html')
self.data['flickr_photos'] = photos
self.data['title'] = title
end
end
class FlickrPlugin < Generator
safe true
priority :low
def generate(site)
return unless config = site.config['flickr']
FlickrAPI.setup(config)
# photostream
if config['photostream'] and config['user_id']
generate_photostream(site)
end
# photosets
if config['photosets'] and config['user_id']
generate_photosets(site)
end
end
def generate_photostream(site)
config = site.config['flickr']
page = 1
per_page = config['photostream']['per_page'].to_i || 50
limit = config['photostream']['limit'].to_i || 100
photos = FlickrAPI.photostream(config['user_id'], limit)
pages = limit / per_page + ((limit % per_page == 0) ? 0 : 1)
dir = File.join(File::SEPARATOR, 'flickr', 'photostream')
photostream_pages = []
pages.times do |i|
page = i + 1
photostream_pages << FlickrPage.new(
site, site.source, dir,
photos[per_page * i, per_page], page,
"Photostream #{(page > 1) ? "##{page}" : ""}")
site.pages << photostream_pages.last
site.photostream = photostream_pages.last if page == 1
end
photostream_pages.each_with_index do |page, i|
page.pager = FlickrPager.new(site.config, i + 1, photostream_pages)
end
end
def generate_photosets(site)
config = site.config['flickr']['photosets']
user_id = site.config['flickr']['user_id']
per_page = (config['per_page']) ? config['per_page'].to_i : 50
sets = FlickrAPI.photoset_list(user_id)
site.photosets = []
sets.each do |set|
photos = FlickrAPI.photoset_photos(set)
pages = photos.size / per_page +
((photos.size % per_page == 0) ? 0 : 1)
dir = File.join(File::SEPARATOR, 'flickr', 'photosets', set.id.to_s)
set_pages = []
pages.times do |i|
page = i + 1
set_pages << FlickrPage.new(
site, site.source, dir,
photos[per_page * i, per_page], page,
"#{set.title} #{(page > 1) ? "##{page}" : ""}")
site.pages << set_pages.last
site.photosets << set_pages.last if page == 1
end
set_pages.each_with_index do |page, i|
page.pager = FlickrPager.new(site.config, i + 1, set_pages)
end
end
end
end
module FlickrTag
def render_tag(photos)
ret = '<div class="gallery">'
photos.each do |v|
s = v.source
i = v.sizes[@size].source
w = v.sizes[@size].width
h = v.sizes[@size].height
ret += %{<a href="#{s}"><img src="#{i}" width="#{w}" height="#{h}" /></a>}
end
ret + '</div>'
end
end
class FlickrPhotostreamTag < Liquid::Tag
include FlickrTag
def initialize(tag_name, text, tokens)
super
@size, @limit = text.strip.split(/\s+/)
@size ||= 'square'
@limit = @limit.to_i - 1
end
def render(context)
user_id = context.registers[:site].config['flickr']['user_id']
photos = FlickrAPI.photostream(user_id, @limit)
render_tag(photos)
end
end
class FlickrPhotosetTag < Liquid::Tag
include FlickrTag
def initialize(tag_name, text, tokens)
super
@set_id, @size, @limit = text.strip.split(/\s+/)
@size ||= 'square'
@limit = @limit.to_i - 1
end
def render(context)
set = FlickrAPI.photoset(@set_id)
photos = FlickrAPI.photoset_photos(set)
render_tag(photos[0..@limit])
end
end
class FlickrGalleryTag < Liquid::Block
include FlickrTag
def initialize(tag_name, text, tokens)
super
@size = text.strip
@photo_ids = @nodelist.first.strip.split(/\s+/m)
end
def render(context)
photos = @photo_ids.inject([]){|arr, v| arr << FlickrPhoto.new(v); arr}
render_tag(photos)
end
end
class FlickrLinkTag < Liquid::Tag
def initialize(tag_name, text, tokens)
super
@photo_id, *@text = text.strip.split(/\s+/)
end
def render(context)
photo = FlickrPhoto.new(@photo_id)
<<-tag.strip
<a class="flickr" href="#{photo.source}">#{@text.join(' ')}</a>
tag
end
end
end
Liquid::Template.register_tag('flickr_photostream', Jekyll::FlickrPhotostreamTag)
Liquid::Template.register_tag('flickr_photoset', Jekyll::FlickrPhotosetTag)
Liquid::Template.register_tag('flickr_gallery', Jekyll::FlickrGalleryTag)
Liquid::Template.register_tag('flickr_link', Jekyll::FlickrLinkTag)
if $0 == __FILE__
puts "API Key and shared secret can be obtained at following URL"
puts "http://www.flickr.com/services/apps/by/me"
puts
print "Your API Key: "
FlickRaw.api_key = gets.strip
print "Your shared secret: "
FlickRaw.shared_secret = gets.strip
token = flickr.get_request_token
auth_url = flickr.get_authorize_url(token['oauth_token'], :perms => 'delete')
puts "Open this url in your process to complete the authication process : #{auth_url}"
puts "Copy here the number given when you complete the process."
puts
print "Number: "
verify = gets.strip
print "Your Username: "
username = gets.strip
user = flickr.people.findByUsername(:username => username)
begin
flickr.get_access_token(
token['oauth_token'], token['oauth_token_secret'], verify)
login = flickr.test.login
puts "User ID: #{user['usid']}"
puts "API Key: #{FlickRaw.api_key}"
puts "Shared Secret: #{FlickRaw.shared_secret}"
puts "Access Token: #{flickr.access_token}"
puts "access_secret: #{flickr.access_secret}"
rescue FlickRaw::FailedResponse => e
puts "Authentication failed : #{e.msg}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment