meme_captain 0.2.0 → 0.3.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/ChangeLog +4 -0
- data/README.md +0 -45
- data/lib/meme_captain.rb +0 -6
- data/lib/meme_captain/caption.rb +6 -4
- data/lib/meme_captain/caption_choice.rb +3 -1
- data/lib/meme_captain/image_list.rb +0 -5
- data/lib/meme_captain/text_pos.rb +8 -6
- data/lib/meme_captain/version.rb +1 -1
- data/meme_captain.gemspec +5 -18
- metadata +2 -181
- data/config.ru +0 -50
- data/doc/lightweight_front_end.md +0 -64
- data/doc/setup.md +0 -13
- data/lib/meme_captain/image_list/cache.rb +0 -49
- data/lib/meme_captain/image_list/fetch.rb +0 -28
- data/lib/meme_captain/image_list/fetch_error.rb +0 -17
- data/lib/meme_captain/image_list/source_image.rb +0 -30
- data/lib/meme_captain/meme_data.rb +0 -33
- data/lib/meme_captain/norm_params.rb +0 -92
- data/lib/meme_captain/pretty_format.rb +0 -12
- data/lib/meme_captain/server.rb +0 -303
- data/lib/meme_captain/source_fetch_fail.rb +0 -28
- data/lib/meme_captain/upload.rb +0 -30
- data/public/css/screen.css +0 -80
- data/public/favicon.ico +0 -0
- data/public/js/fabric.min.js +0 -4
- data/public/js/jquery-1.7.2.min.js +0 -4
- data/public/js/meme_captain.js +0 -391
- data/public/source_images.json +0 -234
- data/public/thumbs.jpg +0 -0
- data/public/thumbs_1330486916.jpg +0 -0
- data/public/thumbs_1333591668.jpg +0 -0
- data/public/thumbs_1334189407.jpg +0 -0
- data/public/thumbs_1334973608.jpg +0 -0
- data/public/thumbs_1336623277.jpg +0 -0
- data/public/thumbs_1336624196.jpg +0 -0
- data/public/thumbs_1339811279.jpg +0 -0
- data/public/tmp/.gitignore +0 -0
- data/script/thumb_sprites.rb +0 -76
- data/spec/image_list/fetch_spec.rb +0 -33
- data/spec/norm_params_spec.rb +0 -223
- data/spec/pretty_format_spec.rb +0 -9
- data/views/404.erb +0 -17
- data/views/index.erb +0 -130
- data/watermark.png +0 -0
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
If you want to host your own custom Meme Captain site but do not want to set
|
|
2
|
-
up the ruby backend you can use the memecaptain.com backend. In this scenario,
|
|
3
|
-
the HTML, Javscript and CSS are hosted on your web server and the meme images
|
|
4
|
-
are created on and hosted on memecaptain.com.
|
|
5
|
-
|
|
6
|
-
This is an option if you are on shared hosting and do not have access to
|
|
7
|
-
ruby or MongoDB or do not want to deal with setting them up.
|
|
8
|
-
|
|
9
|
-
Download the files at these locations and save them in your document root:
|
|
10
|
-
|
|
11
|
-
* http://memecaptain.com/
|
|
12
|
-
* http://memecaptain.com/css/screen.css
|
|
13
|
-
* http://memecaptain.com/js/fabric.min.js
|
|
14
|
-
* http://memecaptain.com/js/meme_captain.js
|
|
15
|
-
* http://memecaptain.com/source_images.json
|
|
16
|
-
|
|
17
|
-
The css in js should go in css and js directories in your document root so
|
|
18
|
-
that they match the url paths.
|
|
19
|
-
|
|
20
|
-
Find this line in js/meme_captain.js
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
genUrl = '/g',
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
and change it to
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
genUrl = 'http://memecaptain.com/g',
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
# Changing the Default Source Images
|
|
33
|
-
|
|
34
|
-
The source image thumbnails that show up on the page are driven by a JSON
|
|
35
|
-
description and a single image that contain CSS sprites. The JSON and image
|
|
36
|
-
must be regenerated to change them.
|
|
37
|
-
|
|
38
|
-
The rmagick ruby gem must be installed:
|
|
39
|
-
|
|
40
|
-
```sh
|
|
41
|
-
gem install rmagick
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Get and run the script:
|
|
45
|
-
|
|
46
|
-
```sh
|
|
47
|
-
wget https://raw.github.com/mmb/meme_captain/master/script/thumb_sprites.rb
|
|
48
|
-
RUBYOPT='r rubygems'
|
|
49
|
-
ruby thumb_sprites.rb -u URL_ROOT -s SOURCE_URL_PREFIX SOURCE_IMAGE_PATH/*
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
SOURCE_IMAGE_PATH is the directory where the source images are stored.
|
|
53
|
-
URL_ROOT is the root url of the Meme Captain installation. SOURCE_URL_PREFIX
|
|
54
|
-
is the part between the root url and the image filenames in the image urls.
|
|
55
|
-
|
|
56
|
-
For example if the images are stored in /var/www/meme.com/source and the
|
|
57
|
-
url root is http://meme.com/, use:
|
|
58
|
-
|
|
59
|
-
```sh
|
|
60
|
-
ruby thumb_sprites.rb -u http://meme.com/ -s source/ /var/www/meme.com/source/*
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Copy the generated source_images.json and thumbs_xxx.jpg files to the Meme
|
|
64
|
-
Captain document root.
|
data/doc/setup.md
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# Requirements
|
|
2
|
-
|
|
3
|
-
* a Ruby/Rack web application environment (such as
|
|
4
|
-
[Passenger](http://www.modrails.com/))
|
|
5
|
-
|
|
6
|
-
* Ruby gem dependencies (see the gemspec)
|
|
7
|
-
|
|
8
|
-
* [MongoDB](http://www.mongodb.org/)
|
|
9
|
-
|
|
10
|
-
You will most likely need a dedicated or virtual private server to run
|
|
11
|
-
MongoDB as most shared hosting does not support it. See the lightweight front
|
|
12
|
-
end document for how host the static HTML/CSS/Javascript only and use
|
|
13
|
-
memecaptain.com for the backend.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
require 'digest/sha1'
|
|
2
|
-
require 'fileutils'
|
|
3
|
-
require 'mime/types'
|
|
4
|
-
|
|
5
|
-
module MemeCaptain
|
|
6
|
-
|
|
7
|
-
module ImageList
|
|
8
|
-
|
|
9
|
-
# Mix-in for Magick::ImageList to add saving to the filesystem based on a
|
|
10
|
-
# hash.
|
|
11
|
-
module Cache
|
|
12
|
-
|
|
13
|
-
# Get the extension for this image.
|
|
14
|
-
def extension
|
|
15
|
-
{
|
|
16
|
-
'image/jpeg' => 'jpg',
|
|
17
|
-
}[mime_type] || MIME::Types[mime_type][0].extensions[0]
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Store this image in the filesystem and return its path.
|
|
21
|
-
def cache(hash_base, dir)
|
|
22
|
-
hashe = Digest::SHA1.hexdigest(hash_base)
|
|
23
|
-
|
|
24
|
-
cache_dir = File.join(dir, hashe[0,3])
|
|
25
|
-
FileUtils.mkdir_p cache_dir
|
|
26
|
-
|
|
27
|
-
file_part = hashe[3..-1]
|
|
28
|
-
fs_path = File.join(cache_dir, "#{file_part}.#{extension}")
|
|
29
|
-
|
|
30
|
-
# If there is a collision add 0's until the filename is unique.
|
|
31
|
-
zeroes = 0
|
|
32
|
-
while File.exist? fs_path
|
|
33
|
-
zeroes += 1
|
|
34
|
-
fs_path = File.join(cache_dir,
|
|
35
|
-
"#{file_part}#{'0' * zeroes}.#{extension}")
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
write(fs_path) {
|
|
39
|
-
self.quality = 100
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
fs_path
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
require 'curb'
|
|
2
|
-
|
|
3
|
-
module MemeCaptain
|
|
4
|
-
|
|
5
|
-
module ImageList
|
|
6
|
-
|
|
7
|
-
# Mix-in for Magick::ImageList to add loading from a URL.
|
|
8
|
-
module Fetch
|
|
9
|
-
|
|
10
|
-
# Load this image from a URL.
|
|
11
|
-
def fetch!(url)
|
|
12
|
-
curl = Curl::Easy.perform(url) do |c|
|
|
13
|
-
c.useragent = 'Meme Captain http://memecaptain.com/'
|
|
14
|
-
c.follow_location = true
|
|
15
|
-
c.max_redirects = 3
|
|
16
|
-
end
|
|
17
|
-
unless curl.response_code == 200
|
|
18
|
-
raise FetchError.new(curl.response_code)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
from_blob curl.body_str
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
module MemeCaptain
|
|
2
|
-
|
|
3
|
-
module ImageList
|
|
4
|
-
|
|
5
|
-
# Error for source image fetch failures.
|
|
6
|
-
class FetchError < StandardError
|
|
7
|
-
|
|
8
|
-
def initialize(response_code)
|
|
9
|
-
@response_code = response_code
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
attr_accessor :response_code
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
require 'RMagick'
|
|
2
|
-
|
|
3
|
-
module MemeCaptain
|
|
4
|
-
|
|
5
|
-
module ImageList
|
|
6
|
-
|
|
7
|
-
# Source image for meme generation.
|
|
8
|
-
class SourceImage < Magick::ImageList
|
|
9
|
-
include Cache
|
|
10
|
-
include Fetch
|
|
11
|
-
include Watermark
|
|
12
|
-
|
|
13
|
-
# Shrink image if necessary and add watermark.
|
|
14
|
-
def prepare!(max_side, watermark_img)
|
|
15
|
-
auto_orient!
|
|
16
|
-
|
|
17
|
-
if size == 1 and (columns > max_side or rows > max_side)
|
|
18
|
-
resize_to_fit! max_side
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
watermark_mc watermark_img
|
|
22
|
-
|
|
23
|
-
strip!
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
require 'mongo_mapper'
|
|
2
|
-
|
|
3
|
-
module MemeCaptain
|
|
4
|
-
|
|
5
|
-
class MemeData
|
|
6
|
-
include MongoMapper::Document
|
|
7
|
-
|
|
8
|
-
set_collection_name 'meme'
|
|
9
|
-
|
|
10
|
-
key :meme_id, String
|
|
11
|
-
key :fs_path, String
|
|
12
|
-
key :mime_type, String
|
|
13
|
-
key :size, Integer
|
|
14
|
-
|
|
15
|
-
key :source_url, String
|
|
16
|
-
key :source_fs_path, String
|
|
17
|
-
key :texts, Array
|
|
18
|
-
|
|
19
|
-
key :request_count, Integer
|
|
20
|
-
key :last_request, Time
|
|
21
|
-
|
|
22
|
-
key :creator_ip, String
|
|
23
|
-
|
|
24
|
-
timestamps!
|
|
25
|
-
|
|
26
|
-
def requested!
|
|
27
|
-
increment :request_count => 1
|
|
28
|
-
set :last_request => Time.now
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
end
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
module MemeCaptain
|
|
2
|
-
|
|
3
|
-
# Normalize query string parameters.
|
|
4
|
-
#
|
|
5
|
-
# Provide defaults, do some basic validation and convert some parameters
|
|
6
|
-
# to floats or integers.
|
|
7
|
-
class NormParams
|
|
8
|
-
|
|
9
|
-
def initialize(params={})
|
|
10
|
-
@u = ''
|
|
11
|
-
|
|
12
|
-
@t1 = ''
|
|
13
|
-
@t2 = ''
|
|
14
|
-
|
|
15
|
-
@t1x = 0.05
|
|
16
|
-
@t1y = 0
|
|
17
|
-
@t1w = 0.9
|
|
18
|
-
@t1h = 0.25
|
|
19
|
-
|
|
20
|
-
@t2x = 0.05
|
|
21
|
-
@t2y = 0.75
|
|
22
|
-
@t2w = 0.9
|
|
23
|
-
@t2h = 0.25
|
|
24
|
-
|
|
25
|
-
load params
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Load query string parameters.
|
|
29
|
-
#
|
|
30
|
-
# Do some basic validation and convert some parameters to floats or
|
|
31
|
-
# integers.
|
|
32
|
-
def load(params)
|
|
33
|
-
params.select { |k,v|
|
|
34
|
-
[
|
|
35
|
-
:u,
|
|
36
|
-
:t1,
|
|
37
|
-
:t2,
|
|
38
|
-
].include? k.to_sym }.each do |k,v|
|
|
39
|
-
send "#{k}=", v.to_s
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
params.select { |k,v|
|
|
43
|
-
[
|
|
44
|
-
:t1x,
|
|
45
|
-
:t1y,
|
|
46
|
-
:t1w,
|
|
47
|
-
:t1h,
|
|
48
|
-
|
|
49
|
-
:t2x,
|
|
50
|
-
:t2y,
|
|
51
|
-
:t2w,
|
|
52
|
-
:t2h,
|
|
53
|
-
].include?(k.to_sym) and !v.to_s.empty? }.each do |k,v|
|
|
54
|
-
send "#{k}=", convert_metric(v)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Return a sorted string representation of the fields.
|
|
59
|
-
def signature
|
|
60
|
-
instance_variables.sort.map { |v|
|
|
61
|
-
name = v[1..-1] # remove @
|
|
62
|
-
"#{name}#{instance_variable_get(v)}"
|
|
63
|
-
}.join
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
attr_accessor :u
|
|
67
|
-
|
|
68
|
-
attr_accessor :t1
|
|
69
|
-
attr_accessor :t2
|
|
70
|
-
|
|
71
|
-
attr_accessor :t1x
|
|
72
|
-
attr_accessor :t1y
|
|
73
|
-
attr_accessor :t1w
|
|
74
|
-
attr_accessor :t1h
|
|
75
|
-
|
|
76
|
-
attr_accessor :t2x
|
|
77
|
-
attr_accessor :t2y
|
|
78
|
-
attr_accessor :t2w
|
|
79
|
-
attr_accessor :t2h
|
|
80
|
-
|
|
81
|
-
private
|
|
82
|
-
|
|
83
|
-
# Convert a metric string to a float or integer.
|
|
84
|
-
#
|
|
85
|
-
# Expects a string.
|
|
86
|
-
def convert_metric(metric)
|
|
87
|
-
metric.index('.') ? metric.to_f : metric.to_i
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
end
|
data/lib/meme_captain/server.rb
DELETED
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
require 'digest/sha1'
|
|
2
|
-
|
|
3
|
-
require 'json'
|
|
4
|
-
require 'rack'
|
|
5
|
-
require 'sinatra/base'
|
|
6
|
-
|
|
7
|
-
module MemeCaptain
|
|
8
|
-
|
|
9
|
-
class Server < Sinatra::Base
|
|
10
|
-
|
|
11
|
-
set :root, File.expand_path(File.join('..', '..'), File.dirname(__FILE__))
|
|
12
|
-
set :source_img_max_side, 800
|
|
13
|
-
set :upload_prefix, 'up/'
|
|
14
|
-
set :watermark, Magick::ImageList.new(File.expand_path(
|
|
15
|
-
File.join('..', '..', 'watermark.png'), File.dirname(__FILE__)))
|
|
16
|
-
|
|
17
|
-
# uncomment this to allow other sites to use this site's backend for
|
|
18
|
-
# generating images, used to allow third-party static only sites
|
|
19
|
-
# to generate images using memecaptain.com
|
|
20
|
-
|
|
21
|
-
# set :protection, :except => :json_csrf
|
|
22
|
-
|
|
23
|
-
get '/' do
|
|
24
|
-
@u = params[:u]
|
|
25
|
-
|
|
26
|
-
@t1 = params[:t1]
|
|
27
|
-
@t1x = params[:t1x]
|
|
28
|
-
@t1y = params[:t1y]
|
|
29
|
-
@t1w = params[:t1w]
|
|
30
|
-
@t1h = params[:t1h]
|
|
31
|
-
|
|
32
|
-
@t2 = params[:t2]
|
|
33
|
-
@t2x = params[:t2x]
|
|
34
|
-
@t2y = params[:t2y]
|
|
35
|
-
@t2w = params[:t2w]
|
|
36
|
-
@t2h = params[:t2h]
|
|
37
|
-
|
|
38
|
-
@root_url = url('/')
|
|
39
|
-
|
|
40
|
-
erb :index
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def normalize_params(p)
|
|
44
|
-
result = NormParams.new(p)
|
|
45
|
-
|
|
46
|
-
# if the id of an existing meme is passed in as the source url, use the
|
|
47
|
-
# source image of that meme for the source image
|
|
48
|
-
if result.u[%r{^[a-f0-9]+\.(?:gif|jpg|png)$}]
|
|
49
|
-
if existing_as_source = MemeData.find_by_meme_id(result.u)
|
|
50
|
-
result.u = existing_as_source.source_url
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
result
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def gen(p)
|
|
58
|
-
logger.debug "params:\n#{MemeCaptain.pretty_format(p)}"
|
|
59
|
-
norm_params = normalize_params(p)
|
|
60
|
-
logger.debug 'normalized params:'
|
|
61
|
-
logger.debug(MemeCaptain.pretty_format(norm_params))
|
|
62
|
-
|
|
63
|
-
if existing = MemeData.first(
|
|
64
|
-
:source_url => norm_params.u,
|
|
65
|
-
|
|
66
|
-
'texts.0.text' => norm_params.t1,
|
|
67
|
-
'texts.0.x' => norm_params.t1x,
|
|
68
|
-
'texts.0.y' => norm_params.t1y,
|
|
69
|
-
'texts.0.w' => norm_params.t1w,
|
|
70
|
-
'texts.0.h' => norm_params.t1h,
|
|
71
|
-
|
|
72
|
-
'texts.1.text' => norm_params.t2,
|
|
73
|
-
'texts.1.x' => norm_params.t2x,
|
|
74
|
-
'texts.1.y' => norm_params.t2y,
|
|
75
|
-
'texts.1.w' => norm_params.t2w,
|
|
76
|
-
'texts.1.h' => norm_params.t2h
|
|
77
|
-
)
|
|
78
|
-
logger.debug 'found existing meme:'
|
|
79
|
-
logger.debug(MemeCaptain.pretty_format(existing))
|
|
80
|
-
existing
|
|
81
|
-
else
|
|
82
|
-
if same_source = MemeData.find_by_source_url(norm_params.u)
|
|
83
|
-
logger.debug 'found existing source image'
|
|
84
|
-
source_fs_path = same_source.source_fs_path
|
|
85
|
-
elsif (norm_params.u.index(settings.upload_prefix) == 0) and
|
|
86
|
-
(upload = Upload.find_by_upload_id(
|
|
87
|
-
norm_params.u[settings.upload_prefix.size..-1]))
|
|
88
|
-
|
|
89
|
-
logger.debug 'source image is upload:'
|
|
90
|
-
logger.debug MemeCaptain.pretty_format(upload)
|
|
91
|
-
source_fs_path = upload.fs_path
|
|
92
|
-
else
|
|
93
|
-
if source_fetch_fail = SourceFetchFail.find_by_url(norm_params.u)
|
|
94
|
-
logger.debug 'skipping fetch of previously failed source image:'
|
|
95
|
-
logger.debug(MemeCaptain.pretty_format(source_fetch_fail))
|
|
96
|
-
source_fetch_fail.requested!
|
|
97
|
-
halt 500, 'Error loading source image url'
|
|
98
|
-
else
|
|
99
|
-
source_img = ImageList::SourceImage.new
|
|
100
|
-
begin
|
|
101
|
-
logger.debug "fetch source image: #{norm_params.u}"
|
|
102
|
-
source_img.fetch! norm_params.u
|
|
103
|
-
rescue => error
|
|
104
|
-
new_source_fetch_fail = SourceFetchFail.new(
|
|
105
|
-
:attempt_count => 1,
|
|
106
|
-
:orig_ip => request.ip,
|
|
107
|
-
:response_code => error.respond_to?(:response_code) ?
|
|
108
|
-
error.response_code : nil,
|
|
109
|
-
:url => norm_params.u
|
|
110
|
-
)
|
|
111
|
-
logger.debug 'source image fetch failed:'
|
|
112
|
-
logger.debug(MemeCaptain.pretty_format(new_source_fetch_fail))
|
|
113
|
-
new_source_fetch_fail.save!
|
|
114
|
-
halt 500, 'Error loading source image url'
|
|
115
|
-
end
|
|
116
|
-
source_img.prepare! settings.source_img_max_side, settings.watermark
|
|
117
|
-
source_fs_path = source_img.cache(norm_params.u, 'source_cache')
|
|
118
|
-
source_img.each { |frame| frame.destroy! }
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
logger.debug "source image filesystem path: #{source_fs_path}"
|
|
123
|
-
|
|
124
|
-
open(source_fs_path, 'rb') do |source_io|
|
|
125
|
-
t1 = TextPos.new(norm_params.t1, norm_params.t1x, norm_params.t1y,
|
|
126
|
-
norm_params.t1w, norm_params.t1h)
|
|
127
|
-
|
|
128
|
-
t2 = TextPos.new(norm_params.t2, norm_params.t2x, norm_params.t2y,
|
|
129
|
-
norm_params.t2w, norm_params.t2h)
|
|
130
|
-
|
|
131
|
-
meme_img = MemeCaptain.meme(source_io, [t1, t2])
|
|
132
|
-
meme_img.extend ImageList::Cache
|
|
133
|
-
|
|
134
|
-
# convert source images in formats other than jpeg, gif or png
|
|
135
|
-
# to png
|
|
136
|
-
unless %w{JPEG GIF PNG}.include?(meme_img.format)
|
|
137
|
-
meme_img.format = 'PNG'
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
# convert non-animated gifs to png
|
|
141
|
-
if meme_img.format == 'GIF' and meme_img.size == 1
|
|
142
|
-
meme_img.format = 'PNG'
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
sig = norm_params.signature
|
|
146
|
-
meme_hash = Digest::SHA1.hexdigest(sig)
|
|
147
|
-
|
|
148
|
-
meme_id = nil
|
|
149
|
-
(6..meme_hash.size).each do |len|
|
|
150
|
-
meme_id = "#{meme_hash[0,len]}.#{meme_img.extension}"
|
|
151
|
-
break unless MemeData.where(:meme_id => meme_id).count > 0
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
meme_fs_path = meme_img.cache(sig, File.join('public', 'meme'))
|
|
155
|
-
|
|
156
|
-
logger.debug "meme filesystem path: #{meme_fs_path}"
|
|
157
|
-
|
|
158
|
-
meme_img.write(meme_fs_path) {
|
|
159
|
-
self.quality = 100
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
meme_data = MemeData.new(
|
|
163
|
-
:meme_id => meme_id,
|
|
164
|
-
:fs_path => meme_fs_path,
|
|
165
|
-
:mime_type => meme_img.mime_type,
|
|
166
|
-
:size => File.size(meme_fs_path),
|
|
167
|
-
|
|
168
|
-
:source_url => norm_params.u,
|
|
169
|
-
:source_fs_path => source_fs_path,
|
|
170
|
-
|
|
171
|
-
:texts => [{
|
|
172
|
-
:text => norm_params.t1,
|
|
173
|
-
:x => norm_params.t1x,
|
|
174
|
-
:y => norm_params.t1y,
|
|
175
|
-
:w => norm_params.t1w,
|
|
176
|
-
:h => norm_params.t1h,
|
|
177
|
-
}, {
|
|
178
|
-
:text => norm_params.t2,
|
|
179
|
-
:x => norm_params.t2x,
|
|
180
|
-
:y => norm_params.t2y,
|
|
181
|
-
:w => norm_params.t2w,
|
|
182
|
-
:h => norm_params.t2h,
|
|
183
|
-
}],
|
|
184
|
-
|
|
185
|
-
:request_count => 0,
|
|
186
|
-
|
|
187
|
-
:creator_ip => request.ip
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
meme_img.each { |frame| frame.destroy! }
|
|
191
|
-
|
|
192
|
-
logger.debug "meme data:\n#{MemeCaptain.pretty_format(meme_data)}"
|
|
193
|
-
|
|
194
|
-
meme_data.save! :safe => true
|
|
195
|
-
|
|
196
|
-
meme_data
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
get '/g' do
|
|
203
|
-
begin
|
|
204
|
-
meme_data = gen(params)
|
|
205
|
-
|
|
206
|
-
[200, { 'Content-Type' => 'application/json' }, {
|
|
207
|
-
'imageUrl' => url("/#{meme_data.meme_id}"),
|
|
208
|
-
'templateUrl' => url("/?u=#{Rack::Utils.escape(meme_data.meme_id)}"),
|
|
209
|
-
}.to_json]
|
|
210
|
-
rescue => error
|
|
211
|
-
logger.error "error generating image: #{error.class} #{error.message}"
|
|
212
|
-
logger.error(MemeCaptain.pretty_format(error.backtrace))
|
|
213
|
-
[500, { 'Content-Type' => 'text/plain' }, 'Error generating image']
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def serve_img(meme_data)
|
|
218
|
-
meme_data.requested!
|
|
219
|
-
|
|
220
|
-
if meme_data.respond_to?(:texts)
|
|
221
|
-
meme_text = meme_data.texts.map do |text|
|
|
222
|
-
Rack::Utils.escape(text['text'])
|
|
223
|
-
end.join('&')
|
|
224
|
-
|
|
225
|
-
headers 'Meme-Text' => meme_text
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
send_file meme_data.fs_path, :type => meme_data.mime_type
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
get '/i' do
|
|
232
|
-
raise Sinatra::NotFound if params[:u].to_s.empty?
|
|
233
|
-
|
|
234
|
-
serve_img(gen(params))
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
get %r{^/([a-f0-9]+\.(?:gif|jpg|png))$} do
|
|
238
|
-
if meme_data = MemeData.find_by_meme_id(params[:captures][0])
|
|
239
|
-
serve_img meme_data
|
|
240
|
-
else
|
|
241
|
-
raise Sinatra::NotFound
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
post '/upload' do
|
|
246
|
-
redirect('/') unless params[:upload]
|
|
247
|
-
|
|
248
|
-
img = ImageList::SourceImage.new
|
|
249
|
-
img.from_blob(params[:upload][:tempfile].read)
|
|
250
|
-
img.prepare! settings.source_img_max_side, settings.watermark
|
|
251
|
-
fs_path = img.cache(params[:upload][:filename], 'source_cache')
|
|
252
|
-
|
|
253
|
-
filename_hash = Digest::SHA1.hexdigest(params[:upload][:filename])
|
|
254
|
-
|
|
255
|
-
len = 6
|
|
256
|
-
upload_id = filename_hash[0,len]
|
|
257
|
-
while Upload.where(:upload_id => upload_id).count > 0
|
|
258
|
-
upload_id = if len < filename_hash.size
|
|
259
|
-
len += 1
|
|
260
|
-
filename_hash[0,len]
|
|
261
|
-
else
|
|
262
|
-
"#{upload_id}0"
|
|
263
|
-
end
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
upload = Upload.new(
|
|
267
|
-
:upload_id => upload_id,
|
|
268
|
-
:fs_path => fs_path,
|
|
269
|
-
:mime_type => img.mime_type,
|
|
270
|
-
:size => File.size(fs_path),
|
|
271
|
-
:request_count => 0,
|
|
272
|
-
:creator_ip => request.ip
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
img.each { |frame| frame.destroy! }
|
|
276
|
-
|
|
277
|
-
upload.save! :safe => true
|
|
278
|
-
|
|
279
|
-
redirect "/?u=#{settings.upload_prefix}#{Rack::Utils.escape(upload_id)}"
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
get %r{/#{settings.upload_prefix}(.+)} do
|
|
283
|
-
if upload = Upload.find_by_upload_id(params[:captures][0])
|
|
284
|
-
serve_img upload
|
|
285
|
-
else
|
|
286
|
-
raise Sinatra::NotFound
|
|
287
|
-
end
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
not_found do
|
|
291
|
-
@root_url = url('/')
|
|
292
|
-
|
|
293
|
-
erb :'404'
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
helpers do
|
|
297
|
-
include Rack::Utils
|
|
298
|
-
alias_method :h, :escape_html
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
end
|