simplificator-rwebthumb 0.0.1
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/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
|
+
|