shutterbug 0.0.11 → 0.1.0
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.
- data/.ruby-version +1 -1
- data/.travis.yml +2 -3
- data/Guardfile +5 -0
- data/README.md +59 -10
- data/config.ru +5 -3
- data/demo/{withIframe.html → iframe_example.html} +0 -0
- data/demo/index.html +7 -24
- data/demo/oil-and-water/heatbath.svg +20 -0
- data/demo/oil-and-water/ke-gradient.svg +27 -0
- data/demo/oil-and-water/oil-and-water.svg +487 -0
- data/demo/simple_example.html +35 -0
- data/demo/svg_example.html +571 -0
- data/images/shutterbug.jpg +0 -0
- data/lib/shutterbug.rb +4 -6
- data/lib/shutterbug/cache_manager.rb +6 -0
- data/lib/shutterbug/cache_manager/cache_entry.rb +19 -0
- data/lib/shutterbug/cache_manager/no_cache.rb +19 -0
- data/lib/shutterbug/configuration.rb +20 -24
- data/lib/shutterbug/handlers.rb +7 -0
- data/lib/shutterbug/handlers/convert_handler.rb +38 -0
- data/lib/shutterbug/handlers/file_handlers.rb +9 -0
- data/lib/shutterbug/handlers/file_handlers/base.rb +39 -0
- data/lib/shutterbug/handlers/file_handlers/html_file.rb +22 -0
- data/lib/shutterbug/handlers/file_handlers/png_file.rb +23 -0
- data/lib/shutterbug/handlers/js_file_handler.rb +27 -0
- data/lib/shutterbug/{shutterbug.js → handlers/shutterbug.js} +26 -3
- data/lib/shutterbug/phantom_job.rb +17 -12
- data/lib/shutterbug/rackapp.rb +33 -31
- data/lib/shutterbug/storage.rb +6 -0
- data/lib/shutterbug/storage/file_storage.rb +20 -0
- data/lib/shutterbug/storage/s3_storage.rb +75 -0
- data/shutterbug.gemspec +3 -0
- data/spec/shared_examples_for_file_handlers.rb +16 -0
- data/spec/shared_examples_for_handlers.rb +26 -0
- data/spec/shared_examples_for_storage.rb +17 -0
- data/spec/shutterbug/configuration_spec.rb +83 -0
- data/spec/shutterbug/convert_handler_spec.rb +29 -0
- data/spec/shutterbug/file_storage_spec.rb +5 -0
- data/spec/shutterbug/html_file_handler_spec.rb +10 -0
- data/spec/shutterbug/js_file_handler_spec.rb +4 -0
- data/spec/shutterbug/png_file_handler_spec.rb +10 -0
- data/spec/shutterbug/rackapp_spec.rb +49 -41
- data/spec/shutterbug/s3_storage_spec.rb +12 -0
- metadata +205 -105
- data/lib/shutterbug/bug_file.rb +0 -22
- data/lib/shutterbug/html_file.rb +0 -3
- data/lib/shutterbug/js_file.rb +0 -11
- data/lib/shutterbug/png_file.rb +0 -3
- data/lib/shutterbug/service.rb +0 -39
Binary file
|
data/lib/shutterbug.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
module Shutterbug
|
2
|
-
VERSION = "0.0
|
3
|
-
autoload :Service, "shutterbug/service"
|
2
|
+
VERSION = "0.1.0"
|
4
3
|
autoload :Rackapp, "shutterbug/rackapp"
|
5
4
|
autoload :Configuration, "shutterbug/configuration"
|
6
|
-
autoload :
|
7
|
-
autoload :
|
8
|
-
autoload :PngFile, "shutterbug/png_file"
|
9
|
-
autoload :JsFile, "shutterbug/js_file"
|
5
|
+
autoload :Storage, "shutterbug/storage"
|
6
|
+
autoload :Handlers, "shutterbug/handlers"
|
10
7
|
autoload :PhantomJob, "shutterbug/phantom_job"
|
8
|
+
autoload :CacheManager, "shutterbug/cache_manager"
|
11
9
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Shutterbug
|
2
|
+
module CacheManager
|
3
|
+
class CacheEntry
|
4
|
+
attr_accessor :key
|
5
|
+
attr_accessor :url
|
6
|
+
attr_accessor :preview_url
|
7
|
+
|
8
|
+
def initialize(storage)
|
9
|
+
@key = storage.filename
|
10
|
+
@url = storage.url
|
11
|
+
@preview_url = storage.url
|
12
|
+
end
|
13
|
+
|
14
|
+
def image_tag
|
15
|
+
"<img src='#{self.preview_url}' alt='#{self.preview_url}'>"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Shutterbug
|
2
|
+
module CacheManager
|
3
|
+
class NoCache
|
4
|
+
attr_accessor :entries
|
5
|
+
def initialize
|
6
|
+
@entries = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def find(key)
|
10
|
+
return @entries[key]
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_entry(cache_entry)
|
14
|
+
@entries[cache_entry.key] = cache_entry
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'tmpdir'
|
1
2
|
module Shutterbug
|
2
3
|
class Configuration
|
3
4
|
|
@@ -5,6 +6,10 @@ module Shutterbug
|
|
5
6
|
attr_accessor :path_prefix
|
6
7
|
attr_accessor :resource_dir
|
7
8
|
attr_accessor :phantom_bin_path
|
9
|
+
attr_accessor :s3_bin
|
10
|
+
attr_accessor :s3_key
|
11
|
+
attr_accessor :s3_secret
|
12
|
+
attr_accessor :cache_manager
|
8
13
|
|
9
14
|
def self.instance(opts={})
|
10
15
|
return @instance || @instance = self.new(opts)
|
@@ -15,43 +20,34 @@ module Shutterbug
|
|
15
20
|
self.path_prefix = opts[:path_prefix] || "/shutterbug"
|
16
21
|
self.resource_dir = opts[:resource_dir] || Dir.tmpdir
|
17
22
|
self.phantom_bin_path = opts[:phantom_bin_path] || "phantomjs"
|
23
|
+
self.s3_bin = opts[:s3_bin]
|
24
|
+
self.s3_key = opts[:s3_key]
|
25
|
+
self.s3_secret = opts[:s3_secret]
|
26
|
+
self.cache_manager = opts[:cache_manager] || Shutterbug::CacheManager::NoCache.new
|
18
27
|
end
|
19
28
|
|
20
|
-
def
|
21
|
-
"#{
|
29
|
+
def fs_path_for(filename)
|
30
|
+
File.join(resource_dir,"phantom_#{filename}")
|
22
31
|
end
|
23
32
|
|
24
|
-
def
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
def js_file
|
29
|
-
File.join(File.dirname(__FILE__),"shutterbug.js")
|
33
|
+
def url_prefix
|
34
|
+
"#{uri_prefix}#{path_prefix}"
|
30
35
|
end
|
31
36
|
|
32
37
|
def convert_path
|
33
|
-
"#{
|
34
|
-
end
|
35
|
-
def convert_regex
|
36
|
-
/#{path_prefix}\/make_snapshot/
|
38
|
+
"#{url_prefix}/make_snapshot"
|
37
39
|
end
|
38
40
|
|
39
|
-
def
|
40
|
-
"#{
|
41
|
-
end
|
42
|
-
def png_regex
|
43
|
-
/#{path_prefix}\/get_png\/([^\/]+)/
|
41
|
+
def base_url(req)
|
42
|
+
req.POST()['base_url'] || req.referrer || "#{req.scheme}://#{req.host_with_port}"
|
44
43
|
end
|
45
44
|
|
46
|
-
def
|
47
|
-
|
48
|
-
end
|
49
|
-
def html_regex
|
50
|
-
/#{path_prefix}\/get_html\/([^\/]+)/
|
45
|
+
def storage
|
46
|
+
use_s3? ? Storage::S3Storage : Storage::FileStorage
|
51
47
|
end
|
52
48
|
|
53
|
-
def
|
54
|
-
|
49
|
+
def use_s3?
|
50
|
+
return (self.s3_bin && self.s3_key && self.s3_secret)
|
55
51
|
end
|
56
52
|
end
|
57
53
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
module Shutterbug
|
3
|
+
module Handlers
|
4
|
+
class ConvertHandler
|
5
|
+
|
6
|
+
def initialize(_config = Configuration.instance)
|
7
|
+
@config = _config
|
8
|
+
end
|
9
|
+
|
10
|
+
def regex
|
11
|
+
/#{@config.path_prefix}\/make_snapshot/
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle(helper, req, env)
|
15
|
+
response_text = convert(req).image_tag
|
16
|
+
helper.good_response(response_text,'text/plain')
|
17
|
+
end
|
18
|
+
|
19
|
+
def convert(req)
|
20
|
+
html = req.POST()['content'] || ""
|
21
|
+
width = req.POST()['width'] || 1000
|
22
|
+
height = req.POST()['height'] || 700
|
23
|
+
css = req.POST()['css'] || ""
|
24
|
+
job = PhantomJob.new(@config.base_url(req), html, css, width, height)
|
25
|
+
unless (cache_entry = @config.cache_manager.find(job.cache_key))
|
26
|
+
job.rasterize
|
27
|
+
html_entry = Shutterbug::CacheManager::CacheEntry.new(job.html_file)
|
28
|
+
png_entry = Shutterbug::CacheManager::CacheEntry.new(job.png_file)
|
29
|
+
html_entry.preview_url = png_entry.preview_url
|
30
|
+
@config.cache_manager.add_entry(html_entry)
|
31
|
+
cache_entry = @config.cache_manager.add_entry(png_entry)
|
32
|
+
end
|
33
|
+
# return the image tag
|
34
|
+
return cache_entry
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
module Shutterbug
|
3
|
+
module Handlers
|
4
|
+
module FileHandlers
|
5
|
+
class Base
|
6
|
+
attr_accessor :config
|
7
|
+
|
8
|
+
def self.instance
|
9
|
+
return @instance || self.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(_config = Configuration.instance)
|
13
|
+
self.config = _config
|
14
|
+
end
|
15
|
+
|
16
|
+
def urlify(name)
|
17
|
+
"#{self.path_prefix}/#{name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def path_prefix
|
21
|
+
"#{self.config.path_prefix}/get_#{file_extension}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def filename_matcher
|
25
|
+
"(([^\/|\.]+)\.?([^\/]+))?"
|
26
|
+
end
|
27
|
+
|
28
|
+
def regex
|
29
|
+
/#{path_prefix}\/#{filename_matcher}/
|
30
|
+
end
|
31
|
+
|
32
|
+
def filename(base)
|
33
|
+
"#{base}.#{file_extension}"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Shutterbug
|
2
|
+
module Handlers
|
3
|
+
module FileHandlers
|
4
|
+
class HtmlFile < Base
|
5
|
+
|
6
|
+
def file_extension
|
7
|
+
"html"
|
8
|
+
end
|
9
|
+
|
10
|
+
def mime_type
|
11
|
+
"text/html"
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle(helper, req, env)
|
15
|
+
sha = regex.match(req.path)[1]
|
16
|
+
file = @config.storage.new(filename(sha),self)
|
17
|
+
helper.good_response(file.get_content, self.mime_type)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Shutterbug
|
2
|
+
module Handlers
|
3
|
+
module FileHandlers
|
4
|
+
class PngFile < Base
|
5
|
+
|
6
|
+
def file_extension
|
7
|
+
"png"
|
8
|
+
end
|
9
|
+
|
10
|
+
def mime_type
|
11
|
+
"image/png"
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle(helper, req, env)
|
15
|
+
local_filename = regex.match(req.path)[1]
|
16
|
+
file = @config.storage.new(local_filename,self)
|
17
|
+
helper.good_response(file.get_content, self.mime_type)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Shutterbug
|
2
|
+
module Handlers
|
3
|
+
class JsFileHandler
|
4
|
+
|
5
|
+
def self.js_path
|
6
|
+
"#{Configuration.instance.url_prefix}/shutterbug.js"
|
7
|
+
end
|
8
|
+
|
9
|
+
def regex
|
10
|
+
/#{@config.path_prefix}\/shutterbug.js/
|
11
|
+
end
|
12
|
+
|
13
|
+
def js_file
|
14
|
+
File.join(File.dirname(__FILE__),"shutterbug.js")
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(_config=Configuration.instance())
|
18
|
+
@config = _config
|
19
|
+
@javascript = File.read(js_file).gsub(/CONVERT_PATH/,@config.convert_path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle(helper, req, env)
|
23
|
+
helper.good_response(@javascript, 'application/javascript')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
/*global $ */
|
2
2
|
(function(){
|
3
|
+
var $ = window.$;
|
3
4
|
|
4
5
|
var getBaseUrl = function() {
|
5
6
|
var base = window.location.href;
|
@@ -72,17 +73,31 @@
|
|
72
73
|
}
|
73
74
|
}
|
74
75
|
var self = this;
|
76
|
+
var time = 0;
|
77
|
+
var counter = $("<span>");
|
78
|
+
counter.html(time);
|
79
|
+
|
80
|
+
$(self.imgDst).html("creating snapshot: ").append(counter);
|
81
|
+
var timer = setInterval(function(t) {
|
82
|
+
time = time + 1;
|
83
|
+
counter.html(time);
|
84
|
+
}, 1000);
|
85
|
+
|
75
86
|
$.ajax({
|
76
87
|
url: "CONVERT_PATH",
|
77
88
|
type: "POST",
|
78
89
|
data: html
|
79
|
-
}).
|
90
|
+
}).success(function(msg) {
|
80
91
|
if(self.imgDst) {
|
81
92
|
$(self.imgDst).html(msg);
|
82
93
|
}
|
83
94
|
if (self.callback) {
|
84
95
|
self.callback(msg);
|
85
96
|
}
|
97
|
+
clearInterval(timer);
|
98
|
+
}).fail(function(e) {
|
99
|
+
$(self.imgDst).html("snapshot failed");
|
100
|
+
clearInterval(timer);
|
86
101
|
});
|
87
102
|
};
|
88
103
|
|
@@ -95,7 +110,16 @@
|
|
95
110
|
destination.postMessage(JSON.stringify(message),"*");
|
96
111
|
};
|
97
112
|
|
98
|
-
window.Shutterbug = function(selector,imgDst,callback,id) {
|
113
|
+
window.Shutterbug = function(selector,imgDst,callback,id,jQuery) {
|
114
|
+
if (typeof(jQuery) != "undefined" && jQuery != null) {
|
115
|
+
$ = jQuery;
|
116
|
+
}
|
117
|
+
// If we still don't have a valid jQuery, try setting it from the global jQuery default.
|
118
|
+
// This can happen if shutterbug.js is included before jquery.js
|
119
|
+
if ((typeof($) == "undefined" || $ == null) && typeof(window.$) != "undefined" && window.$ != null) {
|
120
|
+
$ = window.$;
|
121
|
+
}
|
122
|
+
|
99
123
|
var shutterbugInstance = {
|
100
124
|
element: selector,
|
101
125
|
imgDst: imgDst,
|
@@ -150,5 +174,4 @@
|
|
150
174
|
});
|
151
175
|
return shutterbugInstance;
|
152
176
|
};
|
153
|
-
|
154
177
|
})();
|
@@ -5,7 +5,7 @@ module Shutterbug
|
|
5
5
|
attr_accessor :html_file
|
6
6
|
|
7
7
|
def program
|
8
|
-
|
8
|
+
@config.phantom_bin_path
|
9
9
|
end
|
10
10
|
|
11
11
|
def rasterize_js
|
@@ -18,10 +18,11 @@ module Shutterbug
|
|
18
18
|
@css = css
|
19
19
|
@width = width
|
20
20
|
@height = height
|
21
|
+
@config = Configuration.instance
|
21
22
|
end
|
22
23
|
|
23
24
|
def cache_key
|
24
|
-
|
25
|
+
@cache_key ||= Digest::SHA1.hexdigest("#{@html}#{@css}#{@base_url}")[0..10]
|
25
26
|
end
|
26
27
|
|
27
28
|
def document
|
@@ -42,29 +43,33 @@ module Shutterbug
|
|
42
43
|
"""
|
43
44
|
end
|
44
45
|
|
45
|
-
def
|
46
|
-
|
46
|
+
def html_file_name
|
47
|
+
"#{cache_key}.html"
|
47
48
|
end
|
48
49
|
|
49
|
-
def
|
50
|
-
|
50
|
+
def png_file_name
|
51
|
+
"#{cache_key}.png"
|
51
52
|
end
|
52
53
|
|
53
|
-
def
|
54
|
-
|
54
|
+
def input_path
|
55
|
+
@config.fs_path_for(html_file_name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def output_path
|
59
|
+
@config.fs_path_for(png_file_name)
|
55
60
|
end
|
56
61
|
|
57
62
|
def rasterize_cl
|
58
|
-
%x[#{self.program} #{self.rasterize_js} #{self.
|
63
|
+
%x[#{self.program} #{self.rasterize_js} #{self.input_path} #{self.output_path} #{@width}*#{@height}]
|
59
64
|
end
|
60
65
|
|
61
66
|
def rasterize
|
62
|
-
File.open(
|
67
|
+
File.open(input_path, 'w') do |f|
|
63
68
|
f.write(document)
|
64
69
|
end
|
65
70
|
rasterize_cl()
|
66
|
-
self.png_file = PngFile.new
|
67
|
-
self.html_file = HtmlFile.new
|
71
|
+
self.png_file = @config.storage.new(png_file_name, Shutterbug::Handlers::FileHandlers::PngFile.new)
|
72
|
+
self.html_file = @config.storage.new(html_file_name, Shutterbug::Handlers::FileHandlers::HtmlFile.new)
|
68
73
|
end
|
69
74
|
end
|
70
75
|
end
|