shutterbug 0.2.5 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/.travis.yml +3 -3
- data/README.md +6 -0
- data/bower.json +1 -1
- data/demo/The_Scream.jpg +0 -0
- data/demo/canvas_example.html +36 -0
- data/demo/index.html +1 -0
- data/lib/shutterbug.rb +1 -1
- data/lib/shutterbug/cache_manager.rb +2 -2
- data/lib/shutterbug/configuration.rb +4 -8
- data/lib/shutterbug/handlers.rb +5 -4
- data/lib/shutterbug/handlers/convert_handler.rb +38 -16
- data/lib/shutterbug/handlers/direct_upload_handler.rb +30 -0
- data/lib/shutterbug/handlers/file_handler.rb +30 -0
- data/lib/shutterbug/handlers/js_file_handler.rb +13 -10
- data/lib/shutterbug/handlers/shutterbug.js +123 -32
- data/lib/shutterbug/phantom_job.rb +11 -10
- data/lib/shutterbug/rackapp.rb +15 -18
- data/lib/shutterbug/rasterize.js +4 -4
- data/lib/shutterbug/storage.rb +1 -1
- data/lib/shutterbug/storage/file_storage.rb +21 -8
- data/lib/shutterbug/storage/s3_storage.rb +26 -31
- data/shutterbug.gemspec +0 -1
- data/spec/shared_examples_for_handlers.rb +13 -9
- data/spec/shared_examples_for_storage.rb +14 -10
- data/spec/shutterbug/configuration_spec.rb +1 -11
- data/spec/shutterbug/convert_handler_spec.rb +5 -4
- data/spec/shutterbug/direct_upload_handler_spec.rb +7 -0
- data/spec/shutterbug/file_handler_spec.rb +7 -0
- data/spec/shutterbug/file_storage_spec.rb +2 -1
- data/spec/shutterbug/js_file_handler_spec.rb +2 -1
- data/spec/shutterbug/rackapp_spec.rb +14 -28
- data/spec/shutterbug/s3_storage_spec.rb +1 -1
- metadata +10 -12
- data/lib/shutterbug/handlers/file_handlers.rb +0 -9
- data/lib/shutterbug/handlers/file_handlers/base.rb +0 -39
- data/lib/shutterbug/handlers/file_handlers/html_file.rb +0 -22
- data/lib/shutterbug/handlers/file_handlers/png_file.rb +0 -23
- data/spec/shared_examples_for_file_handlers.rb +0 -16
- data/spec/shutterbug/html_file_handler_spec.rb +0 -10
- data/spec/shutterbug/png_file_handler_spec.rb +0 -10
@@ -1,7 +1,6 @@
|
|
1
1
|
module Shutterbug
|
2
2
|
class PhantomJob
|
3
|
-
|
4
|
-
attr_accessor :png_file
|
3
|
+
attr_accessor :image_file
|
5
4
|
attr_accessor :html_file
|
6
5
|
|
7
6
|
def program
|
@@ -12,17 +11,19 @@ module Shutterbug
|
|
12
11
|
File.join(File.dirname(__FILE__),'rasterize.js')
|
13
12
|
end
|
14
13
|
|
15
|
-
def initialize(base_url, html, css="", width=1000, height=700)
|
14
|
+
def initialize(base_url, html, css="", width=1000, height=700, format="png", quality=10)
|
16
15
|
@base_url = base_url
|
17
16
|
@html = html
|
18
17
|
@css = css
|
19
18
|
@width = width
|
20
19
|
@height = height
|
20
|
+
@format = format
|
21
|
+
@quality = quality
|
21
22
|
@config = Configuration.instance
|
22
23
|
end
|
23
24
|
|
24
25
|
def cache_key
|
25
|
-
@cache_key ||= Digest::SHA1.hexdigest("#{@html}#{@css}#{@base_url}")[0..10]
|
26
|
+
@cache_key ||= Digest::SHA1.hexdigest("#{@html}#{@css}#{@base_url}#{@format}#{@quality}")[0..10]
|
26
27
|
end
|
27
28
|
|
28
29
|
def document
|
@@ -47,8 +48,8 @@ module Shutterbug
|
|
47
48
|
"#{cache_key}.html"
|
48
49
|
end
|
49
50
|
|
50
|
-
def
|
51
|
-
"#{cache_key}
|
51
|
+
def image_file_name
|
52
|
+
"#{cache_key}.#{@format}"
|
52
53
|
end
|
53
54
|
|
54
55
|
def input_path
|
@@ -56,11 +57,11 @@ module Shutterbug
|
|
56
57
|
end
|
57
58
|
|
58
59
|
def output_path
|
59
|
-
@config.fs_path_for(
|
60
|
+
@config.fs_path_for(image_file_name)
|
60
61
|
end
|
61
62
|
|
62
63
|
def rasterize_cl
|
63
|
-
%x[#{self.program} --ignore-ssl-errors=true --ssl-protocol=any #{self.rasterize_js} #{self.input_path} #{self.output_path} #{@width}*#{@height}]
|
64
|
+
%x[#{self.program} --ignore-ssl-errors=true --ssl-protocol=any #{self.rasterize_js} #{self.input_path} #{self.output_path} #{@width}*#{@height} #{@quality}]
|
64
65
|
end
|
65
66
|
|
66
67
|
def rasterize
|
@@ -68,8 +69,8 @@ module Shutterbug
|
|
68
69
|
f.write(document)
|
69
70
|
end
|
70
71
|
rasterize_cl()
|
71
|
-
self.
|
72
|
-
self.html_file = @config.storage.new(html_file_name
|
72
|
+
self.image_file = @config.storage.new(image_file_name)
|
73
|
+
self.html_file = @config.storage.new(html_file_name)
|
73
74
|
end
|
74
75
|
end
|
75
76
|
end
|
data/lib/shutterbug/rackapp.rb
CHANGED
@@ -3,17 +3,16 @@ module Shutterbug
|
|
3
3
|
class Rackapp
|
4
4
|
|
5
5
|
DefaultHandlers = [
|
6
|
-
Shutterbug::Handlers::ConvertHandler
|
6
|
+
Shutterbug::Handlers::ConvertHandler,
|
7
|
+
Shutterbug::Handlers::DirectUploadHandler,
|
7
8
|
Shutterbug::Handlers::JsFileHandler,
|
8
|
-
Shutterbug::Handlers::
|
9
|
-
Shutterbug::Handlers::FileHandlers::HtmlFile
|
9
|
+
Shutterbug::Handlers::FileHandler
|
10
10
|
]
|
11
11
|
|
12
|
-
attr_accessor :handlers
|
13
12
|
def add_handler(klass)
|
14
|
-
instance = klass.new
|
15
|
-
log "adding handler for #{
|
16
|
-
|
13
|
+
instance = klass.new
|
14
|
+
log "adding handler for #{klass.regex} ➙ #{klass.name}"
|
15
|
+
@handlers[klass.regex] = instance
|
17
16
|
end
|
18
17
|
|
19
18
|
def add_default_handlers
|
@@ -29,26 +28,25 @@ module Shutterbug
|
|
29
28
|
log "initialized"
|
30
29
|
end
|
31
30
|
|
32
|
-
def call
|
33
|
-
req
|
34
|
-
result
|
35
|
-
handlers.keys.each do |path_regex|
|
31
|
+
def call(env)
|
32
|
+
req = Rack::Request.new(env)
|
33
|
+
result = false
|
34
|
+
@handlers.keys.each do |path_regex|
|
36
35
|
if req.path =~ path_regex
|
37
|
-
result = handlers[path_regex].handle(self, req, env)
|
36
|
+
result = @handlers[path_regex].handle(self, req, env)
|
38
37
|
end
|
39
38
|
end
|
40
39
|
result || skip(env)
|
41
40
|
end
|
42
41
|
|
43
|
-
def
|
42
|
+
def response(content, type, status=200, cachable=true)
|
44
43
|
headers = {}
|
45
44
|
size = content.respond_to?(:bytesize) ? content.bytesize : content.size
|
46
45
|
headers['Content-Length'] = size.to_s
|
47
46
|
headers['Content-Type'] = type
|
48
47
|
headers['Cache-Control'] = 'no-cache' unless cachable
|
49
|
-
|
50
|
-
|
51
|
-
return [200, headers, content]
|
48
|
+
content = [content] unless content.respond_to? 'each'
|
49
|
+
return [status, headers, content]
|
52
50
|
end
|
53
51
|
|
54
52
|
def log(string)
|
@@ -57,8 +55,7 @@ module Shutterbug
|
|
57
55
|
|
58
56
|
def skip(env)
|
59
57
|
# call the applicaiton default
|
60
|
-
@app.call
|
58
|
+
@app.call(env) if @app
|
61
59
|
end
|
62
|
-
|
63
60
|
end
|
64
61
|
end
|
data/lib/shutterbug/rasterize.js
CHANGED
@@ -2,11 +2,10 @@
|
|
2
2
|
|
3
3
|
var page = require('webpage').create(),
|
4
4
|
system = require('system'),
|
5
|
-
address, output, size;
|
5
|
+
address, output, quality, size;
|
6
6
|
|
7
7
|
if (system.args.length < 3 || system.args.length > 5) {
|
8
|
-
console.log('Usage: rasterize.js URL filename
|
9
|
-
console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
|
8
|
+
console.log('Usage: rasterize.js URL filename quality(0-100)');
|
10
9
|
phantom.exit(1);
|
11
10
|
} else {
|
12
11
|
address = system.args[1];
|
@@ -15,6 +14,7 @@ if (system.args.length < 3 || system.args.length > 5) {
|
|
15
14
|
if (system.args.length > 3) {
|
16
15
|
size = system.args[3].split('*');
|
17
16
|
page.viewportSize = { width: size[0], height: size[1] };
|
17
|
+
quality = system.args[4];
|
18
18
|
}
|
19
19
|
|
20
20
|
page.open(address, function (status) {
|
@@ -23,7 +23,7 @@ if (system.args.length < 3 || system.args.length > 5) {
|
|
23
23
|
phantom.exit();
|
24
24
|
} else {
|
25
25
|
window.setTimeout(function () {
|
26
|
-
page.render(output);
|
26
|
+
page.render(output, {quality: quality});
|
27
27
|
phantom.exit();
|
28
28
|
}, 200);
|
29
29
|
}
|
data/lib/shutterbug/storage.rb
CHANGED
@@ -1,20 +1,33 @@
|
|
1
1
|
module Shutterbug
|
2
2
|
module Storage
|
3
3
|
class FileStorage
|
4
|
-
|
5
|
-
|
6
|
-
attr_accessor :url
|
4
|
+
attr_reader :filename
|
5
|
+
attr_reader :url
|
7
6
|
|
8
|
-
|
7
|
+
MIME_TYPES = {
|
8
|
+
'.png' => 'image/png',
|
9
|
+
'.jpeg' => 'image/jpeg',
|
10
|
+
'.jpg' => 'image/jpeg',
|
11
|
+
'.html' => 'text/html',
|
12
|
+
'' => 'text/html'
|
13
|
+
}
|
14
|
+
|
15
|
+
def self.get_url(name)
|
16
|
+
"#{Handlers::FileHandler.uri_prefix}/#{name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(filename)
|
9
20
|
@filename = Configuration.instance.fs_path_for(filename)
|
10
|
-
@url =
|
21
|
+
@url = self.class.get_url(filename)
|
11
22
|
end
|
12
23
|
|
13
24
|
def get_content
|
14
|
-
|
15
|
-
return file
|
25
|
+
File.open(@filename, 'r')
|
16
26
|
end
|
17
27
|
|
28
|
+
def mime_type
|
29
|
+
MIME_TYPES[File.extname(@filename)]
|
30
|
+
end
|
18
31
|
end
|
19
32
|
end
|
20
|
-
end
|
33
|
+
end
|
@@ -3,15 +3,16 @@ module Shutterbug
|
|
3
3
|
class S3Storage
|
4
4
|
require 'fog'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
attr_reader :filename
|
7
|
+
attr_reader :url
|
8
|
+
|
9
|
+
PUT_URL_EXP_TIME = 300 # seconds
|
9
10
|
|
10
11
|
def self.connect!
|
11
12
|
Fog::Storage.new({
|
12
|
-
:provider
|
13
|
-
:aws_access_key_id
|
14
|
-
:aws_secret_access_key
|
13
|
+
:provider => 'AWS',
|
14
|
+
:aws_access_key_id => Configuration.instance.s3_key,
|
15
|
+
:aws_secret_access_key => Configuration.instance.s3_secret
|
15
16
|
})
|
16
17
|
end
|
17
18
|
|
@@ -29,47 +30,41 @@ module Shutterbug
|
|
29
30
|
@s3_bin ||= self.create_bin
|
30
31
|
end
|
31
32
|
|
32
|
-
def self.write(
|
33
|
+
def self.write(filename)
|
33
34
|
full_path = Configuration.instance.fs_path_for(filename)
|
34
35
|
if self.fs_path_exists? full_path
|
35
36
|
self.s3_bin.files.create(
|
36
|
-
:key =>
|
37
|
+
:key => filename,
|
37
38
|
:body => File.open(full_path),
|
38
39
|
:public => true)
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
|
-
def self.
|
43
|
-
|
43
|
+
def self.fs_path_exists?(filename)
|
44
|
+
File.exists?(filename)
|
44
45
|
end
|
45
46
|
|
46
|
-
def self.
|
47
|
-
|
47
|
+
def self.get_url(filename)
|
48
|
+
# Manual URL construction, no proper method implemented in FOG.
|
49
|
+
# But should be available soon, see: https://github.com/fog/fog/issues/3263
|
50
|
+
"https://#{Configuration.instance.s3_bin}.s3.amazonaws.com/#{filename}"
|
48
51
|
end
|
49
52
|
|
50
|
-
def self.
|
51
|
-
|
53
|
+
def self.put_url(filename)
|
54
|
+
expiry = (Time.now + PUT_URL_EXP_TIME).to_i
|
55
|
+
headers = {}
|
56
|
+
query = {
|
57
|
+
'x-amz-acl' => 'public-read'
|
58
|
+
}
|
59
|
+
options = { path_style: true, query: query }
|
60
|
+
self.connection.put_object_url(Configuration.instance.s3_bin, filename, expiry, headers, options)
|
52
61
|
end
|
53
62
|
|
54
|
-
def initialize(
|
55
|
-
@filename =
|
56
|
-
@
|
57
|
-
@stream_file = S3Storage.write(@filename, long_path)
|
63
|
+
def initialize(filename)
|
64
|
+
@filename = filename
|
65
|
+
@stream_file = S3Storage.write(filename)
|
58
66
|
@url = @stream_file.public_url
|
59
67
|
end
|
60
|
-
|
61
|
-
def get_content
|
62
|
-
@stream_file.body
|
63
|
-
end
|
64
|
-
|
65
|
-
def size
|
66
|
-
@stream_file.content_length
|
67
|
-
end
|
68
|
-
|
69
|
-
def redirect_s3
|
70
|
-
return [301, {"Location" => self.url}, []]
|
71
|
-
end
|
72
|
-
|
73
68
|
end
|
74
69
|
end
|
75
70
|
end
|
data/shutterbug.gemspec
CHANGED
@@ -1,26 +1,30 @@
|
|
1
1
|
shared_examples "a request handler" do
|
2
|
-
let(:config) { Shutterbug::Configuration.new()}
|
3
2
|
let(:rackapp) { mock }
|
4
3
|
let(:req) { mock }
|
5
4
|
let(:env) { mock }
|
6
|
-
let(:handler) { described_class.new
|
5
|
+
let(:handler) { described_class.new }
|
7
6
|
let(:mock_storage) do
|
8
7
|
mock({
|
9
8
|
:new => mock({
|
10
|
-
:get_content => "content"
|
9
|
+
:get_content => "content",
|
10
|
+
:mime_type => "text/plain",
|
11
|
+
:filename => "file",
|
12
|
+
:url => "url"
|
11
13
|
})
|
12
14
|
})
|
13
15
|
end
|
14
16
|
before(:each) do
|
15
|
-
|
17
|
+
Shutterbug::Configuration.instance.stub!(:storage => mock_storage)
|
16
18
|
end
|
19
|
+
|
17
20
|
it "should respond to regex" do
|
18
|
-
handler.should respond_to :regex
|
19
|
-
handler.regex.should be_kind_of Regexp
|
21
|
+
handler.class.should respond_to :regex
|
22
|
+
handler.class.regex.should be_kind_of Regexp
|
20
23
|
end
|
24
|
+
|
21
25
|
it "should respond to handle" do
|
22
26
|
handler.should respond_to :handle
|
23
|
-
rackapp.should_receive :
|
24
|
-
handler.handle(rackapp,req,env)
|
27
|
+
rackapp.should_receive :response
|
28
|
+
handler.handle(rackapp, req, env)
|
25
29
|
end
|
26
|
-
end
|
30
|
+
end
|
@@ -1,17 +1,21 @@
|
|
1
1
|
shared_examples "a storage provider" do
|
2
|
-
let(:filetype) { Shutterbug::Handlers::FileHandlers::HtmlFile.new}
|
3
2
|
let(:filename) { "somefilename.html" }
|
4
|
-
let(:provider) { described_class.new(filename,filetype) }
|
5
3
|
|
6
|
-
|
7
|
-
|
4
|
+
describe "class" do
|
5
|
+
it "should respond to get_url(name)" do
|
6
|
+
described_class.should respond_to :get_url
|
7
|
+
end
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
describe "instance" do
|
11
|
+
let(:instance) { described_class.new(filename) }
|
12
|
+
|
13
|
+
it "should respond to filename" do
|
14
|
+
instance.should respond_to :filename
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
17
|
+
it "should respond to url" do
|
18
|
+
instance.should respond_to :url
|
19
|
+
end
|
16
20
|
end
|
17
|
-
end
|
21
|
+
end
|
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
1
|
describe Shutterbug::Configuration do
|
3
|
-
|
4
2
|
let(:uri_prefix) { "http://blah.com/" }
|
5
3
|
let(:path_prefix) { "/shutterbug" }
|
6
4
|
let(:resource_dir) { "resource_dir"}
|
@@ -20,10 +18,6 @@ describe Shutterbug::Configuration do
|
|
20
18
|
}
|
21
19
|
end
|
22
20
|
|
23
|
-
|
24
|
-
# def js_file
|
25
|
-
|
26
|
-
|
27
21
|
subject { Shutterbug::Configuration.new(opts) }
|
28
22
|
|
29
23
|
describe "#fs_path_for(filename)" do |variable|
|
@@ -56,8 +50,6 @@ describe Shutterbug::Configuration do
|
|
56
50
|
end
|
57
51
|
end
|
58
52
|
|
59
|
-
|
60
|
-
|
61
53
|
describe "use_s3?" do
|
62
54
|
describe "with no S3 information" do
|
63
55
|
its(:use_s3?) { should be_false }
|
@@ -78,6 +70,4 @@ describe Shutterbug::Configuration do
|
|
78
70
|
end
|
79
71
|
end
|
80
72
|
end
|
81
|
-
|
82
|
-
|
83
|
-
end
|
73
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'shared_examples_for_handlers'
|
2
|
+
|
2
3
|
describe Shutterbug::Handlers::ConvertHandler do
|
3
4
|
let(:mock_post) do
|
4
5
|
mock(:POST => {},
|
@@ -14,16 +15,16 @@ describe Shutterbug::Handlers::ConvertHandler do
|
|
14
15
|
|
15
16
|
describe "calling phantom" do
|
16
17
|
let(:mock_results) { mock }
|
17
|
-
let(:rackapp) { mock(:
|
18
|
+
let(:rackapp) { mock(:response => true )}
|
18
19
|
let(:env) { mock }
|
19
20
|
let(:fake_file) { mock(:filename => "blub", :url => "glub")}
|
20
|
-
let(:mock_fantom) { mock(:cache_key => "1", :html_file => fake_file, :
|
21
|
+
let(:mock_fantom) { mock(:cache_key => "1", :html_file => fake_file, :image_file => fake_file) }
|
21
22
|
before(:each) do
|
22
23
|
Shutterbug::PhantomJob.stub!(:new => mock_fantom)
|
23
24
|
end
|
24
25
|
it "should invoke phantom" do
|
25
26
|
mock_fantom.should_receive(:rasterize).and_return(mock_results)
|
26
|
-
subject.handle(rackapp,req,env)
|
27
|
+
subject.handle(rackapp, req, env)
|
27
28
|
end
|
28
29
|
end
|
29
|
-
end
|
30
|
+
end
|