yt 0.13.9 → 0.13.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: db12d589d5763d973797f580561eff7054db2643
4
- data.tar.gz: 2e73f17f11c03ae2b1e3805ba855fa7e84eb7610
3
+ metadata.gz: f38c80c9cc34b749849ed9934a037fe7707614ce
4
+ data.tar.gz: 2a9a06c9f14a9fabe19aa0d74e47e2a2fe2aaf6f
5
5
  SHA512:
6
- metadata.gz: 9cd65afd9ef4f2837604e2570fa3e404cec78fd183e9cb9cd0e7b0e1896c29cf53b50e2e210a1ed3d1688c747a9b12bffa93e14ed448c7efe35d7365beb34532
7
- data.tar.gz: e78d7b773dc49accb73b6e33c3285f5cde7dca2c49da55b071ccd9437df46d79a3c83df5c93ed211ba552d0a15c5a0b698c329860c8073eb6235bd113c89ae64
6
+ metadata.gz: d39da84ceb5bd9941ea7a90b32ca01e2c94d1aa101289ac7ff012728663f08279bf2d6e961761aeb3043f973fe9304109d4449b95c45e78126784bc7d278bdc4
7
+ data.tar.gz: fed816b3f0ef773b7b3f1050135c1a1e08b953ada0ba4aeafc69571c9e0f0408158190a20bcb4be0f4bca803a246254d2738502fed05ec4b4c61f512e09c585c
data/CHANGELOG.md CHANGED
@@ -6,6 +6,10 @@ For more information about changelogs, check
6
6
  [Keep a Changelog](http://keepachangelog.com) and
7
7
  [Vandamme](http://tech-angels.github.io/vandamme).
8
8
 
9
+ ## 0.13.9 - 2015-02-17
10
+
11
+ * [FEATURE] New `video.upload_thumbnail` to upload the thumbnail for a video.
12
+
9
13
  ## 0.13.9 - 2015-02-16
10
14
 
11
15
  * [ENHANCEMENT] Accept `force: true` in `authentication_url` to force approval prompt.
data/README.md CHANGED
@@ -236,6 +236,7 @@ Use [Yt::Video](http://rubydoc.info/github/Fullscreen/yt/master/Yt/Models/Video)
236
236
 
237
237
  * read the attributes of a video
238
238
  * update the attributes of a video
239
+ * upload a thumbnail for a video
239
240
  * access the annotations of a video
240
241
  * delete a video
241
242
  * like and dislike a video
@@ -322,6 +323,9 @@ video = Yt::Video.new id: 'MESycYJytkU', auth: account
322
323
  video.update title: 'A title', description: 'A description <with angle brackets>'
323
324
  video.update tags: ['a tag'], categoryId: '21', license: 'creativeCommon'
324
325
 
326
+ video.upload_thumbnail 'my_thumbnail.jpg'
327
+ video.upload_thumbnail 'http://example.com/remote.png'
328
+
325
329
  video.views since: 7.days.ago #=> {Wed, 28 May 2014 => 12.0, Thu, 29 May 2014 => 3.0, …}
326
330
  video.comments until: 2.days.ago #=> {Wed, 28 May 2014 => 9.0, Thu, 29 May 2014 => 4.0, …}
327
331
  video.likes from: 8.days.ago #=> {Tue, 27 May 2014 => 7.0, Wed, 28 May 2014 => 0.0, …}
@@ -11,26 +11,12 @@ module Yt
11
11
  class ResumableSessions < Base
12
12
 
13
13
  # Starts a resumable session by sending to YouTube the metadata of the
14
- # video to upload. If the request succeeds, YouTube returns a unique
15
- # URL to upload the video file (and eventually resume the upload).
16
- # @param [Integer] content_length the size (bytes) of the video to upload.
17
- # @param [Hash] options the metadata to add to the uploaded video.
18
- # @option options [String] :title The video’s title.
19
- # @option options [String] :description The video’s description.
20
- # @option options [Array<String>] :title The video’s tags.
21
- # @option options [Integer] :category_id The video’s category ID.
22
- # @option options [String] :privacy_status The video’s privacy status.
23
- def insert(content_length, options = {})
14
+ # object to upload. If the request succeeds, YouTube returns a unique
15
+ # URL to upload the object file (and eventually resume the upload).
16
+ # @param [Integer] content_length the size (bytes) of the object to upload.
17
+ # @param [Hash] options the metadata to add to the uploaded object.
18
+ def insert(content_length, body = {})
24
19
  @headers = headers_for content_length
25
- body = {}
26
-
27
- snippet = options.slice :title, :description, :tags, :category_id
28
- snippet[:categoryId] = snippet.delete(:category_id) if snippet[:category_id]
29
- body[:snippet] = snippet if snippet.any?
30
-
31
- status = options[:privacy_status]
32
- body[:status] = {privacyStatus: status} if status
33
-
34
20
  do_insert body: body, headers: @headers
35
21
  end
36
22
 
@@ -43,15 +29,15 @@ module Yt
43
29
  def insert_params
44
30
  super.tap do |params|
45
31
  params[:response_format] = nil
46
- params[:path] = '/upload/youtube/v3/videos'
47
- params[:params] = {part: 'snippet,status', uploadType: 'resumable'}
32
+ params[:path] = @parent.upload_path
33
+ params[:params] = @parent.upload_params.merge uploadType: 'resumable'
48
34
  end
49
35
  end
50
36
 
51
37
  def headers_for(content_length)
52
38
  {}.tap do |headers|
53
39
  headers['x-upload-content-length'] = content_length
54
- headers['X-Upload-Content-Type'] = 'video/*'
40
+ headers['X-Upload-Content-Type'] = @parent.upload_content_type
55
41
  end
56
42
  end
57
43
 
@@ -46,7 +46,7 @@ module Yt
46
46
  # @return [Yt::Collections::Playlists] the account’s playlists.
47
47
  has_many :playlists
48
48
 
49
- # Uploads a video
49
+ # Uploads a video using resumable sessions
50
50
  # @param [String] path_or_url the video to upload. Can either be the
51
51
  # path of a local file or the URL of a remote file.
52
52
  # @param [Hash] params the metadata to add to the uploaded video.
@@ -57,8 +57,11 @@ module Yt
57
57
  # @return [Yt::Models::Video] the newly uploaded video.
58
58
  def upload_video(path_or_url, params = {})
59
59
  file = open path_or_url, 'rb'
60
- session = resumable_sessions.insert file.size, params
61
- session.upload_video file
60
+ session = resumable_sessions.insert file.size, upload_body(params)
61
+
62
+ session.update(body: file) do |data|
63
+ Yt::Video.new id: data['id'], snippet: data['snippet'], status: data['privacyStatus'], auth: self
64
+ end
62
65
  end
63
66
 
64
67
  def create_playlist(params = {})
@@ -71,6 +74,38 @@ module Yt
71
74
  def videos_params
72
75
  {for_mine: true}
73
76
  end
77
+
78
+ # @private
79
+ # Tells `has_many :resumable_sessions` what path to hit to upload a file.
80
+ def upload_path
81
+ '/upload/youtube/v3/videos'
82
+ end
83
+ # @private
84
+ # Tells `has_many :resumable_sessions` what params are set for the object
85
+ # associated to the uploaded file.
86
+ def upload_params
87
+ {part: 'snippet,status'}
88
+ end
89
+
90
+ # @private
91
+ # Tells `has_many :resumable_sessions` what metadata to set in the object
92
+ # associated to the uploaded file.
93
+ def upload_body(params = {})
94
+ {}.tap do |body|
95
+ snippet = params.slice :title, :description, :tags, :category_id
96
+ snippet[:categoryId] = snippet.delete(:category_id) if snippet[:category_id]
97
+ body[:snippet] = snippet if snippet.any?
98
+
99
+ status = params[:privacy_status]
100
+ body[:status] = {privacyStatus: status} if status
101
+ end
102
+ end
103
+
104
+ # @private
105
+ # Tells `has_many :resumable_sessions` what type of file can be uploaded.
106
+ def upload_content_type
107
+ 'video/*'
108
+ end
74
109
  end
75
110
  end
76
111
  end
@@ -13,14 +13,17 @@ module Yt
13
13
  @headers = options[:headers]
14
14
  end
15
15
 
16
- # Uploads a video using the current resumable session
17
- # @param [#read] file A binary object that contains the video content.
16
+ def update(params = {})
17
+ do_update(params) {|data| yield data}
18
+ end
19
+
20
+ # Uploads a thumbnail using the current resumable session
21
+ # @param [#read] file A binary object that contains the image content.
18
22
  # Can either be a File, a StringIO (for instance using open-uri), etc.
19
- # @return [Yt::Models::Video] the newly uploaded video.
20
- def upload_video(file)
21
- do_update(body: file) do |data|
22
- Yt::Video.new id: data['id'], snippet: data['snippet'], status: data['privacyStatus'], auth: @auth
23
- end
23
+ # @return the new thumbnail resource for the given image.
24
+ # @see https://developers.google.com/youtube/v3/docs/thumbnails#resource
25
+ def upload_thumbnail(file)
26
+ do_update(body: file) {|data| data['items'].first}
24
27
  end
25
28
 
26
29
  private
@@ -73,6 +73,11 @@ module Yt
73
73
  delegate :view_count, :like_count, :dislike_count, :favorite_count,
74
74
  :comment_count, to: :statistics_set
75
75
 
76
+ # @!attribute [r] resumable_sessions
77
+ # @return [Yt::Collections::ResumableSessions] the sessions used to
78
+ # upload thumbnails using the resumable upload protocol.
79
+ has_many :resumable_sessions
80
+
76
81
  # Override Resource's new to set statistics and content details as well
77
82
  # if the response includes them
78
83
  def initialize(options = {})
@@ -163,6 +168,20 @@ module Yt
163
168
  !liked?
164
169
  end
165
170
 
171
+ # Uploads a thumbnail
172
+ # @param [String] path_or_url the image to upload. Can either be the
173
+ # path of a local file or the URL of a remote file.
174
+ # @return the new thumbnail resource for the given image.
175
+ # @see https://developers.google.com/youtube/v3/docs/thumbnails#resource
176
+ def upload_thumbnail(path_or_url)
177
+ file = open path_or_url, 'rb'
178
+ session = resumable_sessions.insert file.size
179
+
180
+ session.update(body: file) do |data|
181
+ snippet.instance_variable_set :@thumbnails, data['items'].first
182
+ end
183
+ end
184
+
166
185
  # @private
167
186
  # Tells `has_reports` to retrieve the reports from YouTube Analytics API
168
187
  # either as a Channel or as a Content Owner.
@@ -178,6 +197,24 @@ module Yt
178
197
  end
179
198
  end
180
199
 
200
+ # @private
201
+ # Tells `has_many :resumable_sessions` what path to hit to upload a file.
202
+ def upload_path
203
+ '/upload/youtube/v3/thumbnails/set'
204
+ end
205
+ # @private
206
+ # Tells `has_many :resumable_sessions` what params are set for the object
207
+ # associated to the uploaded file.
208
+ def upload_params
209
+ {video_id: id}
210
+ end
211
+
212
+ # @private
213
+ # Tells `has_many :resumable_sessions` what type of file can be uploaded.
214
+ def upload_content_type
215
+ 'application/octet-stream'
216
+ end
217
+
181
218
  private
182
219
 
183
220
  # @see https://developers.google.com/youtube/v3/docs/videos/update
data/lib/yt/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yt
2
- VERSION = '0.13.9'
2
+ VERSION = '0.13.10'
3
3
  end
@@ -109,15 +109,9 @@ describe Yt::Account, :device_app do
109
109
  it { expect{account.authentication}.to raise_error Yt::Errors::MissingAuth }
110
110
  end
111
111
 
112
- # @note: This test is a reflection of another irrational behavior of
113
- # YouTube API. When passing a wrong 'device_code', YouTube crashes and
114
- # raises 500, instead of an expected MissingAuth.
115
- # The day YouTube fixes it, then this test will finally fail and the
116
- # commented line will be restored.
117
112
  context 'and an invalid device code' do
118
113
  before { attrs[:device_code] = '--not-a-valid-device-code--' }
119
- # it { expect{account.authentication}.to raise_error Yt::Errors::MissingAuth }
120
- it { expect{account.authentication}.to raise_error Yt::Errors::ServerError }
114
+ it { expect{account.authentication}.to raise_error Yt::Errors::MissingAuth }
121
115
  end
122
116
  end
123
117
 
@@ -342,4 +342,26 @@ describe Yt::Video, :device_app do
342
342
  end
343
343
  end
344
344
  end
345
+
346
+ # @note: This should somehow test that the thumbnail *changes*. However,
347
+ # YouTube does not change the URL of the thumbnail even though the content
348
+ # changes. A full test would have to *download* the thumbnails before and
349
+ # after, and compare the files. For now, not raising error is enough.
350
+ # Eventually, change to `expect{update}.to change{video.thumbnail_url}`
351
+ context 'given one of my own videos for which I want to upload a thumbnail' do
352
+ let(:id) { $account.videos.where(order: 'viewCount').first.id }
353
+ let(:update) { video.upload_thumbnail path_or_url }
354
+
355
+ context 'given the path to a local JPG image file' do
356
+ let(:path_or_url) { File.expand_path '../thumbnail.jpg', __FILE__ }
357
+
358
+ it { expect{update}.not_to raise_error }
359
+ end
360
+
361
+ context 'given the path to a remote PNG image file' do
362
+ let(:path_or_url) { 'https://bit.ly/yt_thumbnail' }
363
+
364
+ it { expect{update}.not_to raise_error }
365
+ end
366
+ end
345
367
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.9
4
+ version: 0.13.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claudio Baccigalupo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-16 00:00:00.000000000 Z
11
+ date: 2015-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -257,6 +257,7 @@ files:
257
257
  - spec/requests/as_account/playlist_item_spec.rb
258
258
  - spec/requests/as_account/playlist_spec.rb
259
259
  - spec/requests/as_account/resource_spec.rb
260
+ - spec/requests/as_account/thumbnail.jpg
260
261
  - spec/requests/as_account/video.mp4
261
262
  - spec/requests/as_account/video_spec.rb
262
263
  - spec/requests/as_content_owner/account_spec.rb
@@ -353,6 +354,7 @@ test_files:
353
354
  - spec/requests/as_account/playlist_item_spec.rb
354
355
  - spec/requests/as_account/playlist_spec.rb
355
356
  - spec/requests/as_account/resource_spec.rb
357
+ - spec/requests/as_account/thumbnail.jpg
356
358
  - spec/requests/as_account/video.mp4
357
359
  - spec/requests/as_account/video_spec.rb
358
360
  - spec/requests/as_content_owner/account_spec.rb