botr 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.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.gitignore +31 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +4 -0
- data/LICENSE.txt +20 -0
- data/README.md +278 -0
- data/Rakefile +43 -0
- data/botr.gemspec +24 -0
- data/botr.watchr +3 -0
- data/certs/cacert.pem +3554 -0
- data/lib/botr.rb +34 -0
- data/lib/botr/api/api.rb +83 -0
- data/lib/botr/api/authentication.rb +24 -0
- data/lib/botr/channels/channel.rb +137 -0
- data/lib/botr/channels/channel_thumbnail.rb +88 -0
- data/lib/botr/channels/channel_video.rb +130 -0
- data/lib/botr/channels/channel_view.rb +88 -0
- data/lib/botr/common/logger.rb +31 -0
- data/lib/botr/configuration.rb +18 -0
- data/lib/botr/http/http.rb +88 -0
- data/lib/botr/http/http_backend.rb +66 -0
- data/lib/botr/http/http_response.rb +48 -0
- data/lib/botr/http/multipart.rb +84 -0
- data/lib/botr/http/uri_ext.rb +28 -0
- data/lib/botr/object.rb +20 -0
- data/lib/botr/players/player.rb +149 -0
- data/lib/botr/players/player_view.rb +88 -0
- data/lib/botr/version.rb +3 -0
- data/lib/botr/videos/video.rb +187 -0
- data/lib/botr/videos/video_caption.rb +154 -0
- data/lib/botr/videos/video_conversion.rb +114 -0
- data/lib/botr/videos/video_engagement.rb +51 -0
- data/lib/botr/videos/video_tag.rb +52 -0
- data/lib/botr/videos/video_thumbnail.rb +87 -0
- data/lib/botr/videos/video_view.rb +89 -0
- data/spec/authentication_spec.rb +31 -0
- data/spec/botr_spec.rb +8 -0
- data/spec/http_backend_spec.rb +93 -0
- data/spec/http_response_spec.rb +48 -0
- data/spec/multipart_spec.rb +35 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/test.txt +1 -0
- metadata +150 -0
data/lib/botr.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'botr/version'
|
2
|
+
require 'botr/configuration'
|
3
|
+
|
4
|
+
require 'botr/common/logger'
|
5
|
+
|
6
|
+
require 'botr/http/multipart'
|
7
|
+
require 'botr/http/http_response'
|
8
|
+
require 'botr/http/http_backend'
|
9
|
+
require 'botr/http/http'
|
10
|
+
require 'botr/http/uri_ext'
|
11
|
+
|
12
|
+
require 'botr/api/api'
|
13
|
+
require 'botr/api/authentication'
|
14
|
+
|
15
|
+
require 'botr/object'
|
16
|
+
|
17
|
+
require 'botr/videos/video'
|
18
|
+
require 'botr/videos/video_conversion'
|
19
|
+
require 'botr/videos/video_thumbnail'
|
20
|
+
require 'botr/videos/video_caption'
|
21
|
+
require 'botr/videos/video_tag'
|
22
|
+
require 'botr/videos/video_view'
|
23
|
+
require 'botr/videos/video_engagement'
|
24
|
+
|
25
|
+
require 'botr/channels/channel'
|
26
|
+
require 'botr/channels/channel_thumbnail'
|
27
|
+
require 'botr/channels/channel_video'
|
28
|
+
require 'botr/channels/channel_view'
|
29
|
+
|
30
|
+
require 'botr/players/player'
|
31
|
+
require 'botr/players/player_view'
|
32
|
+
|
33
|
+
|
34
|
+
ENV['SSL_CERT_FILE'] = File.expand_path('../..', __FILE__) + "/certs/cacert.pem"
|
data/lib/botr/api/api.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module BOTR
|
2
|
+
|
3
|
+
module API
|
4
|
+
|
5
|
+
def api_protocol
|
6
|
+
BOTR.configuration.protocol || "https"
|
7
|
+
end
|
8
|
+
|
9
|
+
def api_server
|
10
|
+
BOTR.configuration.server || "api.bitsontherun.com"
|
11
|
+
end
|
12
|
+
|
13
|
+
def api_version
|
14
|
+
"v1"
|
15
|
+
end
|
16
|
+
|
17
|
+
def api_format
|
18
|
+
"json"
|
19
|
+
end
|
20
|
+
|
21
|
+
def api_key
|
22
|
+
BOTR.configuration.api_key || BOTR::API_KEY
|
23
|
+
end
|
24
|
+
|
25
|
+
def api_timestamp
|
26
|
+
Time.now.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return an 8-digit random number.
|
30
|
+
def api_nonce
|
31
|
+
8.times.map { [*'0'..'9'].sample }.join
|
32
|
+
end
|
33
|
+
|
34
|
+
def api_secret_key
|
35
|
+
BOTR.configuration.secret_key || BOTR::SECRET_KEY
|
36
|
+
end
|
37
|
+
|
38
|
+
def api_call_class
|
39
|
+
if defined? call_class
|
40
|
+
call_class
|
41
|
+
elsif defined? self.class.call_class
|
42
|
+
self.class.call_class
|
43
|
+
elsif (defined? self.name) && (self.class.name == "Class") # We are in a class.
|
44
|
+
klass, subclass = self.name.scan(/([[:upper:]][[:lower:]]+)/).flatten
|
45
|
+
subclass ? "#{klass}s/#{subclass}s".downcase : "#{klass}s".downcase
|
46
|
+
else # We are in an instance.
|
47
|
+
klass, subclass = self.class.name.scan(/([[:upper:]][[:lower:]]+)/).flatten
|
48
|
+
subclass ? "#{klass}s/#{subclass}s".downcase : "#{klass}s".downcase
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def upload_protocol
|
53
|
+
@link["protocol"] || "http"
|
54
|
+
end
|
55
|
+
|
56
|
+
def upload_address
|
57
|
+
@link["address"] || "upload.bitsontherun.com"
|
58
|
+
end
|
59
|
+
|
60
|
+
def upload_key
|
61
|
+
@link["query"]["key"] || upload_key
|
62
|
+
end
|
63
|
+
|
64
|
+
def upload_token
|
65
|
+
@link["query"]["token"] || upload_token
|
66
|
+
end
|
67
|
+
|
68
|
+
def api_url(api_method = "")
|
69
|
+
"#{api_protocol}://#{api_server}/#{api_version}/#{api_call_class}/#{api_method}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def upload_url
|
73
|
+
"#{upload_protocol}://#{upload_address}/#{api_version}/#{api_call_class}/upload"
|
74
|
+
# "http://httpbin.org/post"
|
75
|
+
end
|
76
|
+
|
77
|
+
def progress_url(callback)
|
78
|
+
"#{upload_protocol}://#{upload_address}/progress?token=#{upload_token}&callback=#{callback}"
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
module BOTR
|
4
|
+
|
5
|
+
module Authentication
|
6
|
+
|
7
|
+
def signature(params = {})
|
8
|
+
sorted_params = {}
|
9
|
+
str_params = ""
|
10
|
+
|
11
|
+
# Sort params by key (hashes maintain insertion order)
|
12
|
+
params.keys.sort.each do |key|
|
13
|
+
sorted_params[key] = params[key]
|
14
|
+
end
|
15
|
+
|
16
|
+
# URL encode params
|
17
|
+
str_params = URI.encode_www_form(sorted_params)
|
18
|
+
|
19
|
+
Digest::SHA1.hexdigest str_params + api_secret_key
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module BOTR
|
2
|
+
|
3
|
+
class Channel < BOTR::Object
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
attr_reader :last_status
|
8
|
+
|
9
|
+
def show(key)
|
10
|
+
json = get_request({:method => 'show',
|
11
|
+
:channel_key => key})
|
12
|
+
res = JSON.parse(json.body)
|
13
|
+
|
14
|
+
if json.status == 200
|
15
|
+
params = process_show_response(res)
|
16
|
+
else
|
17
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
18
|
+
end
|
19
|
+
|
20
|
+
return new(params)
|
21
|
+
end
|
22
|
+
|
23
|
+
alias :find :show
|
24
|
+
|
25
|
+
def list(**options)
|
26
|
+
json = get_request(options.merge(:method => 'list'))
|
27
|
+
res = JSON.parse(json.body)
|
28
|
+
|
29
|
+
if json.status == 200
|
30
|
+
results = process_list_response(res)
|
31
|
+
else
|
32
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
33
|
+
end
|
34
|
+
|
35
|
+
return results
|
36
|
+
end
|
37
|
+
|
38
|
+
def all
|
39
|
+
list({})
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def process_show_response(body)
|
45
|
+
@last_status = body["status"]
|
46
|
+
return body["channel"]
|
47
|
+
end
|
48
|
+
|
49
|
+
def process_list_response(body)
|
50
|
+
res = []
|
51
|
+
|
52
|
+
body["channels"].each do |channel|
|
53
|
+
res << new(channel)
|
54
|
+
end
|
55
|
+
|
56
|
+
return res
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
attr_reader :last_status, :key, :author, :title, :description, :link,
|
62
|
+
:type, :tags, :tags_mode, :sort_order, :videos, :views
|
63
|
+
|
64
|
+
def initialize(params = {})
|
65
|
+
params.each do |key, val|
|
66
|
+
param = "@#{key.to_s}"
|
67
|
+
next unless methods.include? key.to_sym
|
68
|
+
instance_variable_set(param, val)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def create(type, **options)
|
73
|
+
json = get_request(options.merge(:method => 'create',
|
74
|
+
:type => type))
|
75
|
+
res = JSON.parse(json.body)
|
76
|
+
|
77
|
+
if json.status == 200
|
78
|
+
process_create_response(res)
|
79
|
+
else
|
80
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
81
|
+
end
|
82
|
+
|
83
|
+
return self
|
84
|
+
end
|
85
|
+
|
86
|
+
def update(**options)
|
87
|
+
json = put_request(options.merge(:channel_key => @key))
|
88
|
+
res = JSON.parse(json.body)
|
89
|
+
|
90
|
+
if json.status == 200
|
91
|
+
process_update_response(res, options)
|
92
|
+
else
|
93
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
94
|
+
end
|
95
|
+
|
96
|
+
return self
|
97
|
+
end
|
98
|
+
|
99
|
+
def delete
|
100
|
+
json = delete_request({:channel_key => @key})
|
101
|
+
res = JSON.parse(json.body)
|
102
|
+
|
103
|
+
if json.status == 200
|
104
|
+
process_delete_response(res)
|
105
|
+
else
|
106
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
107
|
+
end
|
108
|
+
|
109
|
+
return self
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def process_create_response(body)
|
115
|
+
@last_status = body["status"]
|
116
|
+
@key = body["channel"]["key"]
|
117
|
+
end
|
118
|
+
|
119
|
+
def process_update_response(body, updated_params)
|
120
|
+
@last_status = body["status"]
|
121
|
+
updated_params.each do |key, val|
|
122
|
+
param = "@#{key.to_s}"
|
123
|
+
next unless methods.include? key
|
124
|
+
instance_variable_set(param, val)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def process_delete_response(body)
|
129
|
+
@last_status = body["status"]
|
130
|
+
instance_variables.each do |param|
|
131
|
+
instance_variable_set(param, nil)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module BOTR
|
2
|
+
|
3
|
+
class ChannelThumbnail < BOTR::Object
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
attr_reader :last_status
|
8
|
+
|
9
|
+
def show(key)
|
10
|
+
json = get_request({:method => 'show',
|
11
|
+
:channel_key => key})
|
12
|
+
res = JSON.parse(json.body)
|
13
|
+
|
14
|
+
if json.status == 200
|
15
|
+
params = process_show_response(res)
|
16
|
+
else
|
17
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
18
|
+
end
|
19
|
+
|
20
|
+
return new(params)
|
21
|
+
end
|
22
|
+
|
23
|
+
alias :find :show
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def process_show_response(body)
|
28
|
+
@last_status = body["status"]
|
29
|
+
|
30
|
+
return body["thumbnail"]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :last_status, :key, :status, :error
|
36
|
+
|
37
|
+
def initialize(params = {})
|
38
|
+
params.each do |key, val|
|
39
|
+
param = "@#{key.to_s}"
|
40
|
+
next unless methods.include? key.to_sym
|
41
|
+
instance_variable_set(param, val)
|
42
|
+
end
|
43
|
+
|
44
|
+
raise ArgumentError, "You must specify a channel key." if @key.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def update
|
48
|
+
json = put_request({:channel_key => @key})
|
49
|
+
res = JSON.parse(json.body)
|
50
|
+
|
51
|
+
if json.status == 200
|
52
|
+
process_update_response(res)
|
53
|
+
else
|
54
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
55
|
+
end
|
56
|
+
|
57
|
+
return self
|
58
|
+
end
|
59
|
+
|
60
|
+
def upload(data_path, **options)
|
61
|
+
json = post_request(options, data_path)
|
62
|
+
res = JSON.parse(json.body)
|
63
|
+
|
64
|
+
if json.status == 200
|
65
|
+
process_upload_response(res)
|
66
|
+
else
|
67
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
68
|
+
end
|
69
|
+
|
70
|
+
return self
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def process_update_response(body)
|
76
|
+
@last_status = body["status"]
|
77
|
+
@key = body["media"]["key"]
|
78
|
+
@link = body["link"]
|
79
|
+
end
|
80
|
+
|
81
|
+
def process_upload_response(body)
|
82
|
+
@last_status = body["status"]
|
83
|
+
@file = body["file"]
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module BOTR
|
2
|
+
|
3
|
+
class ChannelVideo < BOTR::Object
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
attr_reader :last_status
|
8
|
+
|
9
|
+
def show(key, **options)
|
10
|
+
json = get_request(options.merge(:method => 'show',
|
11
|
+
:channel_key => key))
|
12
|
+
res = JSON.parse(json.body)
|
13
|
+
|
14
|
+
if json.status == 200
|
15
|
+
params = process_show_response(res)
|
16
|
+
else
|
17
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
18
|
+
end
|
19
|
+
|
20
|
+
return new(params)
|
21
|
+
end
|
22
|
+
|
23
|
+
alias :find :show
|
24
|
+
|
25
|
+
def list(key, **options)
|
26
|
+
json = get_request(options.merge(:method => 'list',
|
27
|
+
:channel_key => key))
|
28
|
+
res = JSON.parse(json.body)
|
29
|
+
|
30
|
+
if json.status == 200
|
31
|
+
results = process_list_response(res)
|
32
|
+
else
|
33
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
34
|
+
end
|
35
|
+
|
36
|
+
return results
|
37
|
+
end
|
38
|
+
|
39
|
+
def update(channel_key, **options)
|
40
|
+
json = put_request(options.merge(:channel_key => channel_key))
|
41
|
+
res = JSON.parse(json.body)
|
42
|
+
|
43
|
+
if json.status == 200
|
44
|
+
process_update_response(res)
|
45
|
+
else
|
46
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
47
|
+
end
|
48
|
+
|
49
|
+
return self
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def process_show_response(body)
|
55
|
+
@last_status = body["status"]
|
56
|
+
return body["video"]
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_list_response(body)
|
60
|
+
res = []
|
61
|
+
|
62
|
+
body["videos"].each do |video|
|
63
|
+
res << new(video)
|
64
|
+
end
|
65
|
+
|
66
|
+
return res
|
67
|
+
end
|
68
|
+
|
69
|
+
def process_update_response(body)
|
70
|
+
@last_status = body["status"]
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
attr_reader :last_status, :key, :author, :date, :description, :duration,
|
76
|
+
:link, :md5, :mediatype, :tags, :title, :views
|
77
|
+
|
78
|
+
def initialize(params = {})
|
79
|
+
params.each do |key, val|
|
80
|
+
param = "@#{key.to_s}"
|
81
|
+
next unless methods.include? key.to_sym
|
82
|
+
instance_variable_set(param, val)
|
83
|
+
end
|
84
|
+
raise ArgumentError, "You must specify a video key." if @key.nil?
|
85
|
+
end
|
86
|
+
|
87
|
+
def create(channel_key, **options)
|
88
|
+
json = get_request(options.merge(:method => 'create',
|
89
|
+
:channel_key => channel_key,
|
90
|
+
:video_key => @key))
|
91
|
+
res = JSON.parse(json.body)
|
92
|
+
|
93
|
+
if json.status == 200
|
94
|
+
process_create_response(res)
|
95
|
+
else
|
96
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
97
|
+
end
|
98
|
+
|
99
|
+
return self
|
100
|
+
end
|
101
|
+
|
102
|
+
def delete(channel_key)
|
103
|
+
json = delete_request({:channel_key => channel_key})
|
104
|
+
res = JSON.parse(json.body)
|
105
|
+
|
106
|
+
if json.status == 200
|
107
|
+
process_delete_response(res)
|
108
|
+
else
|
109
|
+
raise "HTTP Error #{json.status}: #{json.body}"
|
110
|
+
end
|
111
|
+
|
112
|
+
return self
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def process_create_response(body)
|
118
|
+
@last_status = body["status"]
|
119
|
+
end
|
120
|
+
|
121
|
+
def process_delete_response(body)
|
122
|
+
@last_status = body["status"]
|
123
|
+
instance_variables.each do |param|
|
124
|
+
instance_variable_set(param, nil)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|