viddler 0.2.2 → 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.
@@ -2,13 +2,15 @@ module Viddler
2
2
  # This class wraps Viddler's comment's information.
3
3
  class Comment
4
4
 
5
- attr_accessor :author, :text, :time
5
+ attr_accessor :id, :author, :text, :time, :timepoint
6
6
 
7
7
  def initialize(attributes={}) #:nodoc:
8
8
  a = attributes
9
+ @id = a['id']
9
10
  @author = a['author']
10
11
  @text = a['text']
11
12
  @time = Time.at(fix_unix_time(a['time']))
13
+ @timepoint = a['add_timepoint'].to_i / 1000
12
14
  end
13
15
 
14
16
  private
@@ -19,4 +21,4 @@ module Viddler
19
21
  end
20
22
 
21
23
  end
22
- end
24
+ end
@@ -16,20 +16,25 @@ class MultipartParams #:nodoc:
16
16
  end
17
17
 
18
18
  def pack_params(hash)
19
- marker = "--#{@boundary_token}\r\n"
20
- files_params = hash.find_all{|k,v| v.is_a?(File)}.to_h
21
- text_params = hash - files_params
19
+ marker = "--#{@boundary_token}"
20
+ # Partition the hash, then return 2 hashes from the arrays returned.
21
+ files_params, text_params = hash.partition { |k,v| v.is_a?(File) or v.is_a?(Tempfile) }.map do |a|
22
+ # Converts array like [['foo', 'bar']] => {'foo' => 'bar'}
23
+ a.inject({}) { |h, x| h[x[0]] = x[1]; h }
24
+ end
22
25
 
23
- pack_hash(text_params, marker) + marker + pack_hash(files_params, marker) + "--#{@boundary_token}--\r\n"
26
+ pack_hash(text_params, marker+"\r\n") + pack_hash(files_params, marker+"\r\n") + marker + "--"
24
27
  end
25
28
 
26
29
  def pack_hash(hash, marker)
27
30
  hash.map do |name, value|
28
31
  marker + case value
29
- when String
32
+ when String, Fixnum
30
33
  text_to_multipart(name, value)
31
- when File
34
+ when File, Tempfile
32
35
  file_to_multipart(name, value)
36
+ else
37
+ raise "Unexpected #{value.class}: #{value.inspect}"
33
38
  end
34
39
  end.join('')
35
40
  end
@@ -1,34 +1,34 @@
1
1
  require 'rest_client'
2
2
 
3
3
  module Viddler
4
-
4
+
5
5
  # Raised when response from Viddler contains absolutely no data
6
6
  class EmptyResponseError < ViddlerError #:nodoc:
7
7
  end
8
-
8
+
9
9
  # Raised when response from Viddler contains an error
10
10
  class ResponseError < ViddlerError #:nodoc:
11
11
  def initialize(message)
12
12
  super message
13
13
  end
14
14
  end
15
-
15
+
16
16
  # Class used to send requests over http to Viddler API.
17
17
  class Request #:nodoc:
18
-
18
+
19
19
  API_URL = 'http://api.viddler.com/rest/v1/'
20
20
  DEFAULT_HEADERS = {:accept => 'application/xml', :content_type => 'application/x-www-form-urlencoded'}
21
-
21
+
22
22
  attr_accessor :url, :http_method, :response, :body
23
23
  attr_reader :headers, :params
24
-
24
+
25
25
  def initialize(http_method, method) #:nodoc:
26
26
  @http_method = http_method.to_s
27
27
  @url = API_URL
28
- self.params = {:method => viddlerize(method)}
28
+ self.params = {:method => viddlerize(method)}
29
29
  self.headers = DEFAULT_HEADERS
30
30
  end
31
-
31
+
32
32
  # Use this method to setup your request's payload and headers.
33
33
  #
34
34
  # Example:
@@ -41,54 +41,54 @@ module Viddler
41
41
  # p.sessionid = '12323'
42
42
  # p.api_key = '13123
43
43
  # end
44
- #
44
+ #
45
45
  def set(container, &declarations)
46
46
  struct = OpenStruct.new
47
47
  declarations.call(struct)
48
48
  send("#{container}=", struct.table)
49
49
  end
50
-
50
+
51
51
  # Send http request to Viddler API.
