msp-youtube-g 0.4.8.1 → 0.4.8.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,5 @@
1
- == trunk
1
+ == trunk
2
+ * Create a method to check the status of the uploaded video by status URL [msp]
2
3
  * Move network dependent tests to integration-test [msp]
3
4
  * Create a parser and a model for upload errors [msp]
4
5
  * Stub driven tests for VideoFeedParser, VideosFeedParser, UploadErrorParser [msp]
@@ -26,5 +26,5 @@ require File.dirname(__FILE__) + '/youtube_g/request/video_search'
26
26
  require File.dirname(__FILE__) + '/youtube_g/response/video_search'
27
27
 
28
28
  class YouTubeG #:nodoc:
29
- VERSION = '0.4.8.1'
29
+ VERSION = '0.4.8.3'
30
30
  end
@@ -61,16 +61,34 @@ class YouTubeG
61
61
  # Retrieves a single YouTube video.
62
62
  #
63
63
  # === Parameters
64
- # vid<String>:: The ID or URL of the video that you'd like to retrieve.
64
+ # vid<String>:: The ID or URL of the video that you'd like to retrieve. If your uncertain
65
+ # of the processed state use video_processed_by_youtube? first else this will fail.
65
66
  #
66
67
  # === Returns
67
68
  # YouTubeG::Model::Video
68
69
  def video_by(vid)
69
- video_id = vid =~ /^http/ ? vid : "http://gdata.youtube.com/feeds/videos/#{vid}"
70
+ video_id = vid =~ /^http/ ? vid : "http://gdata.youtube.com/feeds/api/videos/#{vid}"
70
71
  parser = YouTubeG::Parser::VideoFeedParser.new(video_id)
71
- parser.parse
72
- end
73
-
72
+ parser.parse
73
+ end
74
+
75
+ # Checks the status of a users uploaded video.
76
+ #
77
+ # === Parameters
78
+ # status_url<String>:: The URL returned by YT when the video was uploaded e.g.
79
+ #
80
+ # http://gdata.youtube.com/feeds/api/users/speechboxmatt/uploads/QR1sWOVqxoM
81
+ #
82
+ # This is stored on upload as Video.status_url
83
+ # === Returns
84
+ # Boolean
85
+ def video_by_status_url(status_url)
86
+ parser = YouTubeG::Parser::VideoFeedParser.new(status_url)
87
+ video = parser.parse
88
+ return video
89
+ end
90
+
91
+
74
92
  private
75
93
 
76
94
  def calculate_offset(page, per_page)
@@ -59,7 +59,10 @@ class YouTubeG
59
59
  # Used in video uploads only to check the state of the upload
60
60
  class AppControl < YouTubeG::Record
61
61
  attr_reader :draft
62
- attr_reader :state
62
+ attr_reader :state
63
+ attr_reader :reason
64
+ attr_reader :help_url
65
+ attr_reader :description
63
66
  end
64
67
 
65
68
  # *Fixnum*:: Duration of a video in seconds.
@@ -113,6 +116,9 @@ class YouTubeG
113
116
  # *String*:: The link to watch the URL on YouTubes website.
114
117
  attr_reader :player_url
115
118
 
119
+ # *String*:: The URL to check the processing status of the video at YT.
120
+ attr_reader :status_url
121
+
116
122
  # YouTubeG::Model::Rating:: Information about the videos rating.
117
123
  attr_reader :rating
118
124
 
@@ -187,6 +193,15 @@ EDOC
187
193
  # String: Absolute URL for embedding video
188
194
  def embed_url
189
195
  @player_url.sub('watch?', '').sub('=', '/')
196
+ end
197
+
198
+ # Has this vid been processed by YT?
199
+ #
200
+ # === Returns
201
+ # Boolean
202
+ def processed?
203
+ return true if self.app_control == nil
204
+ return false if self.app_control.state.upcase == 'PROCESSING' || self.app_control.state.upcase == 'REJECTED' || self.app_control.state.upcase == 'FAILED'
190
205
  end
191
206
 
192
207
  end
@@ -68,7 +68,10 @@ class YouTubeG
68
68
  if app_control_element
69
69
  app_control = YouTubeG::Model::Video::AppControl.new(
70
70
  :draft => app_control_element.elements["app:draft"].text,
71
- :state => app_control_element.elements["yt:state"].attributes["name"])
71
+ :state => app_control_element.elements["yt:state"].attributes["name"],
72
+ :reason => app_control_element.elements["yt:state"].attributes["reasonCode"],
73
+ :help_url => app_control_element.elements["yt:state"].attributes["helpUrl"],
74
+ :description => app_control_element.elements["yt:state"].text)
72
75
  end
73
76
 
74
77
  # parse the category and keyword lists
@@ -136,7 +139,12 @@ class YouTubeG
136
139
  view_count = (el = entry.elements["yt:statistics"]) ? el.attributes["viewCount"].to_i : 0
137
140
 
138
141
  noembed = entry.elements["yt:noembed"] ? true : false
