simplificator-rwebthumb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +29 -0
- data/init.rb +2 -0
- data/lib/rwebthumb.rb +4 -0
- data/lib/rwebthumb/base.rb +82 -0
- data/lib/rwebthumb/job.rb +99 -0
- data/lib/rwebthumb/webthumb.rb +69 -0
- data/test/base_test.rb +23 -0
- data/test/helper.rb +4 -0
- data/test/job_test.rb +35 -0
- data/test/webthumb_test.rb +15 -0
- metadata +63 -0
data/README
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
== rwebthumb
|
2
|
+
|
3
|
+
= what is it
|
4
|
+
A Ruby wrapper for the webthumb API from http://webthumb.bluga.net
|
5
|
+
|
6
|
+
= dependencies
|
7
|
+
- tzinfo:http://tzinfo.rubyforge.org (install: sudo gem install tzinfo)
|
8
|
+
|
9
|
+
= Usage
|
10
|
+
# Creating a Webthumb Object. This is used as your main access point
|
11
|
+
wt = Webthumb.new('YOUR API KEY')
|
12
|
+
|
13
|
+
# Create a new thumbnail job
|
14
|
+
job = wt.thumbnail(:url => 'http://simplificator.com')
|
15
|
+
|
16
|
+
# fetch the thumbnail. this might throw an exception from server side
|
17
|
+
# if thumb is not ready yet
|
18
|
+
job.fetch(:large)
|
19
|
+
|
20
|
+
# you can check the status of a job
|
21
|
+
job.check_status()
|
22
|
+
|
23
|
+
# or fetch the thumbnail when it is complete
|
24
|
+
job.fetch_when_complete(:large)
|
25
|
+
|
26
|
+
# once thumbnails are fetched they are cached within the job. so a new fetch will not go to the server again
|
27
|
+
|
28
|
+
# there is a helper method to write the images to disk
|
29
|
+
job.write_file(, '/tmp/test.jpg')
|
data/init.rb
ADDED
data/lib/rwebthumb.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module Simplificator
|
2
|
+
module Webthumb
|
3
|
+
#
|
4
|
+
#
|
5
|
+
#
|
6
|
+
#
|
7
|
+
class Base
|
8
|
+
# Valid output_types for thumbnail requests
|
9
|
+
VALID_OUTPUT_TYPES = [:jpg, :png]
|
10
|
+
# Valid values for size element in fetch requests
|
11
|
+
VALID_SIZES = [:small, :medium, :medium2, :large, :full, :excerpt, :effect, :custom, :zip]
|
12
|
+
|
13
|
+
# Timezone to convert from MST (Webthumb) to UTC
|
14
|
+
MST_TIMEZONE = TZInfo::Timezone.get('MST')
|
15
|
+
|
16
|
+
attr_reader :api_key
|
17
|
+
# Constructor
|
18
|
+
# api_key: the Webthumb api key, not nil and not blank
|
19
|
+
#
|
20
|
+
def initialize(api_key, api_endpoint = 'http://webthumb.bluga.net/api.php')
|
21
|
+
raise WebthumbException.new('Need an noot nil and not blank api_key') if api_key == nil || api_key == ''
|
22
|
+
@api_key = api_key
|
23
|
+
@api_endpoint = api_endpoint
|
24
|
+
@api_uri = URI.parse(@api_endpoint)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Parse the datetime string and returns a DateTime object in UTC time
|
28
|
+
# Webthumb returns the time in MST (Mountain Standard Time) which is some 7 hours
|
29
|
+
# behind UTC
|
30
|
+
def self.parse_webthumb_datetime(s)
|
31
|
+
MST_TIMEZONE.local_to_utc(DateTime.strptime(s, '%Y-%m-%d %H:%M:%S'))
|
32
|
+
end
|
33
|
+
|
34
|
+
def do_request(xml)
|
35
|
+
request = Net::HTTP::Post.new(@api_uri.path)
|
36
|
+
request.body = xml.to_s
|
37
|
+
response = Net::HTTP.new(@api_uri.host, @api_uri.port).start {|p| p.request(request) }
|
38
|
+
case response
|
39
|
+
when Net::HTTPOK :
|
40
|
+
case response.content_type
|
41
|
+
when 'text/xml' : REXML::Document.new(response.body)
|
42
|
+
when 'image/jpg'
|
43
|
+
when 'image/jpeg'
|
44
|
+
when 'image/png'
|
45
|
+
response.body
|
46
|
+
else
|
47
|
+
raise WebthumbException.new("usupported content type #{response.content_type}. Body was: \n#{response.body}")
|
48
|
+
end
|
49
|
+
else
|
50
|
+
raise CommunicationException('Response code was not HTTP OK')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# builds the root node for webthumb requtes
|
55
|
+
def build_root_node()
|
56
|
+
root = REXML::Element.new('webthumb')
|
57
|
+
api = root.add_element('apikey')
|
58
|
+
api.text = @api_key
|
59
|
+
root
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
#
|
64
|
+
# add a XML element if value is present.
|
65
|
+
# can be used to create XML for webthumb requests from ruby options hash.
|
66
|
+
#
|
67
|
+
# root: the root XML element where element is added to
|
68
|
+
# options: the hash where value is taken from
|
69
|
+
# key: the key to lookup the value in options
|
70
|
+
# name: the name of the XML element. defaults to key
|
71
|
+
#
|
72
|
+
def add_element(root, options, key, name = key.to_s)
|
73
|
+
root.add_element(name).add_text(options[key].to_s) if options.has_key?(key)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
class WebthumbException < RuntimeError
|
78
|
+
end
|
79
|
+
class CommunicationException < RuntimeError
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Simplificator
|
2
|
+
module Webthumb
|
3
|
+
class Job < Base
|
4
|
+
|
5
|
+
attr_reader :duration_estimate, :submission_datetime, :cost, :job_id, :url
|
6
|
+
|
7
|
+
# Constant for the status attribute when job is beeing processed
|
8
|
+
STATUS_PROCESSING = 100
|
9
|
+
# Constant for the status attribute when job is done
|
10
|
+
STATUS_PICKUP = 200
|
11
|
+
|
12
|
+
# Factory method to build a Job object from a REXML xml element
|
13
|
+
def self.from_thumbnail_xml(api_key, xml)
|
14
|
+
job_element = REXML::XPath.first(xml, '/webthumb/jobs/job')
|
15
|
+
submission_datetime = self.parse_webthumb_datetime(job_element.attributes['time'])
|
16
|
+
Job.new(api_key, job_element.text, job_element.attributes['url'], submission_datetime, job_element.attributes['estimate'].to_i, job_element.attributes['cost'].to_i)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.from_status_xml(api_key, xml)
|
20
|
+
status_element = REXML::XPath.first(xml, '/webthumb/jobStatus/status')
|
21
|
+
submission_datetime = self.parse_webthumb_datetime(status_element.attributes['submissionTime'])
|
22
|
+
job = Job.new(api_key, status_element.attributes['id'], nil, submission_datetime, 5, nil,
|
23
|
+
status_element.text == 'Complete' ? STATUS_PICKUP : STATUS_PROCESSING)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(api_key, job_id, url, submission_datetime, duration_estimate, cost, status = STATUS_PROCESSING)
|
27
|
+
super(api_key)
|
28
|
+
@job_id = job_id
|
29
|
+
@url = url
|
30
|
+
@submission_datetime = submission_datetime
|
31
|
+
@duration_estimate = duration_estimate
|
32
|
+
@cost = cost
|
33
|
+
@status = status
|
34
|
+
@cache = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def request_status
|
38
|
+
response = do_request(build_status_xml())
|
39
|
+
@status = REXML::XPath.first(response, '/webthumb/jobStatus/status').text == 'Complete' ? STATUS_PICKUP : STATUS_PROCESSING
|
40
|
+
if pickup?
|
41
|
+
@completion_time = response.attributes['completionTime']
|
42
|
+
@duration = 'not yet... need to convert times first'
|
43
|
+
end
|
44
|
+
@status
|
45
|
+
end
|
46
|
+
|
47
|
+
def fetch_when_complete(size = :small)
|
48
|
+
while not pickup?
|
49
|
+
puts "waiting for #{@duration_estimate}"
|
50
|
+
sleep @duration_estimate
|
51
|
+
request_status
|
52
|
+
end
|
53
|
+
fetch(size)
|
54
|
+
end
|
55
|
+
|
56
|
+
def fetch(size = :small)
|
57
|
+
unless @cache.has_key?(size)
|
58
|
+
response = do_request(build_fetch_xml(size))
|
59
|
+
@cache[size] = response
|
60
|
+
end
|
61
|
+
@cache[size]
|
62
|
+
end
|
63
|
+
|
64
|
+
def write_file(data, name)
|
65
|
+
File.open(name, 'wb+') do |file|
|
66
|
+
file.write(data)
|
67
|
+
file.close
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def pickup?
|
72
|
+
@status == STATUS_PICKUP
|
73
|
+
end
|
74
|
+
def processing?
|
75
|
+
@status == STATUS_PROCESSING
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def build_fetch_xml(size = :small)
|
80
|
+
raise WebthumbException.new("size parameter must be one of #{VALID_SIZES.join(', ')} but was #{size}") unless Base::VALID_SIZES.include?(size)
|
81
|
+
root = build_root_node()
|
82
|
+
fetch = root.add_element('fetch')
|
83
|
+
fetch.add_element('job').add_text(@job_id)
|
84
|
+
fetch.add_element('size').add_text(size.to_s)
|
85
|
+
root
|
86
|
+
end
|
87
|
+
def build_status_xml()
|
88
|
+
root = build_root_node()
|
89
|
+
status = root.add_element('status')
|
90
|
+
status.add_element('job').add_text(@job_id)
|
91
|
+
root
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_s
|
95
|
+
"Job: #{@job_id} / Status: #{@status} / Submission Time #{@submission_time} / Duration Estimate #{@duration_estimate}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'rexml/document'
|
3
|
+
require 'date'
|
4
|
+
module Simplificator
|
5
|
+
module Webthumb
|
6
|
+
|
7
|
+
|
8
|
+
class Webthumb < Base
|
9
|
+
def thumbnail(options = {})
|
10
|
+
Job.from_thumbnail_xml(@api_key, do_request(build_thumbnail_xml(options)))
|
11
|
+
end
|
12
|
+
|
13
|
+
def job_status(job_id)
|
14
|
+
Job.from_status_xml(@api_key, do_request(build_job_status_xml(job_id)))
|
15
|
+
end
|
16
|
+
|
17
|
+
def credits()
|
18
|
+
root = build_root_node()
|
19
|
+
root.add_element('credits')
|
20
|
+
elements = do_request(root).elements['webthumb'].elements['credits'].elements
|
21
|
+
{:reserve => elements['reserve'].text.to_i, :subscription => elements['subscription'].text.to_i}
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def build_thumbnail_xml(options)
|
26
|
+
validate_thumbnail_options(options)
|
27
|
+
|
28
|
+
|
29
|
+
root = build_root_node()
|
30
|
+
request = root.add_element('request')
|
31
|
+
request.add_element('url').add_text(options[:url])
|
32
|
+
add_element(request, options, :output_type, 'outputType')
|
33
|
+
[:width, :height, :effect, :delay, :notofy].each {|item| add_element(request, options, item)}
|
34
|
+
|
35
|
+
if options[:fullthumb] == true
|
36
|
+
request.add_element('fullthumb').add_text('1')
|
37
|
+
end
|
38
|
+
if options.has_key?(:custom_thumbnail)
|
39
|
+
request.add_element('customThumbnail',
|
40
|
+
'width' => options[:custom_thumbnail][:width].to_s,
|
41
|
+
'height' => options[:custom_thumbnail][:height].to_s)
|
42
|
+
|
43
|
+
end
|
44
|
+
if options.has_key?(:excerpt)
|
45
|
+
excerpt = request.add_element('excerpt')
|
46
|
+
[:x, :y, :width, :height].each {|item| add_element(excerpt, options[:excerpt], item)}
|
47
|
+
end
|
48
|
+
root
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_job_status_xml(job_id)
|
52
|
+
root = build_root_node()
|
53
|
+
root.add_element('status').add_element('job').add_text(job_id)
|
54
|
+
root
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_thumbnail_options(options)
|
58
|
+
raise WebthumbException.new('Need an URL') if options[:url] == nil || options[:url] == ''
|
59
|
+
raise WebthumbException.new("output_type is invalid: #{options[:output_type]}") if options.has_key?(:output_type) and (not Base::VALID_OUTPUT_TYPES.include?(options[:output_type]))
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
data/test/base_test.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'helper'
|
2
|
+
class BaseTest < Test::Unit::TestCase
|
3
|
+
def test_api_key_required
|
4
|
+
assert_raises(WebthumbException) { Base.new('') }
|
5
|
+
assert_raises(WebthumbException) { Base.new(nil) }
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_parse_webthumb_date
|
9
|
+
[['2000-1-1 14:00:00', '2000-1-1 07:00:00'], ['2000-1-1 07:00:00', '2000-1-1 00:00:00'], ['2000-8-1 07:44:2', '2000-8-1 00:44:02']].each do |item|
|
10
|
+
utc = DateTime.strptime(item[0], '%Y-%m-%d %H:%M:%S')
|
11
|
+
mst = Base.parse_webthumb_datetime(item[1])
|
12
|
+
assert_equal(utc, mst)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_build_root_node()
|
17
|
+
root = Base.new('1234').build_root_node()
|
18
|
+
assert_not_nil(root)
|
19
|
+
assert_not_nil(REXML::XPath.first(root, '/'))
|
20
|
+
assert_not_nil(REXML::XPath.first(root, '/apikey'))
|
21
|
+
assert_equal('1234', REXML::XPath.first(root, '/apikey').text)
|
22
|
+
end
|
23
|
+
end
|
data/test/helper.rb
ADDED
data/test/job_test.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'helper'
|
2
|
+
class JobTest < Test::Unit::TestCase
|
3
|
+
def setup()
|
4
|
+
xml = <<-EOF
|
5
|
+
<webthumb>
|
6
|
+
<jobs>
|
7
|
+
<job estimate='20' time='2008-02-27 12:49:48' url='http://blog.joshuaeichorn.com' cost='1'>wt47c5f71c37c3a</job>
|
8
|
+
</jobs>
|
9
|
+
</webthumb>
|
10
|
+
EOF
|
11
|
+
job_xml = REXML::Document.new(xml)
|
12
|
+
@job = Job.from_thumbnail_xml('1234', job_xml)
|
13
|
+
end
|
14
|
+
def test_from_thumbnail_xml
|
15
|
+
|
16
|
+
assert_equal('1234', @job.api_key)
|
17
|
+
assert_equal(20, @job.duration_estimate)
|
18
|
+
assert_equal(DateTime.strptime('2008-02-27 19:49:48', '%Y-%m-%d %H:%M:%S'), @job.submission_datetime)
|
19
|
+
assert_equal('http://blog.joshuaeichorn.com', @job.url)
|
20
|
+
assert_equal(1, @job.cost)
|
21
|
+
assert_equal('wt47c5f71c37c3a', @job.job_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def test_build_fetch()
|
26
|
+
xml = @job.send(:build_fetch_xml)
|
27
|
+
assert_equal('small', REXML::XPath.first(xml, 'fetch/size').text)
|
28
|
+
assert_equal('wt47c5f71c37c3a', REXML::XPath.first(xml, 'fetch/job').text)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_build_status_xml()
|
32
|
+
xml = @job.send(:build_status_xml)
|
33
|
+
assert_equal('wt47c5f71c37c3a', REXML::XPath.first(xml, 'status/job').text)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'helper'
|
2
|
+
class WebthumbTest < Test::Unit::TestCase
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
def test_build_fetch()
|
7
|
+
xml = Webthumb.new('1234').send(:build_thumbnail_xml, :url => 'http://simplificator.com')
|
8
|
+
assert_equal('http://simplificator.com', REXML::XPath.first(xml, 'request/url').text)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_build_job_status_xml()
|
12
|
+
xml = Webthumb.new('1234').send(:build_job_status_xml, 'abcd')
|
13
|
+
assert_equal('abcd', REXML::XPath.first(xml, 'status/job').text)
|
14
|
+
end
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simplificator-rwebthumb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Simplificator GmbH
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-07-10 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: rwebthumb provides a ruby interface for the webthumb.bluga.net
|
17
|
+
email: gems@simplificator.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/rwebthumb.rb
|
26
|
+
- lib/rwebthumb/base.rb
|
27
|
+
- lib/rwebthumb/job.rb
|
28
|
+
- lib/rwebthumb/webthumb.rb
|
29
|
+
- test/base_test.rb
|
30
|
+
- test/helper.rb
|
31
|
+
- test/job_test.rb
|
32
|
+
- test/run_test.rb
|
33
|
+
- test/webthumb_test.rb
|
34
|
+
- README
|
35
|
+
- init.rb
|
36
|
+
has_rdoc: false
|
37
|
+
homepage: http://labs.simplificator.com/
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "0"
|
48
|
+
version:
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
requirements: []
|
56
|
+
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 1.2.0
|
59
|
+
signing_key:
|
60
|
+
specification_version: 2
|
61
|
+
summary: rwebthumb provides a ruby interface for the webthumb.bluga.net
|
62
|
+
test_files: []
|
63
|
+
|