flickrcaptionr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +72 -0
- data/Rakefile +2 -0
- data/bin/flickrcaptionr-cli +64 -0
- data/bin/flickrcaptionr-web +37 -0
- data/flickrcaptionr.gemspec +24 -0
- data/fonts/Coda-Heavy.ttf +0 -0
- data/lib/flickrcaptionr/app.rb +90 -0
- data/lib/flickrcaptionr/config.rb +33 -0
- data/lib/flickrcaptionr/exceptions.rb +2 -0
- data/lib/flickrcaptionr/fetcher.rb +42 -0
- data/lib/flickrcaptionr/fetchers/base.rb +22 -0
- data/lib/flickrcaptionr/fetchers/flickr.rb +56 -0
- data/lib/flickrcaptionr/fetchers/oembed.rb +29 -0
- data/lib/flickrcaptionr/processor.rb +60 -0
- data/lib/flickrcaptionr/version.rb +3 -0
- data/lib/flickrcaptionr.rb +16 -0
- data/pub/bootstrap.min.css +387 -0
- data/views/index.haml +67 -0
- metadata +165 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 James Harrison
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# flickrcaptionr
|
2
|
+
|
3
|
+
flickrcaptionr is a gem which lets you easily retrieve images (from flickr and other sources), resize them (cropping etc as desired), and overlay classic "image macro" text on them.
|
4
|
+
|
5
|
+
It can be used as a web service, command-line tool or as a library in your application.
|
6
|
+
|
7
|
+
You will need your own API key for flickr if you want to get images from there. oEmbed API enabled sources are also supported, such as tumblr, for which an API key is not required (but source image resolutions may be limited). Direct image URLs can also be passed to the application for resizing and thumbnailing.
|
8
|
+
|
9
|
+
## Dependencies
|
10
|
+
|
11
|
+
flickrcaptionr has no non-gem dependencies other than ImageMagick's convert tool, Ruby 1.9 or greater (1.9.3 recommended) and the standard Ruby net/http library.
|
12
|
+
|
13
|
+
On Ubuntu systems, ImageMagick can be installed with:
|
14
|
+
|
15
|
+
sudo apt-get install imagemagick
|
16
|
+
|
17
|
+
On Mac systems, ImageMagick can be installed with:
|
18
|
+
|
19
|
+
sudo port install ImageMagick
|
20
|
+
|
21
|
+
You can check everything is working by running `convert -version`. If you see something like `Version: ImageMagick 6.6.0-4 2012-04-30 Q16 http://www.imagemagick.org`, everything is probably just fine. Greater version numbers are untested, but anything newer than 6.4.x the line *should* work fine.
|
22
|
+
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add this line to your application's Gemfile:
|
27
|
+
|
28
|
+
gem 'flickrcaptionr'
|
29
|
+
|
30
|
+
And then execute:
|
31
|
+
|
32
|
+
$ bundle
|
33
|
+
|
34
|
+
Or install it standalone as:
|
35
|
+
|
36
|
+
$ gem install flickrcaptionr
|
37
|
+
|
38
|
+
## Usage
|
39
|
+
|
40
|
+
To fetch, resize and caption images from the command line use:
|
41
|
+
|
42
|
+
$ flickrcaptionr-cli [options] url
|
43
|
+
|
44
|
+
To provide a web service, spin up the webapp with:
|
45
|
+
|
46
|
+
$ flickrcaptionr-web [options]
|
47
|
+
|
48
|
+
Point your browser at the URL given in the output, typically `http://localhost:4567`. You'll probably want to read the help on these.
|
49
|
+
|
50
|
+
Configuration for flickrcaptionr is stored in a Yaml file, by default at ~/.flickrcaptionr.yml. You can change this if you like. The CLI or web tools can create this file for you, and set options in it. For instance, to set your Flickr API key:
|
51
|
+
|
52
|
+
$ flickrcaptionr-cli -f 21k41poj52oi5j3oj522oj5i3
|
53
|
+
|
54
|
+
You only need to do this once and then you're set.
|
55
|
+
|
56
|
+
A more comprehensive example of the CLI follows:
|
57
|
+
|
58
|
+
$ flickrcaptionr-cli --caption-font-size=48 --caption "BLUE. BLUE EVERYWHERE." \
|
59
|
+
--resize 400x400 "http://assets.talkunafraid.co.uk/img/IMG_0311.jpg"
|
60
|
+
|
61
|
+
|
62
|
+
## Contributing
|
63
|
+
|
64
|
+
1. Fork it
|
65
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
66
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
67
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
68
|
+
5. Create new Pull Request
|
69
|
+
|
70
|
+
## License
|
71
|
+
|
72
|
+
See the LICENSE file. Long story short, MIT, go crazy.
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
3
|
+
require 'flickrcaptionr'
|
4
|
+
require 'trollop'
|
5
|
+
opts = Trollop::options do
|
6
|
+
version "flickrcaptionr #{Flickrcaptionr::VERSION} (c) James Harrison"
|
7
|
+
banner <<-EOS
|
8
|
+
flickrcaptionr is a tool to retrieve images from Flickr and many popular OEmbed-enabled web services.
|
9
|
+
|
10
|
+
This is the cli tool, for command line operation.
|
11
|
+
|
12
|
+
"Persistent" configuration options are stored in a YAML file, by default at ~/.flickrcaptionr.yml. This file is common across all flickrcaptionr services. Passing options to this tool, with or without a URL to retrieve, will generate this file for you.
|
13
|
+
|
14
|
+
For instance:
|
15
|
+
|
16
|
+
flickrcaptionr-cli -f 21k41poj52oi5j3oj522oj5i3
|
17
|
+
|
18
|
+
will set the Flickr API key used by this client for future operations.
|
19
|
+
|
20
|
+
Operation-specific options like resize width and height, overlay text settings, etc are not persisted in this manner
|
21
|
+
|
22
|
+
Usage:
|
23
|
+
flickrcaptionr-cli [options] url
|
24
|
+
|
25
|
+
Options:
|
26
|
+
EOS
|
27
|
+
opt :config_path, "Configuration file path", type: String, default: '~/.flickrcaptionr.yml'
|
28
|
+
opt :output_path, "File output path (default is to output to current working directory)", type: String
|
29
|
+
opt :flickr_api_key, "Flickr API key (not needed if you don't want to use flickr)", type: String
|
30
|
+
opt :resize, "Resize images to this size (as WxH, ie 300x400)", type: String
|
31
|
+
opt :caption, "Add a caption to the image", type: String
|
32
|
+
opt :caption_font_path, "Select font to use for the caption", type: String
|
33
|
+
opt :caption_font_size, "Select font size to use for the caption", type: Integer
|
34
|
+
opt :caption_font_stroke, "Select font stroke width to use for the caption", type: Integer
|
35
|
+
end
|
36
|
+
|
37
|
+
url = ARGV.shift
|
38
|
+
|
39
|
+
config_path = opts[:config_path]
|
40
|
+
c = Flickrcaptionr::Config.new(config_path, {:output_path => opts[:output_path], :flickr_api_key=>opts[:flickr_api_key]})
|
41
|
+
if url and url.size > 0
|
42
|
+
f = Flickrcaptionr::Fetcher.new
|
43
|
+
p = Flickrcaptionr::Processor.new
|
44
|
+
caption_opts = {}
|
45
|
+
if opts[:caption_given]
|
46
|
+
caption_opts[:font_path] = opts[:caption_font_path] if opts[:caption_font_path_given]
|
47
|
+
caption_opts[:font_size] = opts[:caption_font_size] if opts[:caption_font_size_given]
|
48
|
+
caption_opts[:font_stroke] = opts[:caption_font_stroke] if opts[:caption_font_stroke_given]
|
49
|
+
end
|
50
|
+
file = f.fetch(url)
|
51
|
+
if opts[:resize_given]
|
52
|
+
rd = opts[:resize].split("x")
|
53
|
+
if rd.size == 2
|
54
|
+
resized_path = p.resize!(file, rd[0].to_i, rd[1].to_i)
|
55
|
+
p.add_text!(resized_path, opts[:caption], caption_opts) if opts[:caption_given]
|
56
|
+
else
|
57
|
+
puts "Resize string not understood, format is widthxheight, like 300x400"
|
58
|
+
end
|
59
|
+
else
|
60
|
+
p.add_text!(file, opts[:caption], caption_opts) if opts[:caption_given]
|
61
|
+
end
|
62
|
+
else
|
63
|
+
puts "No URL provided, not fetching anything. flickrcaptionr-cli -h for usage."
|
64
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
3
|
+
require 'flickrcaptionr'
|
4
|
+
require 'trollop'
|
5
|
+
opts = Trollop::options do
|
6
|
+
version "flickrcaptionr #{Flickrcaptionr::VERSION} (c) James Harrison"
|
7
|
+
banner <<-EOS
|
8
|
+
flickrcaptionr is a tool to retrieve images from Flickr and many popular OEmbed-enabled web services.
|
9
|
+
|
10
|
+
This is the web service, and is typically run thusly:
|
11
|
+
|
12
|
+
flickrcaptionr-web -o /some/path/to/store/images
|
13
|
+
|
14
|
+
The -o parameter is only needed on first run and may be omitted subsequently.
|
15
|
+
|
16
|
+
"Persistent" configuration options are stored in a YAML file, by default at ~/.flickrcaptionr.yml.
|
17
|
+
This file is common across all flickrcaptionr services. Passing options to this tool, with or without a URL to retrieve, will generate this file for you.
|
18
|
+
|
19
|
+
For instance:
|
20
|
+
|
21
|
+
flickrcaptionr-web -f 21k41poj52oi5j3oj522oj5i3
|
22
|
+
|
23
|
+
will set the Flickr API key used by this client for future operations.
|
24
|
+
|
25
|
+
Usage:
|
26
|
+
flickrcaptionr-web [options]
|
27
|
+
|
28
|
+
Options:
|
29
|
+
EOS
|
30
|
+
opt :config_path, "Configuration file path", type: String, default: '~/.flickrcaptionr.yml'
|
31
|
+
opt :output_path, "File output path (default is to output to current working directory)", type: String
|
32
|
+
opt :flickr_api_key, "Flickr API key (not needed if you don't want to use flickr)", type: String
|
33
|
+
end
|
34
|
+
config_path = opts[:config_path]
|
35
|
+
c = Flickrcaptionr::Config.new(config_path, {:output_path => opts[:output_path], :flickr_api_key=>opts[:flickr_api_key]})
|
36
|
+
|
37
|
+
Flickrcaptionr::App.run!
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/flickrcaptionr/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["James Harrison"]
|
6
|
+
gem.email = ["james@talkunafraid.co.uk"]
|
7
|
+
gem.description = %q{flickrcaptionr generates images, given a Flickr or other oEmbed-supported source, at the resolution of your choice and optionally with image-macro-style captions}
|
8
|
+
gem.summary = %q{flickrcaptionr turns Flickr images into (optionally) captioned thumbnails}
|
9
|
+
gem.homepage = "http://github.com/JamesHarrison/flickrcaptionr"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^spec/})
|
14
|
+
gem.name = "flickrcaptionr"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Flickrcaptionr::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency("ruby-oembed", ">= 0.8.7")
|
19
|
+
gem.add_dependency("trollop", ">= 1.16.2")
|
20
|
+
gem.add_dependency("dimensions", ">= 1.2.0")
|
21
|
+
gem.add_dependency("sinatra", ">= 1.3.2")
|
22
|
+
gem.add_dependency("haml", ">= 3.1.6")
|
23
|
+
gem.add_dependency("thin", ">= 1.3.1")
|
24
|
+
end
|
Binary file
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'haml'
|
3
|
+
class Flickrcaptionr::App < Sinatra::Base
|
4
|
+
set :haml, format: :html5
|
5
|
+
set :views, ::File.expand_path('../../../views', __FILE__)
|
6
|
+
@@public_files = {
|
7
|
+
"bootstrap.min.css" => "text/css"
|
8
|
+
}
|
9
|
+
helpers do
|
10
|
+
include Rack::Utils
|
11
|
+
alias_method :h, :escape_html
|
12
|
+
end
|
13
|
+
get '/' do
|
14
|
+
haml :index
|
15
|
+
end
|
16
|
+
get '/get/:image_url/:image_width/:image_height/:caption_text' do
|
17
|
+
@f ||= Flickrcaptionr::Fetcher.new
|
18
|
+
@p ||= Flickrcaptionr::Processor.new
|
19
|
+
# {"image_url"=>"https://secure.flickr.com/photos/must_love_cartoons/7474524298/",
|
20
|
+
# "image_width"=>"300", "image_height"=>"400",
|
21
|
+
# "caption_text"=>"You have angered the developer", "caption_font_size"=>"36", "caption_font_stroke"=>"2"}
|
22
|
+
|
23
|
+
if params['image_url'] and params['image_url'].size > 0
|
24
|
+
caption_opts = {}
|
25
|
+
if params['caption_text'] and params['caption_text'] != ''
|
26
|
+
caption_opts[:font_size] = params['caption_font_size'].to_i if params['caption_font_size'] and params['caption_font_size'].size > 0
|
27
|
+
caption_opts[:font_stroke] = params['caption_font_stroke'].to_i if params['caption_font_stroke'] and params['caption_font_stroke'].size > 0
|
28
|
+
end
|
29
|
+
begin
|
30
|
+
file = @f.fetch(params['image_url'])
|
31
|
+
w = params['image_width'].to_i
|
32
|
+
h = params['image_height'].to_i
|
33
|
+
if w > 0 and h > 0
|
34
|
+
file = @p.resize!(file, w, h)
|
35
|
+
end
|
36
|
+
file = @p.add_text!(file, params['caption_text'], caption_opts) if params['caption_text'] and params['caption_text'] != ''
|
37
|
+
send_file file
|
38
|
+
rescue Exception => e
|
39
|
+
params['error'] = e.message
|
40
|
+
end
|
41
|
+
else
|
42
|
+
params['error'] = "You didn't supply a URL. Not sure what you expect me to do without that."
|
43
|
+
end
|
44
|
+
haml :index
|
45
|
+
end
|
46
|
+
post '/' do
|
47
|
+
@f ||= Flickrcaptionr::Fetcher.new
|
48
|
+
@p ||= Flickrcaptionr::Processor.new
|
49
|
+
# {"image_url"=>"https://secure.flickr.com/photos/must_love_cartoons/7474524298/",
|
50
|
+
# "image_width"=>"300", "image_height"=>"400",
|
51
|
+
# "caption_text"=>"You have angered the developer", "caption_font_size"=>"36", "caption_font_stroke"=>"2"}
|
52
|
+
|
53
|
+
if params['image_url'] and params['image_url'].size > 0
|
54
|
+
|
55
|
+
caption_opts = {}
|
56
|
+
if params['caption_text'] and params['caption_text'] != ''
|
57
|
+
caption_opts[:font_size] = params['caption_font_size'].to_i if params['caption_font_size'] and params['caption_font_size'].size > 0
|
58
|
+
caption_opts[:font_stroke] = params['caption_font_stroke'].to_i if params['caption_font_stroke'] and params['caption_font_stroke'].size > 0
|
59
|
+
end
|
60
|
+
begin
|
61
|
+
file = @f.fetch(params['image_url'])
|
62
|
+
w = params['image_width'].to_i
|
63
|
+
h = params['image_height'].to_i
|
64
|
+
if w > 0 and h > 0
|
65
|
+
file = @p.resize!(file, w, h)
|
66
|
+
end
|
67
|
+
file = @p.add_text!(file, params['caption_text'], caption_opts) if params['caption_text'] and params['caption_text'] != ''
|
68
|
+
redirect "/image/#{File.basename(file)}"
|
69
|
+
rescue Exception => e
|
70
|
+
params['error'] = e.message
|
71
|
+
end
|
72
|
+
|
73
|
+
else
|
74
|
+
params['error'] = "You didn't supply a URL. Not sure what you expect me to do without that."
|
75
|
+
end
|
76
|
+
haml :index
|
77
|
+
end
|
78
|
+
get '/image/:filename' do
|
79
|
+
send_file File.join(Flickrcaptionr::Config.output_path, params['filename'])
|
80
|
+
end
|
81
|
+
get '/favicon.ico' do
|
82
|
+
""
|
83
|
+
end
|
84
|
+
@@public_files.each do |public_file, public_file_type|
|
85
|
+
get "/#{public_file}" do
|
86
|
+
content_type(public_file_type)
|
87
|
+
::File.open(::File.expand_path("../../../pub/#{public_file}", __FILE__)).read
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Flickrcaptionr::Config
|
2
|
+
# TODO: DRY this out.
|
3
|
+
def initialize(config_path, user_options={})
|
4
|
+
user_options.delete_if{|k,v|v == nil or v == ''}
|
5
|
+
config_path = File.expand_path(config_path)
|
6
|
+
@@defaults = {flickr_api_key:'', output_path: ''}
|
7
|
+
config = YAML.load(open(config_path).read()) rescue nil
|
8
|
+
if config
|
9
|
+
@@config = config
|
10
|
+
if user_options != {} and not user_options == nil
|
11
|
+
user_options.each_pair do |k,v|
|
12
|
+
@@config[k] = v
|
13
|
+
end
|
14
|
+
File.open(config_path, 'w'){|f|f<<YAML.dump(@@config)}
|
15
|
+
end
|
16
|
+
else
|
17
|
+
begin
|
18
|
+
if user_options != {} and not user_options == nil
|
19
|
+
user_options.each_pair do |k,v|
|
20
|
+
@@config[k] = v
|
21
|
+
end
|
22
|
+
end
|
23
|
+
File.open(config_path, 'w'){|f|f<<YAML.dump(@@defaults)}
|
24
|
+
rescue Exception => e
|
25
|
+
raise ArgumentError, "Couldn't write a default config file! Check the config file path is writeable (#{e.inspect})."
|
26
|
+
end
|
27
|
+
end
|
28
|
+
puts "Configuration: "+@@config.inspect
|
29
|
+
end
|
30
|
+
def self.method_missing(method_name, *args, &block)
|
31
|
+
return @@config[method_name.to_sym] rescue nil
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Flickrcaptionr::Fetcher
|
2
|
+
def initialize(fetchers=[])
|
3
|
+
if not fetchers or (fetchers and fetchers.size == 0)
|
4
|
+
fetchers = [Flickrcaptionr::Fetchers::Flickr, Flickrcaptionr::Fetchers::OEmbed]
|
5
|
+
end
|
6
|
+
@fetchers = []
|
7
|
+
# Spin up each fetcher
|
8
|
+
for f in fetchers
|
9
|
+
@fetchers.push(f.new)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
def fetch(url)
|
13
|
+
puts "Fetching #{url}..."
|
14
|
+
for f in @fetchers
|
15
|
+
if f.can_handle_url?(url)
|
16
|
+
to_get = f.fetch(url)
|
17
|
+
return do_fetch(to_get, f)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
# If none of the matchers hit it but we appear to be a direct image URL, just go get it!
|
21
|
+
if /^.+\.(png|gif|jpg|jpeg)$/i.match(url)
|
22
|
+
return do_fetch(url, Flickrcaptionr::Fetchers::Base.new)
|
23
|
+
end
|
24
|
+
raise Flickrcaptionr::RequestNotFetchableException, "Couldn't find any suitable image fetcher for this URL. Try supplying a direct image URL if possible."
|
25
|
+
end
|
26
|
+
def do_fetch(to_get, fetcher)
|
27
|
+
out_name = File.basename(to_get)
|
28
|
+
if !Flickrcaptionr::Config.output_path or Flickrcaptionr::Config.output_path == ''
|
29
|
+
out_name = File.join(Dir.pwd, out_name)
|
30
|
+
else
|
31
|
+
out_name = File.join(Flickrcaptionr::Config.output_path, out_name)
|
32
|
+
end
|
33
|
+
unless File.exists?(out_name)
|
34
|
+
puts "Downloading #{to_get}..."
|
35
|
+
fetcher.download_file(to_get, out_name)
|
36
|
+
puts "Written file to #{out_name}"
|
37
|
+
else
|
38
|
+
puts "Already got #{to_get}, not redownloading"
|
39
|
+
end
|
40
|
+
return out_name
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
# Base Fetcher, all others inherit from this. Don't use it directly - it won't do anything.
|
4
|
+
class Flickrcaptionr::Fetchers::Base
|
5
|
+
# Setup the fetcher
|
6
|
+
def initialize
|
7
|
+
|
8
|
+
end
|
9
|
+
# Resolve the exact file URL to download
|
10
|
+
def fetch(url)
|
11
|
+
end
|
12
|
+
# Downloads a file to a given location using a simple HTTP GET
|
13
|
+
def download_file(url, out_path)
|
14
|
+
uri = URI(url)
|
15
|
+
resp = Net::HTTP.get_response(uri)
|
16
|
+
open(out_path, "wb"){|f| f.write(resp.body) }
|
17
|
+
end
|
18
|
+
# Should return true if a given URL can be handled by this fetcher.
|
19
|
+
def can_handle_url?(url)
|
20
|
+
return false
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'json'
|
2
|
+
# NOTE: Since flickr is the main service this is designed for, this will catch anything
|
3
|
+
# that looks like a number on its own as a URL (no http:// or anything) to treat as a
|
4
|
+
# Flickr Photo ID.
|
5
|
+
class Flickrcaptionr::Fetchers::Flickr < Flickrcaptionr::Fetchers::Base
|
6
|
+
def initialize
|
7
|
+
@@api_key = Flickrcaptionr::Config.flickr_api_key
|
8
|
+
@@flickr_regexes = [/(?!www\.flickr.com|secure\.flickr.com|flickr.com).+\/(\d+)\/.*/,/^(\d+)$/]
|
9
|
+
end
|
10
|
+
def fetch(url)
|
11
|
+
unless @@api_key
|
12
|
+
raise Flickrcaptionr::FetcherNotConfiguredException, "Flickr API requires an API key! Configure one in your configuration file."
|
13
|
+
end
|
14
|
+
photo_id = nil
|
15
|
+
@@flickr_regexes.each do |regex|
|
16
|
+
md = regex.match(url)
|
17
|
+
if md
|
18
|
+
photo_id = md[1]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
unless photo_id
|
22
|
+
raise Flickrcaptionr::RequestNotFetchableException, "Could not retrieve #{url}, couldn't figure out the photo ID from that URL"
|
23
|
+
end
|
24
|
+
api_req_uri = URI.parse("http://api.flickr.com/services/rest/?method=flickr.photos.getSizes&format=json&api_key=#{@@api_key}&photo_id=#{photo_id.to_s}")
|
25
|
+
api_data = {}
|
26
|
+
begin
|
27
|
+
api_resp = Net::HTTP.get_response(api_req_uri) # Fetch it
|
28
|
+
api_data = JSON.load(api_resp.body.gsub("jsonFlickrApi(","")[0..-2]) # Note we have to remove the JSONP chunks here so Ruby's JSON lib will parse it
|
29
|
+
rescue Exception => e
|
30
|
+
raise Flickrcaptionr::RequestNotFetchableException, "Could not retrieve #{url}, API request failed (underlying request URL #{api_req_uri.inspect})\n#{e.inspect}\n#{e.backtrace}"
|
31
|
+
end
|
32
|
+
# We now have data!
|
33
|
+
if api_data['stat'] != 'ok'
|
34
|
+
raise Flickrcaptionr::RequestNotFetchableException, "Could not retrieve #{url}, API request returned an error from Flickr! (underlying request URL #{api_req_uri.inspect}, response was #{api_data.inspect})"
|
35
|
+
end
|
36
|
+
if api_data['sizes']['candownload'] != 1
|
37
|
+
raise Flickrcaptionr::RequestNotFetchableException, "Could not retrieve #{url}, image requested is not downloadable"
|
38
|
+
end
|
39
|
+
# We've now made sure we can fetch these.
|
40
|
+
# Okay, now we want the biggest image we can lay our hands on.
|
41
|
+
img = api_data['sizes']['size'].sort_by{|s|s['width'].to_i}.reverse[0]
|
42
|
+
return img['source']
|
43
|
+
end
|
44
|
+
def can_handle_url?(url)
|
45
|
+
@@flickr_regexes.each do |regex|
|
46
|
+
if regex.match(url)
|
47
|
+
if @@api_key
|
48
|
+
return true
|
49
|
+
else
|
50
|
+
raise Flickrcaptionr::FetcherNotConfiguredException, "Flickr API requires an API key!"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'oembed'
|
2
|
+
class Flickrcaptionr::Fetchers::OEmbed < Flickrcaptionr::Fetchers::Base
|
3
|
+
def initialize
|
4
|
+
OEmbed::Providers.register_all
|
5
|
+
end
|
6
|
+
def fetch(url)
|
7
|
+
# OEmbed::Providers.get("https://www.youtube.com/watch?v=mNrXMOSkBas")
|
8
|
+
# Try and fetch this URL
|
9
|
+
resp = OEmbed::Providers.get(url)
|
10
|
+
# Now figure out what the heck in our oembed response is actually the image we're seeking
|
11
|
+
if resp
|
12
|
+
for key in %w(url thumbnail_url)
|
13
|
+
if resp[key] and resp[key] != nil
|
14
|
+
return resp[key]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
# If we're here, we either didn't retrieve any suitable image URL, or our provider broke
|
19
|
+
raise Flickrcaptionr::RequestNotFetchableException, "Could not retrieve #{url}"
|
20
|
+
end
|
21
|
+
def can_handle_url?(url)
|
22
|
+
OEmbed::Providers.urls.each_pair do |k,v|
|
23
|
+
if k.match(url)
|
24
|
+
return true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'dimensions'
|
3
|
+
class Flickrcaptionr::Processor
|
4
|
+
def initialize
|
5
|
+
Flickrcaptionr::Processor.has_dependencies?
|
6
|
+
|
7
|
+
end
|
8
|
+
# Resize an image, fitting the space provided as best as possible with a centre-weighted crop
|
9
|
+
def resize!(path, width, height)
|
10
|
+
out_filename = File.expand_path(path)
|
11
|
+
# Now pull the basename out and add our size string
|
12
|
+
out_filename = File.join(File.dirname(out_filename), File.basename(out_filename).gsub(/(.+)\.([A-Za-z0-9]{3,4})$/,'\1-'+"#{width.to_i.to_s}x#{height.to_i.to_s}"+'.\2'))
|
13
|
+
if File.exists?(out_filename)
|
14
|
+
puts "Not resizing, #{out_filename} already exists"
|
15
|
+
else
|
16
|
+
puts "Resizing #{path} to #{width.to_i.to_s}x#{height.to_i.to_s} at #{out_filename}"
|
17
|
+
res = `convert #{path} -resize #{width.to_i.to_s}x#{height.to_i.to_s}^ -gravity center -extent #{width.to_i.to_s}x#{height.to_i.to_s} #{out_filename}`
|
18
|
+
end
|
19
|
+
return out_filename
|
20
|
+
end
|
21
|
+
# Add some funky macro text to an image.
|
22
|
+
# Takes an optional hash of :font_path, :font_size and :font_stroke (defaults: bundled Coda Heavy font, 36, 2)
|
23
|
+
def add_text!(path, text, opts={})
|
24
|
+
out_filename = File.expand_path(path)
|
25
|
+
# Now pull the basename out and add our size string
|
26
|
+
out_filename = File.join(File.dirname(out_filename), File.basename(out_filename).gsub(/(.+)\.([A-Za-z0-9]{3,4})$/,'\1-'+Digest::SHA1.hexdigest(text+opts.to_s)+'.\2'))
|
27
|
+
# Generate our text layer
|
28
|
+
if File.exists?(out_filename)
|
29
|
+
puts "Already added text to this image, not doing it again"
|
30
|
+
else
|
31
|
+
puts "Adding text '#{text}' to #{path}"
|
32
|
+
`convert -background none -fill white -font "#{opts[:font_path] ? opts[:font_path] : (File.join(File.dirname(__FILE__), '..', '..', 'fonts', 'Coda-Heavy.ttf' ))}" -stroke black -strokewidth #{opts[:font_stroke] ? opts[:font_stroke].to_s : 2.to_s} -pointsize #{opts[:font_size] ? opts[:font_size].to_s : 36.to_s} -size #{((Dimensions.width(path)-10).to_s)} -gravity Center caption:'#{text.gsub(/[^A-Za-z0-9 \-"\.,]/,"")}' caption-tmp.png`
|
33
|
+
`composite caption-tmp.png #{path} -compose atop -gravity South #{out_filename}`
|
34
|
+
`rm -rf caption-tmp.png`
|
35
|
+
end
|
36
|
+
return out_filename
|
37
|
+
end
|
38
|
+
# Checks for presence of required tools
|
39
|
+
def self.has_dependencies?
|
40
|
+
unless self.which('convert')
|
41
|
+
raise SystemCallError, "ImageMagick is required to use this library.\nYou can install it on Ubuntu/Debian with 'sudo apt-get install imagemagick', or on OSX with 'port install ImageMagick'.\nSpecifically I need 'convert' in my PATH."
|
42
|
+
end
|
43
|
+
unless self.which('composite')
|
44
|
+
raise SystemCallError, "ImageMagick is required to use this library.\nYou can install it on Ubuntu/Debian with 'sudo apt-get install imagemagick', or on OSX with 'port install ImageMagick'.\nSpecifically I need 'composite' in my PATH."
|
45
|
+
end
|
46
|
+
end
|
47
|
+
private
|
48
|
+
# Utility method to identify if a program is available and executable.
|
49
|
+
# Basically a clone of the unix tool 'which'
|
50
|
+
def self.which(cmd)
|
51
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
52
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
53
|
+
exts.each { |ext|
|
54
|
+
bin = "#{path}/#{cmd}#{ext}"
|
55
|
+
return bin if File.executable? bin
|
56
|
+
}
|
57
|
+
end
|
58
|
+
return nil
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
3
|
+
require "flickrcaptionr/version"
|
4
|
+
|
5
|
+
module Flickrcaptionr
|
6
|
+
module Fetchers
|
7
|
+
end
|
8
|
+
end
|
9
|
+
require 'flickrcaptionr/config'
|
10
|
+
require 'flickrcaptionr/exceptions'
|
11
|
+
require 'flickrcaptionr/processor'
|
12
|
+
require 'flickrcaptionr/fetchers/base'
|
13
|
+
require 'flickrcaptionr/fetchers/flickr'
|
14
|
+
require 'flickrcaptionr/fetchers/oembed'
|
15
|
+
require 'flickrcaptionr/fetcher'
|
16
|
+
require 'flickrcaptionr/app'
|
@@ -0,0 +1,387 @@
|
|
1
|
+
/*!
|
2
|
+
* Bootstrap v2.0.4
|
3
|
+
*
|
4
|
+
* Copyright 2012 Twitter, Inc
|
5
|
+
* Licensed under the Apache License v2.0
|
6
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
*
|
8
|
+
* Designed and built with all the love in the world @twitter by @mdo and @fat.
|
9
|
+
*/
|
10
|
+
.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";}
|
11
|
+
.clearfix:after{clear:both;}
|
12
|
+
.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}
|
13
|
+
.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}
|
14
|
+
article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
|
15
|
+
audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
|
16
|
+
audio:not([controls]){display:none;}
|
17
|
+
html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
|
18
|
+
a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
|
19
|
+
a:hover,a:active{outline:0;}
|
20
|
+
sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
|
21
|
+
sup{top:-0.5em;}
|
22
|
+
sub{bottom:-0.25em;}
|
23
|
+
img{max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}
|
24
|
+
#map_canvas img{max-width:none;}
|
25
|
+
button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
|
26
|
+
button,input{*overflow:visible;line-height:normal;}
|
27
|
+
button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
|
28
|
+
button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
|
29
|
+
input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;}
|
30
|
+
input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
|
31
|
+
textarea{overflow:auto;vertical-align:top;}
|
32
|
+
body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;}
|
33
|
+
a{color:#0088cc;text-decoration:none;}
|
34
|
+
a:hover{color:#005580;text-decoration:underline;}
|
35
|
+
.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";}
|
36
|
+
.row:after{clear:both;}
|
37
|
+
[class*="span"]{float:left;margin-left:20px;}
|
38
|
+
.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
|
39
|
+
.span12{width:940px;}
|
40
|
+
.span11{width:860px;}
|
41
|
+
.span10{width:780px;}
|
42
|
+
.span9{width:700px;}
|
43
|
+
.span8{width:620px;}
|
44
|
+
.span7{width:540px;}
|
45
|
+
.span6{width:460px;}
|
46
|
+
.span5{width:380px;}
|
47
|
+
.span4{width:300px;}
|
48
|
+
.span3{width:220px;}
|
49
|
+
.span2{width:140px;}
|
50
|
+
.span1{width:60px;}
|
51
|
+
.offset12{margin-left:980px;}
|
52
|
+
.offset11{margin-left:900px;}
|
53
|
+
.offset10{margin-left:820px;}
|
54
|
+
.offset9{margin-left:740px;}
|
55
|
+
.offset8{margin-left:660px;}
|
56
|
+
.offset7{margin-left:580px;}
|
57
|
+
.offset6{margin-left:500px;}
|
58
|
+
.offset5{margin-left:420px;}
|
59
|
+
.offset4{margin-left:340px;}
|
60
|
+
.offset3{margin-left:260px;}
|
61
|
+
.offset2{margin-left:180px;}
|
62
|
+
.offset1{margin-left:100px;}
|
63
|
+
.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";}
|
64
|
+
.row-fluid:after{clear:both;}
|
65
|
+
.row-fluid [class*="span"]{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574%;*margin-left:2.0744680846382977%;}
|
66
|
+
.row-fluid [class*="span"]:first-child{margin-left:0;}
|
67
|
+
.row-fluid .span12{width:99.99999998999999%;*width:99.94680850063828%;}
|
68
|
+
.row-fluid .span11{width:91.489361693%;*width:91.4361702036383%;}
|
69
|
+
.row-fluid .span10{width:82.97872339599999%;*width:82.92553190663828%;}
|
70
|
+
.row-fluid .span9{width:74.468085099%;*width:74.4148936096383%;}
|
71
|
+
.row-fluid .span8{width:65.95744680199999%;*width:65.90425531263828%;}
|
72
|
+
.row-fluid .span7{width:57.446808505%;*width:57.3936170156383%;}
|
73
|
+
.row-fluid .span6{width:48.93617020799999%;*width:48.88297871863829%;}
|
74
|
+
.row-fluid .span5{width:40.425531911%;*width:40.3723404216383%;}
|
75
|
+
.row-fluid .span4{width:31.914893614%;*width:31.8617021246383%;}
|
76
|
+
.row-fluid .span3{width:23.404255317%;*width:23.3510638276383%;}
|
77
|
+
.row-fluid .span2{width:14.89361702%;*width:14.8404255306383%;}
|
78
|
+
.row-fluid .span1{width:6.382978723%;*width:6.329787233638298%;}
|
79
|
+
.container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";}
|
80
|
+
.container:after{clear:both;}
|
81
|
+
.container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";}
|
82
|
+
.container-fluid:after{clear:both;}
|
83
|
+
p{margin:0 0 9px;}p small{font-size:11px;color:#999999;}
|
84
|
+
.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;}
|
85
|
+
h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;}
|
86
|
+
h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;}
|
87
|
+
h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;}
|
88
|
+
h3{font-size:18px;line-height:27px;}h3 small{font-size:14px;}
|
89
|
+
h4,h5,h6{line-height:18px;}
|
90
|
+
h4{font-size:14px;}h4 small{font-size:12px;}
|
91
|
+
h5{font-size:12px;}
|
92
|
+
h6{font-size:11px;color:#999999;text-transform:uppercase;}
|
93
|
+
.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;}
|
94
|
+
.page-header h1{line-height:1;}
|
95
|
+
ul,ol{padding:0;margin:0 0 9px 25px;}
|
96
|
+
ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
|
97
|
+
ul{list-style:disc;}
|
98
|
+
ol{list-style:decimal;}
|
99
|
+
li{line-height:18px;}
|
100
|
+
ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}
|
101
|
+
dl{margin-bottom:18px;}
|
102
|
+
dt,dd{line-height:18px;}
|
103
|
+
dt{font-weight:bold;line-height:17px;}
|
104
|
+
dd{margin-left:9px;}
|
105
|
+
.dl-horizontal dt{float:left;width:120px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
106
|
+
.dl-horizontal dd{margin-left:130px;}
|
107
|
+
hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}
|
108
|
+
strong{font-weight:bold;}
|
109
|
+
em{font-style:italic;}
|
110
|
+
.muted{color:#999999;}
|
111
|
+
abbr[title]{cursor:help;border-bottom:1px dotted #999999;}
|
112
|
+
abbr.initialism{font-size:90%;text-transform:uppercase;}
|
113
|
+
blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;}
|
114
|
+
blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
|
115
|
+
blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
|
116
|
+
q:before,q:after,blockquote:before,blockquote:after{content:"";}
|
117
|
+
address{display:block;margin-bottom:18px;font-style:normal;line-height:18px;}
|
118
|
+
small{font-size:100%;}
|
119
|
+
cite{font-style:normal;}
|
120
|
+
code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
|
121
|
+
code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}
|
122
|
+
pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{margin-bottom:18px;}
|
123
|
+
pre code{padding:0;color:inherit;background-color:transparent;border:0;}
|
124
|
+
.pre-scrollable{max-height:340px;overflow-y:scroll;}
|
125
|
+
table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}
|
126
|
+
.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;}
|
127
|
+
.table th{font-weight:bold;}
|
128
|
+
.table thead th{vertical-align:bottom;}
|
129
|
+
.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;}
|
130
|
+
.table tbody+tbody{border-top:2px solid #dddddd;}
|
131
|
+
.table-condensed th,.table-condensed td{padding:4px 5px;}
|
132
|
+
.table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapsed;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;}
|
133
|
+
.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}
|
134
|
+
.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;}
|
135
|
+
.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px;}
|
136
|
+
.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;}
|
137
|
+
.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;}
|
138
|
+
.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
|
139
|
+
.table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;}
|
140
|
+
table .span1{float:none;width:44px;margin-left:0;}
|
141
|
+
table .span2{float:none;width:124px;margin-left:0;}
|
142
|
+
table .span3{float:none;width:204px;margin-left:0;}
|
143
|
+
table .span4{float:none;width:284px;margin-left:0;}
|
144
|
+
table .span5{float:none;width:364px;margin-left:0;}
|
145
|
+
table .span6{float:none;width:444px;margin-left:0;}
|
146
|
+
table .span7{float:none;width:524px;margin-left:0;}
|
147
|
+
table .span8{float:none;width:604px;margin-left:0;}
|
148
|
+
table .span9{float:none;width:684px;margin-left:0;}
|
149
|
+
table .span10{float:none;width:764px;margin-left:0;}
|
150
|
+
table .span11{float:none;width:844px;margin-left:0;}
|
151
|
+
table .span12{float:none;width:924px;margin-left:0;}
|
152
|
+
table .span13{float:none;width:1004px;margin-left:0;}
|
153
|
+
table .span14{float:none;width:1084px;margin-left:0;}
|
154
|
+
table .span15{float:none;width:1164px;margin-left:0;}
|
155
|
+
table .span16{float:none;width:1244px;margin-left:0;}
|
156
|
+
table .span17{float:none;width:1324px;margin-left:0;}
|
157
|
+
table .span18{float:none;width:1404px;margin-left:0;}
|
158
|
+
table .span19{float:none;width:1484px;margin-left:0;}
|
159
|
+
table .span20{float:none;width:1564px;margin-left:0;}
|
160
|
+
table .span21{float:none;width:1644px;margin-left:0;}
|
161
|
+
table .span22{float:none;width:1724px;margin-left:0;}
|
162
|
+
table .span23{float:none;width:1804px;margin-left:0;}
|
163
|
+
table .span24{float:none;width:1884px;margin-left:0;}
|
164
|
+
form{margin:0 0 18px;}
|
165
|
+
fieldset{padding:0;margin:0;border:0;}
|
166
|
+
legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:13.5px;color:#999999;}
|
167
|
+
label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px;}
|
168
|
+
input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
|
169
|
+
label{display:block;margin-bottom:5px;}
|
170
|
+
select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;}
|
171
|
+
input,textarea{width:210px;}
|
172
|
+
textarea{height:auto;}
|
173
|
+
textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#ffffff;border:1px solid #cccccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);}
|
174
|
+
input[type="radio"],input[type="checkbox"]{margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer;}
|
175
|
+
input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto;}
|
176
|
+
.uneditable-textarea{width:auto;height:auto;}
|
177
|
+
select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;}
|
178
|
+
select{width:220px;border:1px solid #bbb;}
|
179
|
+
select[multiple],select[size]{height:auto;}
|
180
|
+
select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
|
181
|
+
.radio,.checkbox{min-height:18px;padding-left:18px;}
|
182
|
+
.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;}
|
183
|
+
.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
|
184
|
+
.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}
|
185
|
+
.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
|
186
|
+
.input-mini{width:60px;}
|
187
|
+
.input-small{width:90px;}
|
188
|
+
.input-medium{width:150px;}
|
189
|
+
.input-large{width:210px;}
|
190
|
+
.input-xlarge{width:270px;}
|
191
|
+
.input-xxlarge{width:530px;}
|
192
|
+
input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0;}
|
193
|
+
.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block;}
|
194
|
+
input,textarea,.uneditable-input{margin-left:0;}
|
195
|
+
input.span12, textarea.span12, .uneditable-input.span12{width:930px;}
|
196
|
+
input.span11, textarea.span11, .uneditable-input.span11{width:850px;}
|
197
|
+
input.span10, textarea.span10, .uneditable-input.span10{width:770px;}
|
198
|
+
input.span9, textarea.span9, .uneditable-input.span9{width:690px;}
|
199
|
+
input.span8, textarea.span8, .uneditable-input.span8{width:610px;}
|
200
|
+
input.span7, textarea.span7, .uneditable-input.span7{width:530px;}
|
201
|
+
input.span6, textarea.span6, .uneditable-input.span6{width:450px;}
|
202
|
+
input.span5, textarea.span5, .uneditable-input.span5{width:370px;}
|
203
|
+
input.span4, textarea.span4, .uneditable-input.span4{width:290px;}
|
204
|
+
input.span3, textarea.span3, .uneditable-input.span3{width:210px;}
|
205
|
+
input.span2, textarea.span2, .uneditable-input.span2{width:130px;}
|
206
|
+
input.span1, textarea.span1, .uneditable-input.span1{width:50px;}
|
207
|
+
input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;border-color:#ddd;}
|
208
|
+
input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;}
|
209
|
+
.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
|
210
|
+
.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning .checkbox:focus,.control-group.warning .radio:focus,.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;}
|
211
|
+
.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
|
212
|
+
.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
|
213
|
+
.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error .checkbox:focus,.control-group.error .radio:focus,.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;}
|
214
|
+
.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
|
215
|
+
.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
|
216
|
+
.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success .checkbox:focus,.control-group.success .radio:focus,.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;}
|
217
|
+
.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}
|
218
|
+
input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
|
219
|
+
.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";}
|
220
|
+
.form-actions:after{clear:both;}
|
221
|
+
.uneditable-input{overflow:hidden;white-space:nowrap;cursor:not-allowed;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);}
|
222
|
+
:-moz-placeholder{color:#999999;}
|
223
|
+
:-ms-input-placeholder{color:#999999;}
|
224
|
+
::-webkit-input-placeholder{color:#999999;}
|
225
|
+
.help-block,.help-inline{color:#555555;}
|
226
|
+
.help-block{display:block;margin-bottom:9px;}
|
227
|
+
.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;}
|
228
|
+
.input-prepend,.input-append{margin-bottom:5px;}.input-prepend input,.input-append input,.input-prepend select,.input-append select,.input-prepend .uneditable-input,.input-append .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:middle;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend select:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{z-index:2;}
|
229
|
+
.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;}
|
230
|
+
.input-prepend .add-on,.input-append .add-on{display:inline-block;width:auto;height:18px;min-width:16px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 #ffffff;vertical-align:middle;background-color:#eeeeee;border:1px solid #ccc;}
|
231
|
+
.input-prepend .add-on,.input-append .add-on,.input-prepend .btn,.input-append .btn{margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
|
232
|
+
.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;}
|
233
|
+
.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;}
|
234
|
+
.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
|
235
|
+
.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
|
236
|
+
.input-append .uneditable-input{border-right-color:#ccc;border-left-color:#eee;}
|
237
|
+
.input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
|
238
|
+
.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
|
239
|
+
.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
|
240
|
+
.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
|
241
|
+
.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;}
|
242
|
+
.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;}
|
243
|
+
.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
|
244
|
+
.form-search label,.form-inline label{display:inline-block;}
|
245
|
+
.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;}
|
246
|
+
.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;}
|
247
|
+
.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0;}
|
248
|
+
.control-group{margin-bottom:9px;}
|
249
|
+
legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;}
|
250
|
+
.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";}
|
251
|
+
.form-horizontal .control-group:after{clear:both;}
|
252
|
+
.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right;}
|
253
|
+
.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:160px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:160px;}
|
254
|
+
.form-horizontal .help-block{margin-top:9px;margin-bottom:0;}
|
255
|
+
.form-horizontal .form-actions{padding-left:160px;}
|
256
|
+
.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 10px 4px;margin-bottom:0;font-size:13px;line-height:18px;*line-height:20px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-ms-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(top, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #cccccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;*background-color:#d9d9d9;}
|
257
|
+
.btn:active,.btn.active{background-color:#cccccc \9;}
|
258
|
+
.btn:first-child{*margin-left:0;}
|
259
|
+
.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
|
260
|
+
.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
|
261
|
+
.btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);}
|
262
|
+
.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
|
263
|
+
.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
|
264
|
+
.btn-large [class^="icon-"]{margin-top:1px;}
|
265
|
+
.btn-small{padding:5px 9px;font-size:11px;line-height:16px;}
|
266
|
+
.btn-small [class^="icon-"]{margin-top:-1px;}
|
267
|
+
.btn-mini{padding:2px 6px;font-size:11px;line-height:14px;}
|
268
|
+
.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}
|
269
|
+
.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);}
|
270
|
+
.btn{border-color:#ccc;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);}
|
271
|
+
.btn-primary{background-color:#0074cc;background-image:-moz-linear-gradient(top, #0088cc, #0055cc);background-image:-ms-linear-gradient(top, #0088cc, #0055cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));background-image:-webkit-linear-gradient(top, #0088cc, #0055cc);background-image:-o-linear-gradient(top, #0088cc, #0055cc);background-image:linear-gradient(top, #0088cc, #0055cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);border-color:#0055cc #0055cc #003580;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0055cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0055cc;*background-color:#004ab3;}
|
272
|
+
.btn-primary:active,.btn-primary.active{background-color:#004099 \9;}
|
273
|
+
.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;*background-color:#df8505;}
|
274
|
+
.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
|
275
|
+
.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;*background-color:#a9302a;}
|
276
|
+
.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
|
277
|
+
.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;*background-color:#499249;}
|
278
|
+
.btn-success:active,.btn-success.active{background-color:#408140 \9;}
|
279
|
+
.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;*background-color:#2a85a0;}
|
280
|
+
.btn-info:active,.btn-info.active{background-color:#24748c \9;}
|
281
|
+
.btn-inverse{background-color:#414141;background-image:-moz-linear-gradient(top, #555555, #222222);background-image:-ms-linear-gradient(top, #555555, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));background-image:-webkit-linear-gradient(top, #555555, #222222);background-image:-o-linear-gradient(top, #555555, #222222);background-image:linear-gradient(top, #555555, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#222222;*background-color:#151515;}
|
282
|
+
.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;}
|
283
|
+
button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;}
|
284
|
+
button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;}
|
285
|
+
button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;}
|
286
|
+
button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;}
|
287
|
+
.btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";}
|
288
|
+
.btn-group:after{clear:both;}
|
289
|
+
.btn-group:first-child{*margin-left:0;}
|
290
|
+
.btn-group+.btn-group{margin-left:5px;}
|
291
|
+
.btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;}
|
292
|
+
.btn-group>.btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
|
293
|
+
.btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
|
294
|
+
.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
|
295
|
+
.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}
|
296
|
+
.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}
|
297
|
+
.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;}
|
298
|
+
.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
|
299
|
+
.btn-group>.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:4px;*padding-bottom:4px;}
|
300
|
+
.btn-group>.btn-mini.dropdown-toggle{padding-left:5px;padding-right:5px;}
|
301
|
+
.btn-group>.btn-small.dropdown-toggle{*padding-top:4px;*padding-bottom:4px;}
|
302
|
+
.btn-group>.btn-large.dropdown-toggle{padding-left:12px;padding-right:12px;}
|
303
|
+
.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);}
|
304
|
+
.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;}
|
305
|
+
.btn-group.open .btn-primary.dropdown-toggle{background-color:#0055cc;}
|
306
|
+
.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;}
|
307
|
+
.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;}
|
308
|
+
.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;}
|
309
|
+
.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;}
|
310
|
+
.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;}
|
311
|
+
.btn .caret{margin-top:7px;margin-left:0;}
|
312
|
+
.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);}
|
313
|
+
.btn-mini .caret{margin-top:5px;}
|
314
|
+
.btn-small .caret{margin-top:6px;}
|
315
|
+
.btn-large .caret{margin-top:6px;border-left-width:5px;border-right-width:5px;border-top-width:5px;}
|
316
|
+
.dropup .btn-large .caret{border-bottom:5px solid #000000;border-top:0;}
|
317
|
+
.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);}
|
318
|
+
.nav{margin-left:0;margin-bottom:18px;list-style:none;}
|
319
|
+
.nav>li>a{display:block;}
|
320
|
+
.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;}
|
321
|
+
.nav>.pull-right{float:right;}
|
322
|
+
.nav .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;}
|
323
|
+
.nav li+.nav-header{margin-top:9px;}
|
324
|
+
.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;}
|
325
|
+
.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}
|
326
|
+
.nav-list>li>a{padding:3px 15px;}
|
327
|
+
.nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;}
|
328
|
+
.nav-list [class^="icon-"]{margin-right:2px;}
|
329
|
+
.nav-list .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}
|
330
|
+
.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";}
|
331
|
+
.nav-tabs:after,.nav-pills:after{clear:both;}
|
332
|
+
.nav-tabs>li,.nav-pills>li{float:left;}
|
333
|
+
.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}
|
334
|
+
.nav-tabs{border-bottom:1px solid #ddd;}
|
335
|
+
.nav-tabs>li{margin-bottom:-1px;}
|
336
|
+
.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;}
|
337
|
+
.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
|
338
|
+
.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
|
339
|
+
.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#0088cc;}
|
340
|
+
.nav-stacked>li{float:none;}
|
341
|
+
.nav-stacked>li>a{margin-right:0;}
|
342
|
+
.nav-tabs.nav-stacked{border-bottom:0;}
|
343
|
+
.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
|
344
|
+
.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
|
345
|
+
.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
|
346
|
+
.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;}
|
347
|
+
.nav-pills.nav-stacked>li>a{margin-bottom:3px;}
|
348
|
+
.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}
|
349
|
+
.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;}
|
350
|
+
.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
|
351
|
+
.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;}
|
352
|
+
.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580;}
|
353
|
+
.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;border-bottom-color:#333333;}
|
354
|
+
.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;}
|
355
|
+
.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;}
|
356
|
+
.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);}
|
357
|
+
.tabs-stacked .open>a:hover{border-color:#999999;}
|
358
|
+
.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";}
|
359
|
+
.tabbable:after{clear:both;}
|
360
|
+
.tab-content{overflow:auto;}
|
361
|
+
.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;}
|
362
|
+
.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
|
363
|
+
.tab-content>.active,.pill-content>.active{display:block;}
|
364
|
+
.tabs-below>.nav-tabs{border-top:1px solid #ddd;}
|
365
|
+
.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;}
|
366
|
+
.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below>.nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;}
|
367
|
+
.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd;}
|
368
|
+
.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;}
|
369
|
+
.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}
|
370
|
+
.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}
|
371
|
+
.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
|
372
|
+
.tabs-left>.nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}
|
373
|
+
.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}
|
374
|
+
.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}
|
375
|
+
.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
|
376
|
+
.tabs-right>.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}
|
377
|
+
.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}
|
378
|
+
.alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#c09853;}
|
379
|
+
.alert-heading{color:inherit;}
|
380
|
+
.alert .close{position:relative;top:-2px;right:-21px;line-height:18px;}
|
381
|
+
.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;}
|
382
|
+
.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;}
|
383
|
+
.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;}
|
384
|
+
.alert-block{padding-top:14px;padding-bottom:14px;}
|
385
|
+
.alert-block>p,.alert-block>ul{margin-bottom:0;}
|
386
|
+
.alert-block p+p{margin-top:5px;}
|
387
|
+
body{margin-top:20px;}
|
data/views/index.haml
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
!!!
|
2
|
+
%html{lang: 'en'}
|
3
|
+
%head
|
4
|
+
%title
|
5
|
+
%link{rel: 'stylesheet', href: '/bootstrap.min.css'}
|
6
|
+
%body
|
7
|
+
.container
|
8
|
+
.row
|
9
|
+
.span12.well
|
10
|
+
%h1
|
11
|
+
flickrcaptionr
|
12
|
+
%small Putting words in your reasonably-sized images since 2012
|
13
|
+
- if params['error']
|
14
|
+
.alert
|
15
|
+
%h3 Uh-oh, something went wrong
|
16
|
+
= params['error']
|
17
|
+
%form.form-horizontal{action: '/', method: 'post'}
|
18
|
+
%fieldset
|
19
|
+
%legend
|
20
|
+
Where do we get your image?
|
21
|
+
.control-group
|
22
|
+
%label.control-label Image Source
|
23
|
+
.controls
|
24
|
+
%input.input-xlarge{type: 'text', name: 'image_url'}
|
25
|
+
%p.help-block
|
26
|
+
This can be a URL to a Flickr page, a Flickr image ID (just the number), or a link to an image directly.
|
27
|
+
%br
|
28
|
+
OEmbed services like Instagram and Tumblr pages are also supported.
|
29
|
+
%fieldset
|
30
|
+
%legend
|
31
|
+
Do you want that small, tiny or normal-sized?
|
32
|
+
.control-group
|
33
|
+
%label.control-label Image Width
|
34
|
+
.controls
|
35
|
+
%input{type: 'text', name: 'image_width', value: params[:image_width] ? params[:image_width] : 300}
|
36
|
+
.control-group
|
37
|
+
%label.control-label Image Height
|
38
|
+
.controls
|
39
|
+
%input{type: 'text', name: 'image_height', value: params[:image_height] ? params[:image_height] : 400}
|
40
|
+
%p.help-block
|
41
|
+
We can resize your image to whichever size you desire. The image will be cropped to fit these dimensions if required.
|
42
|
+
%fieldset
|
43
|
+
%legend
|
44
|
+
Add a caption to your image
|
45
|
+
%small Don't forget, LOLcat haz own languages
|
46
|
+
.control-group
|
47
|
+
%label.control-label Caption Text
|
48
|
+
.controls
|
49
|
+
%input.input-xlarge{type: 'text', name: 'caption_text', value: params[:caption_text] ? params[:caption_text] : ''}
|
50
|
+
.control-group
|
51
|
+
%label.control-label Font Size
|
52
|
+
.controls
|
53
|
+
%input.input-xlarge{type: 'text', name: 'caption_font_size', value: params[:caption_font_size] ? params[:caption_font_size] : 36}
|
54
|
+
.control-group
|
55
|
+
%label.control-label Font Stroke Weight
|
56
|
+
.controls
|
57
|
+
%input.input-xlarge{type: 'text', name: 'caption_font_stroke', value: params[:caption_font_stroke] ? params[:caption_font_stroke] : 2}
|
58
|
+
.form-actions
|
59
|
+
%button.btn.btn-large.btn-primary{type:'submit'} Generate my image!
|
60
|
+
|
61
|
+
%p
|
62
|
+
You can also use the GET API as follows:
|
63
|
+
%code
|
64
|
+
\/get/flickr-photo-id-or-encoded-url/width/height/caption-text
|
65
|
+
%p
|
66
|
+
For instance,
|
67
|
+
%a{href: "/get/6792442709/300/400/I%20has%20a%20LED"} something like this.
|
metadata
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: flickrcaptionr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- James Harrison
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ruby-oembed
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.8.7
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.8.7
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: trollop
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.16.2
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.16.2
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: dimensions
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.2.0
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.2.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: sinatra
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.3.2
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.3.2
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: haml
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 3.1.6
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 3.1.6
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: thin
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.3.1
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.3.1
|
110
|
+
description: flickrcaptionr generates images, given a Flickr or other oEmbed-supported
|
111
|
+
source, at the resolution of your choice and optionally with image-macro-style captions
|
112
|
+
email:
|
113
|
+
- james@talkunafraid.co.uk
|
114
|
+
executables:
|
115
|
+
- flickrcaptionr-cli
|
116
|
+
- flickrcaptionr-web
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- .gitignore
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- bin/flickrcaptionr-cli
|
126
|
+
- bin/flickrcaptionr-web
|
127
|
+
- flickrcaptionr.gemspec
|
128
|
+
- fonts/Coda-Heavy.ttf
|
129
|
+
- lib/flickrcaptionr.rb
|
130
|
+
- lib/flickrcaptionr/app.rb
|
131
|
+
- lib/flickrcaptionr/config.rb
|
132
|
+
- lib/flickrcaptionr/exceptions.rb
|
133
|
+
- lib/flickrcaptionr/fetcher.rb
|
134
|
+
- lib/flickrcaptionr/fetchers/base.rb
|
135
|
+
- lib/flickrcaptionr/fetchers/flickr.rb
|
136
|
+
- lib/flickrcaptionr/fetchers/oembed.rb
|
137
|
+
- lib/flickrcaptionr/processor.rb
|
138
|
+
- lib/flickrcaptionr/version.rb
|
139
|
+
- pub/bootstrap.min.css
|
140
|
+
- views/index.haml
|
141
|
+
homepage: http://github.com/JamesHarrison/flickrcaptionr
|
142
|
+
licenses: []
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
none: false
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
|
+
none: false
|
155
|
+
requirements:
|
156
|
+
- - ! '>='
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
159
|
+
requirements: []
|
160
|
+
rubyforge_project:
|
161
|
+
rubygems_version: 1.8.24
|
162
|
+
signing_key:
|
163
|
+
specification_version: 3
|
164
|
+
summary: flickrcaptionr turns Flickr images into (optionally) captioned thumbnails
|
165
|
+
test_files: []
|