139
- racy = entry.elements["media:rating"] ? true : false
142
+ racy = entry.elements["media:rating"] ? true : false
143
+
144
+ status_url = nil
145
+ entry.elements.each("link") do |el|
146
+ status_url = el.attributes["href"] if el.attributes["rel"] == "self"
147
+ end
140
148
 
141
149
  YouTubeG::Model::Video.new(
142
150
  :video_id => video_id,
@@ -156,7 +164,8 @@ class YouTubeG
156
164
  :rating => rating,
157
165
  :view_count => view_count,
158
166
  :noembed => noembed,
159
- :racy => racy)
167
+ :racy => racy,
168
+ :status_url => status_url)
160
169
  end
161
170
 
162
171
  def parse_media_content (media_content_element)
@@ -79,9 +79,13 @@ class YouTubeG
79
79
  response = upload.post(direct_upload_url, upload_body, upload_header)
80
80
  # todo parse this out also
81
81
  if response.code.to_i == 403
82
+ logger.error("ERROR: #{response.code}")
82
83
  raise AuthenticationError, response.body[/<TITLE>(.+)<\/TITLE>/, 1]
83
- elsif response.code.to_i != 201
84
+ elsif response.code.to_i != 201
85
+ logger.error("ERROR: #{response.code}")
86
+ logger.debug("response: #{response.body}")
84
87
  upload_errors = YouTubeG::Parser::UploadErrorParser.new(response.body).parse
88
+ logger.debug("upload_errors: #{upload_errors}")
85
89
  raise UploadError, upload_errors.inspect
86
90
  end
87
91
  return YouTubeG::Parser::VideoFeedParser.new(response.body).parse
@@ -0,0 +1,47 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+ <entry xmlns='http://www.w3.org/2005/Atom' xmlns:gml='http://www.opengis.net/gml'
3
+ xmlns:georss='http://www.georss.org/georss' xmlns:media='http://search.yahoo.com/mrss/'
4
+ xmlns:batch='http://schemas.google.com/gdata/batch' xmlns:yt='http://gdata.youtube.com/schemas/2007'
5
+ xmlns:gd='http://schemas.google.com/g/2005'>
6
+ <id>http://gdata.youtube.com/feeds/api/videos/QR1sWOVqxoM</id>
7
+ <published>2008-08-22T04:07:16.000-07:00</published>
8
+ <updated>2008-08-22T04:07:16.000-07:00</updated>
9
+ <app:control xmlns:app='http://purl.org/atom/app#'>
10
+ <app:draft>yes</app:draft>
11
+ <yt:state name='rejected'
12
+ reasonCode='tooLong'
13
+ helpUrl='http://www.youtube.com/t/community_guidelines'>Video is too long.</yt:state>
14
+ </app:control>
15
+ <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='speechbox'/>
16
+ <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat' term='Film' label='Film &amp; Animation'/>
17
+ <category scheme='http://schemas.google.com/g/2005#kind' term='http://gdata.youtube.com/schemas/2007#video'/>
18
+ <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='wordia'/>
19
+ <title type='text'>discombobulate [08/22/2008 at 12:06PM]</title>
20
+ <content type='text'>To throw into a state of confusion; to befuddle or perplex</content>
21
+ <link rel='alternate' type='text/html' href='http://www.youtube.com/my_videos_edit?ns=1&amp;video_id=QR1sWOVqxoM'/>
22
+ <link rel='http://gdata.youtube.com/schemas/2007#video.responses' type='application/atom+xml'
23
+ href='http://gdata.youtube.com/feeds/api/videos/QR1sWOVqxoM/responses'/>
24
+ <link rel='http://gdata.youtube.com/schemas/2007#video.related' type='application/atom+xml'
25
+ href='http://gdata.youtube.com/feeds/api/videos/QR1sWOVqxoM/related'/>
26
+ <link rel='self' type='application/atom+xml'
27
+ href='http://gdata.youtube.com/feeds/api/users/speechboxmatt/uploads/QR1sWOVqxoM'/>
28
+ <author>
29
+ <name>speechboxmatt</name>
30
+ <uri>http://gdata.youtube.com/feeds/api/users/speechboxmatt</uri>
31
+ </author>
32
+ <media:group>
33
+ <media:title type='plain'>discombobulate [08/22/2008 at 12:06PM]</media:title>
34
+ <media:description type='plain'>To throw into a state of confusion; to befuddle or perplex</media:description>
35
+ <media:keywords>speechbox, wordia</media:keywords>
36
+ <yt:duration seconds='0'/>
37
+ <media:category label='Film &amp; Animation' scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
38
+ Film
39
+ </media:category>
40
+ <media:content url='http://www.youtube.com/v/QR1sWOVqxoM&amp;f=gdata_user_uploads'
41
+ type='application/x-shockwave-flash' medium='video' isDefault='true' expression='full'
42
+ yt:format='5'/>
43
+ </media:group>
44
+ <gd:comments>
45
+ <gd:feedLink href='http://gdata.youtube.com/feeds/api/videos/QR1sWOVqxoM/comments' countHint='0'/>
46
+ </gd:comments>
47
+ </entry>
@@ -4,7 +4,8 @@ require File.dirname(__FILE__) + '/../lib/youtube_g'
4
4
  class TestParser < Test::Unit::TestCase
