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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +4 -0
- data/lib/yt/collections/resumable_sessions.rb +8 -22
- data/lib/yt/models/account.rb +38 -3
- data/lib/yt/models/resumable_session.rb +10 -7
- data/lib/yt/models/video.rb +37 -0
- data/lib/yt/version.rb +1 -1
- data/spec/requests/as_account/authentications_spec.rb +1 -7
- data/spec/requests/as_account/thumbnail.jpg +0 -0
- data/spec/requests/as_account/video_spec.rb +22 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f38c80c9cc34b749849ed9934a037fe7707614ce
|
4
|
+
data.tar.gz: 2a9a06c9f14a9fabe19aa0d74e47e2a2fe2aaf6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
#
|
15
|
-
# URL to upload the
|
16
|
-
# @param [Integer] content_length the size (bytes) of the
|
17
|
-
# @param [Hash] options the metadata to add to the uploaded
|
18
|
-
|
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] =
|
47
|
-
params[:params] =
|
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'] =
|
40
|
+
headers['X-Upload-Content-Type'] = @parent.upload_content_type
|
55
41
|
end
|
56
42
|
end
|
57
43
|
|
data/lib/yt/models/account.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
17
|
-
|
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
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
data/lib/yt/models/video.rb
CHANGED
@@ -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
@@ -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
|
-
|
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
|
|
Binary file
|
@@ -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.
|
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-
|
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
|