52
52
  def run(&block)
53
53
  if block_given?
54
54
  set(:params, &block)
55
55
  end
56
-
56
+
57
57
  if post? and multipart?
58
58
  put_multipart_params_into_body
59
59
  else
60
60
  put_params_into_url
61
- end
61
+ end
62
62
  request = RestClient::Request.execute(
63
- :method => http_method,
64
- :url => url,
65
- :headers => headers,
63
+ :method => http_method,
64
+ :url => url,
65
+ :headers => headers,
66
66
  :payload => body
67
67
  )
68
68
  self.response = parse_response(request)
69
69
  end
70
-
70
+
71
71
  private
72
-
72
+
73
73
  def parse_response(raw_response)
74
- raise EmptyResponseError if raw_response.blank?
74
+ raise EmptyResponseError if raw_response.nil? || raw_response.empty?
75
75
  response_hash = Hash.from_xml(raw_response)
76
76
  if response_error = response_hash['error']
77
77
  raise ResponseError.new(viddler_error_message(response_error))
78
78
  end
79
79
  response_hash
80
80
  end
81
-
81
+
82
82
  def put_multipart_params_into_body
83
83
  multiparams = MultipartParams.new(params)
84
84
  self.body = multiparams.body
85
85
  self.headers = {:content_type => multiparams.content_type}
86
86
  end
87
-
87
+
88
88
  def put_params_into_url
89
- self.url = API_URL + '?' + params.to_query
89
+ self.url = self.url + '?' + params.to_query
90
90
  end
91
-
91
+
92
92
  def viddlerize(name)
93
93
  if name.include?('viddler.')
94
94
  name
@@ -96,34 +96,35 @@ module Viddler
96
96
  'viddler.' + name
97
97
  end
98
98
  end
99
-
99
+
100
100
  def params=(hash) #:nodoc:
101
101
  @params ||= Hash.new
102
102
  @params.update(hash)
103
103
  end
104
-
104
+
105
105
  def headers=(hash) #:nodoc:
106
106
  @headers ||= Hash.new
107
107
  @headers.update(hash)
108
108
  end
109
-
109
+
110
110
  def multipart? #:nodoc:
111
- if params.find{|k,v| v.is_a?(File)} then true else false end
111
+ # Todo: Fix this to find a common ancestor.
112
+ if params.find{|k,v| v.is_a?(File) or v.is_a?(Tempfile) } then true else false end
112
113
  end
113
-
114
+
114
115
  def post? #:nodoc:
115
116
  http_method == 'post'
116
117
  end
117
-
118
+
118
119
  def viddler_error_message(response_error)
119
120
  description = response_error['description'] || ''
120
- details = response_error['details'] || ''
121
+ details = response_error['details'] || ''
121
122
  code = response_error['code'] || ''
122
-
123
+
123
124
  details = ": #{details};" unless details.empty?
124
125
  code = " [code: #{code}]" unless code.empty?
125
126
  %Q[#{description}#{details}#{code}]
126
127
  end
127
-
128
+
128
129
  end
129
- end
130
+ end
@@ -2,7 +2,7 @@ module Viddler #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 2
5
- TINY = 2
5
+ TINY = 8
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -1,7 +1,9 @@
1
1
  module Viddler
2
2
  # This class wraps Viddler's video's information.
3
3
  class Video
4
-
4
+
5
+ include Comparable
6
+
5
7
  attr_accessor :id,
6
8
  :url,
7
9
  :title,
@@ -13,56 +15,93 @@ module Viddler
13
15
  :view_count,
14
16
  :upload_time,
15
17
  :comment_count,
16
- :update_time,
17
18
  :permissions,
18
- :comment_list
19
+ :comments,
20
+ :width,
21
+ :height
19
22
 
20
23
  def initialize(attributes={}) #:nodoc:
21
- a = attributes
22
- @id = a['id']
23
- @title = a['title']
24
- @description = a['description']
25
- @tags = a['tags']
26
- @url = a['url']
27
- @thumbnail_url = a['thumbnail_url']
28
- @author = a['author']
29
- @length_seconds = a['length_seconds'].to_i
30
- @view_count = a['view_count'].to_i
31
- @comment_count = a['comment_count'].to_i
32
- @update_time = a['update_time'] ? Time.at(a['update_time'].to_i) : nil
33
- @permissions = a['permissions'] ? a['permissions'] : nil
34
- @comments = a['comment_list'].values.flatten.collect do |comment|
24
+ @id = attributes['id']
25
+ @title = attributes['title']
26
+ @description = attributes['description']
27
+ @tags = attributes['tags'] ? attributes['tags']['global'].to_a : []
28
+ @url = attributes['url']
29
+ @thumbnail_url = attributes['thumbnail_url']
30
+ @author = attributes['author']
31
+ @length_seconds = attributes['length_seconds'].to_i
32
+ @view_count = attributes['view_count'].to_i
33
+ @comment_count = attributes['comment_count'].to_i
34
+ @upload_time = attributes['upload_time'] ? Time.at(attributes['upload_time'].to_i/1000) : nil
35
+ @permissions = attributes['permissions'] ? attributes['permissions'] : nil
36
+ @comments = attributes['comment_list'].values.flatten.collect do |comment|
35
37
  Viddler::Comment.new(comment)
36
- end if a['comment_list']
38
+ end if attributes['comment_list']
39
+ @width = attributes['width'].to_i
40
+ @height = attributes['height'].to_i
37
41
  end
38
42
 
39
- # Returns HTML code for video embedding.
43
+ # Returns proper HTML code for embedding
44
+ #
45
+ # <tt>options</tt> hash could contain:
46
+ # * <tt>player_type:</tt> The type of player to embed, either "simple" or "player" (default is "player");
47
+ # * <tt>width:</tt> The width of the player (default is 437);
48
+ # * <tt>height:</tt> The height of the player (default is 370);
49
+ # * <tt>autoplay:</tt> Whether or not to autoplay the video, either "t" or "f" (default is "f");
50
+ # * <tt>playAll:</tt> Set to "true" to enable play all player (requires player_type to be "player");
51
+ #
52
+ # Any additional options passed to the method will be added as flashvars
53
+ #
54
+ # Example:
55
+ #
56
+ # @video.embed_code(:player_type => 'simple', :width => 300, :height => 300, autoplay => 't')
57
+ #
58
+ # Returns embed code for auto playing simple player with 300px width and height
59
+ #
40
60
  def embed_code(options={})
41
- options = {
61
+ options.reverse_merge! \
42
62
  :player_type => 'player',
43
63
  :width => 437,
44
64
  :height => 370,
45
- :autoplay => 'f'
46
- }.merge(options)
65
+ :autoplay => 'f',
66
+ :use_secret_url => false
47
67
 
48
68
  # get non flashvars from options
49
- player_type = options.delete(:player_type)
50
- width = options.delete(:width)
51
- height = options.delete(:height)
69
+ player_type = options.delete(:player_type)
70
+ width = options.delete(:width)
71
+ height = options.delete(:height)
72
+ use_secret_url = options.delete(:use_secret_url)
52
73
 
53
74
  flashvars = options.collect{|key,value| "#{key}=#{value}"}.join('&')
54
75
 
76
+ additional = use_secret_url ? "0/#{permissions['view']['secreturl']}/" : ''
77
+
55
78
  html = <<CODE
56
79
  <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="#{width}" height="#{height}" id="viddlerplayer-#{self.id}">
57
- <param name="movie" value="http://www.viddler.com/#{player_type}/#{self.id}/" />
80
+ <param name="movie" value="http://www.viddler.com/#{player_type}/#{self.id}/#{additional}" />
58
81
  <param name="allowScriptAccess" value="always" />
59
82
  <param name="allowFullScreen" value="true" />
60
83
  <param name="flashvars" value="#{flashvars}" />
61
- <embed src="http://www.viddler.com/#{player_type}/#{self.id}/" width="#{width}" height="#{height}" type="application/x-shockwave-flash" allowScriptAccess="always" flashvars="#{flashvars}" allowFullScreen="true" name="viddlerplayer-#{self.id}" >
84
+ <embed src="http://www.viddler.com/#{player_type}/#{self.id}/#{additional}" width="#{width}" height="#{height}" type="application/x-shockwave-flash" allowScriptAccess="always" flashvars="#{flashvars}" allowFullScreen="true" name="viddlerplayer-#{self.id}" >
62
85
  </embed>
63
- </object>'
86
+ </object>
64
87
  CODE
65
88
  end
66
-
89
+
90
+ def ==(other)
91
+ eql?(other)
92
+ end
93
+
94
+ def eql?(other)
95
+ id == other.id
96
+ end
97
+
98
+ def hash
99
+ id.to_i
100
+ end
101
+
102
+ def <=>(other)
103
+ title <=> other.title
104
+ end
105
+
67
106
  end
68
- end
107
+ end
@@ -0,0 +1,8 @@
1
+ <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="437" height="370" id="viddlerplayer-6a2babb2">
2
+ <param name="movie" value="http://www.viddler.com/player/6a2babb2/" />
3
+ <param name="allowScriptAccess" value="always" />
4
+ <param name="allowFullScreen" value="true" />
5
+ <param name="flashvars" value="autoplay=f" />
6
+ <embed src="http://www.viddler.com/player/6a2babb2/" width="437" height="370" type="application/x-shockwave-flash" allowScriptAccess="always" flashvars="autoplay=f" allowFullScreen="true" name="viddlerplayer-6a2babb2" >
7
+ </embed>
8
+ </object>
@@ -1,2 +1,7 @@
1
1
  require 'test/unit'
2
- require 'viddler'
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ Bundler.setup
6
+
7
+ require File.dirname(__FILE__) + '/../lib/viddler'
@@ -5,20 +5,31 @@ class ViddlerTest < Test::Unit::TestCase
5
5
  def message
6
6
  'In order to run this test, insert working Viddler API key inside API_KEY constant.'
7
7
  end
8
- end
9
-
8
+ end
9
+
10
10
  class CredentialsRequired < Exception
11
11
  def message
12
12
  'In order to run this test, insert working Viddler username and password inside LOGIN and PASSWORD constants.'
13
13
  end
14
14
  end
15
-
16
- # In order to run the tests you need a working Viddler account and an API key.
17
- API_KEY = nil
18
- LOGIN = nil
19
- PASSWORD = nil
20
- TEST_VIDEO_FILE_PATH = '/Users/ilya/Desktop/file.mov'
21
-
15
+
16
+ begin
17
+ load 'api_settings.rb'
18
+ raise LoadError unless defined?(API_KEY)
19
+ raise LoadError unless defined?(LOGIN)
20
+ raise LoadError unless defined?(PASSWORD)
21
+ raise LoadError unless defined?(TEST_VIDEO_FILE_PATH)
22
+ rescue LoadError
23
+ puts "\n"
24
+ puts "To run tests, create an test/api_settings.rb file with the following constants:\n\n"
25
+ puts "API_KEY = 'your_viddler_api_key'"
26
+ puts "LOGIN = 'your_viddler_login'"
27
+ puts "PASSWORD = 'your_viddler_password'"
28
+ puts "TEST_VIDEO_FILE_PATH = '/path/to/video/file'"
29
+ puts "\n"*2
30
+ exit
31
+ end
32
+
22
33
  def setup
23
34
  raise KeyRequired unless API_KEY
24
35
  @viddler = Viddler::Base.new(API_KEY, LOGIN, PASSWORD)
@@ -29,72 +40,107 @@ class ViddlerTest < Test::Unit::TestCase
29
40
  @viddler.authenticate
30
41
  assert @viddler.authenticated?
31
42
  end
32
-
43
+
33
44
  def test_should_get_record_token
34
45
  credentials_required
35
46
  token = @viddler.get_record_token
36
47
  assert_kind_of String, token
37
48
  end
38
-
49
+
39
50
  def test_should_upload_video
40
51
  credentials_required
41
52
  file = File.open(TEST_VIDEO_FILE_PATH)
42
- video = @viddler.upload_video(:file => file, :title => 'Testing', :description => 'Bla', :tags => 'one, two, three', :make_public => '0')
53
+ video = @viddler.upload_video(:file => file, :title => 'Testing', :description => 'Bla', :tags => 'one, two, three', :make_public => 1)
54
+ assert_kind_of Viddler::Video, video
43
55
  end
44
-
56
+
57
+ def test_should_upload_tempfile
58
+ credentials_required
59
+ file = File.open(TEST_VIDEO_FILE_PATH)
60
+ tmpfile = Tempfile.new('viddlertest')
61
+ tmpfile.write file.read
62
+ tmpfile.seek 0
63
+ video = @viddler.upload_video(:file => tmpfile, :title => 'Testing Tempfile', :description => 'tempfile description', :tags => 'one, two, three', :make_public => 1)
64
+ assert_kind_of Viddler::Video, video
65
+ end
66
+
67
+ # Works in v2 API, use that.
68
+ # def test_should_delete_video
69
+ # credentials_required
70
+ # file = File.open(TEST_VIDEO_FILE_PATH)
71
+ # video = @viddler.upload_video(:file => file, :title => 'Testing', :description => 'Bla', :tags => 'one, two, three', :make_public => 1)
72
+ # assert @viddler.delete_video(video.id)
73
+ # end
74
+
75
+ # doesnt work
76
+ # def test_should_update_profile
77
+ # credentials_required
78
+ # user = @viddler.update_profile(:first_name => 'Ilya',
79
+ # :last_name => 'Sabanin',
80
+ # :about_me => 'A guy',
81
+ # :birthdate => '1987-05-22',
82
+ # :gender => 'm',
83
+ # :company => 'Wildbit',
84
+ # :city => 'Krasnoyarsk')
85
+ # assert_kind_of Viddler::User, user
86
+ # end
87
+
45
88
  def test_should_find_profile
46
89
  user = @viddler.find_profile('ilya')
47
90
  assert_kind_of Viddler::User, user
48
91
  end
49
-
50
- def test_should_update_profile
51
- credentials_required
52
- user = @viddler.update_profile(:first_name => 'Ilya',
53
- :last_name => 'Sabanin',
54
- :about_me => 'A guy',
55
- :birthdate => '1987-05-22',
56
- :gender => 'm',
57
- :company => 'Wildbit',
58
- :city => 'Krasnoyarsk')
59
- assert_kind_of Viddler::User, user
60
- end
61
-
92
+
62
93
  def test_should_update_account
63
94
  credentials_required
64
95
  assert @viddler.update_account(:show_account => '0')
65
96
  end
66
-
97
+
67
98
  def test_should_get_video_status
68
99
  assert @viddler.get_video_status('f8605d95')
69
100
  end
70
-
101
+
71
102
  def test_should_find_video_by_id
72
103
  video = @viddler.find_video_by_id('6b0b9af1')
73
104
  assert_kind_of Viddler::Video, video
74
105
  end
75
-
106
+
107
+ def test_should_get_dimensions
108
+ video = @viddler.find_video_by_id('6b0b9af1')
109
+ assert_equal 640, video.width
110
+ assert_equal 360, video.height
111
+ end
112
+
76
113
  def test_should_find_video_by_url
77
114
  video = @viddler.find_video_by_url('http://www.viddler.com/explore/ijustine/videos/293/')
78
115
  assert_kind_of Viddler::Video, video
79
116
  end
80
-
117
+
81
118
  def test_should_find_all_videos_by_user
82
119
  videos = @viddler.find_all_videos_by_user('ijustine')
83
120
  assert_kind_of Viddler::Video, videos.first
84
121
  end
85
122
 
123
+ def test_should_update_video
124
+ credentials_required
125
+ videos = @viddler.find_all_videos_by_user(LOGIN)
126
+ raise LoadError, "You must have at least one video in your account to test updates" unless videos.length > 0
127
+ video = videos.first
128
+ update = @viddler.update_video(video.id, :title => video.title + ' [test]', :description => video.description + ' [tested]')
129
+ assert_kind_of Viddler::Video, update
130
+ end
131
+
86
132
  def test_should_find_all_videos_by_tag
87
133
  videos = @viddler.find_all_videos_by_tag('hot')
88
134
  assert_kind_of Viddler::Video, videos.first
89
135
  end
90
-
136
+
91
137
  def test_should_find_all_features_videos
92
138
  videos = @viddler.find_all_featured_videos
93
139
  assert_kind_of Viddler::Video, videos.first
94
140
  end
95
-
141
+
96
142
  private
97
-
143
+
98
144
  def credentials_required
99
145
  raise CredentialsRequired unless LOGIN and PASSWORD
100
146
  end