5
5
 
6
6
  UPLOAD_XML = File.new(File.dirname(__FILE__) +"/upload.xml")
7
- SEARCH_XML = File.new(File.dirname(__FILE__) +"/search.xml")
7
+ SEARCH_XML = File.new(File.dirname(__FILE__) +"/search.xml")
8
+ YOUTUBE_STATUS_XML = File.new(File.dirname(__FILE__) +"/status.xml")
8
9
 
9
10
  YT_VALIDATION = "yt:validation"
10
11
  REQUIRED = "required"
@@ -18,6 +19,10 @@ class TestParser < Test::Unit::TestCase
18
19
  @vf_parser = YouTubeG::Parser::VideoFeedParser.new(UPLOAD_XML.path)
19
20
  @vf_parser_result = @vf_parser.parse
20
21
 
22
+ # video feed error
23
+ @vfe_parser = YouTubeG::Parser::VideoFeedParser.new(YOUTUBE_STATUS_XML.path)
24
+ @vfe_parser_result = @vfe_parser.parse
25
+
21
26
  @vfs_parser = YouTubeG::Parser::VideosFeedParser.new(SEARCH_XML.path)
22
27
  @vfs_parser_result = @vfs_parser.parse
23
28
  end
@@ -93,7 +98,9 @@ class TestParser < Test::Unit::TestCase
93
98
  assert_equal(320,video.thumbnails[3].width)
94
99
  assert_equal("00:00:07.500",video.thumbnails[3].time)
95
100
 
96
- assert_equal("http://www.youtube.com/watch?v=32_mQ0PRT9I",video.player_url)
101
+ assert_equal("http://www.youtube.com/watch?v=32_mQ0PRT9I",video.player_url)
102
+
103
+ assert_equal("http://gdata.youtube.com/feeds/api/users/speechboxmatt/uploads/32_mQ0PRT9I",video.status_url);
97
104
  end
98
105
  end
99
106
 
@@ -143,6 +150,21 @@ class TestParser < Test::Unit::TestCase
143
150
  assert_equal("application/x-shockwave-flash",video.media_content[0].mime_type)
144
151
  end
145
152
 
153
+ def test_video_feed_parser_with_error_status
154
+ video = @vfe_parser_result
155
+ assert_instance_of(YouTubeG::Model::Video, video)
156
+
157
+ assert_equal("http://gdata.youtube.com/feeds/api/videos/QR1sWOVqxoM",video.video_id)
158
+
159
+ # App control - state of the upload
160
+ assert_equal("yes", video.app_control.draft)
161
+ assert_equal("rejected", video.app_control.state)
162
+ # these populated only if errored
163
+ assert_equal("tooLong", video.app_control.reason)
164
+ assert_equal("http://www.youtube.com/t/community_guidelines", video.app_control.help_url)
165
+ assert_equal("Video is too long.", video.app_control.description)
166
+ end
167
+
146
168
  def well_formed_errors_xml
147
169
  errors_xml = ''
148
170
  errors_xml << "<?xml version='1.0' encoding='UTF-8'?>"
@@ -169,4 +191,4 @@ class TestParser < Test::Unit::TestCase
169
191
  errors_xml << " <location type='xpath'>media:group/media:title/text()</location>"
170
192
  errors_xml << "</errors>"
171
193
  end
172
- end
194
+ end
@@ -0,0 +1,26 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/youtube_g'
3
+
4
+ class TestVideo < Test::Unit::TestCase
5
+
6
+ def test_processed_method_for_nil_state
7
+ # we assume no app_control from YT means processed.
8
+ video = YouTubeG::Model::Video.new({})
9
+ assert_equal(true, video.processed?)
10
+ end
11
+
12
+ def test_processed_method_for_processing_state
13
+ video = YouTubeG::Model::Video.new({:app_control => YouTubeG::Model::Video::AppControl.new({:state => 'processing'})})
14
+ assert_equal(false, video.processed?)
15
+ end
16
+
17
+ def test_processed_method_for_rejected_state
18
+ video = YouTubeG::Model::Video.new({:app_control => YouTubeG::Model::Video::AppControl.new({:state => 'rejected'})})
19
+ assert_equal(false, video.processed?)
20
+ end
21
+
22
+ def test_processed_method_for_failed_state
23
+ video = YouTubeG::Model::Video.new({:app_control => YouTubeG::Model::Video::AppControl.new({:state => 'failed'})})
24
+ assert_equal(false, video.processed?)
25
+ end
26
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msp-youtube-g
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8.1
4
+ version: 0.4.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Vitarana
@@ -58,9 +58,11 @@ files:
58
58
  - integration-test/test_video.rb
59
59
  - integration-test/test_video_search.rb
60
60
  - test/test_parser.rb
61
+ - test/test_video.rb
61
62
  - test/test_upload.rb
62
63
  - test/search.xml
63
64
  - test/upload.xml
65
+ - test/status.xml
64
66
  has_rdoc: true
65
67
  homepage: http://youtube-g.rubyforge.org/
66
68
  post_install_message: