yt 0.7.7 → 0.7.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/HISTORY.md +1 -0
- data/README.md +5 -1
- data/lib/yt/actions/delete.rb +5 -10
- data/lib/yt/actions/insert.rb +6 -2
- data/lib/yt/actions/modify.rb +27 -0
- data/lib/yt/actions/update.rb +5 -10
- data/lib/yt/associations/has_reports.rb +15 -0
- data/lib/yt/collections/channels.rb +3 -13
- data/lib/yt/collections/device_flows.rb +2 -12
- data/lib/yt/collections/playlist_items.rb +3 -17
- data/lib/yt/collections/playlists.rb +3 -17
- data/lib/yt/collections/resources.rb +37 -0
- data/lib/yt/collections/resumable_sessions.rb +62 -0
- data/lib/yt/models/account.rb +21 -0
- data/lib/yt/models/annotation.rb +10 -6
- data/lib/yt/models/playlist.rb +0 -19
- data/lib/yt/models/playlist_item.rb +0 -11
- data/lib/yt/models/request.rb +2 -0
- data/lib/yt/models/resource.rb +18 -0
- data/lib/yt/models/resumable_session.rb +47 -0
- data/lib/yt/models/video.rb +0 -12
- data/lib/yt/version.rb +1 -1
- data/spec/requests/as_account/account_spec.rb +17 -0
- data/spec/requests/as_account/video.mp4 +0 -0
- data/spec/spec_helper.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e5cc6f7948f9df0ff8bb425aa5ed45cb653a810
|
4
|
+
data.tar.gz: 5e150be0550652202b54315ba399fb7c3ad02404
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: adb48260492477a302919bea67fa73291403cf48532297bdd3f80392c3da01e0f49c8d022064c82612ceb6af528728607390bb791a75b1d165b8dd08c822a2c9
|
7
|
+
data.tar.gz: 143a4e311f40230fa56c17d76edb9eff0192d5c809abf011881a084f4d7ebb03abc5b8e95bf88771cfac47c322c5db998a199d4db2a7ce3e550bcf9f922bd8c5
|
data/Gemfile.lock
CHANGED
data/HISTORY.md
CHANGED
@@ -14,6 +14,7 @@ v0.7 - 2014/06/18
|
|
14
14
|
* New channel reports: comments, likes, dislikes, shares and impressions
|
15
15
|
* Allow both normal and partnered channels to retrieve reports about views, comments, likes, dislikes, shares
|
16
16
|
* Make reports available also on Video (not just Channel)
|
17
|
+
* New account.upload_video to upload a video (either local or remote).
|
17
18
|
|
18
19
|
v0.6 - 2014/06/05
|
19
20
|
-----------------
|
data/README.md
CHANGED
@@ -44,6 +44,7 @@ Use [Yt::Account](http://rubydoc.info/github/Fullscreen/yt/master/Yt/Models/Acco
|
|
44
44
|
* read the attributes of the account
|
45
45
|
* access the channel managed by the account
|
46
46
|
* access the videos uploaded by the account
|
47
|
+
* upload a video
|
47
48
|
|
48
49
|
```ruby
|
49
50
|
# Accounts can be initialized with access token, refresh token or an authorization code
|
@@ -54,6 +55,9 @@ account.channel #=> #<Yt::Models::Channel @id=...>
|
|
54
55
|
|
55
56
|
account.videos.count #=> 12
|
56
57
|
account.videos.first #=> #<Yt::Models::Video @id=...>
|
58
|
+
|
59
|
+
account.upload_video 'my_video.mp4', title: 'My new video', privacy_status: 'private'
|
60
|
+
account.upload_video 'http://example.com/remote.m4v', title: 'My other video', tags: ['music']
|
57
61
|
```
|
58
62
|
|
59
63
|
*All the above methods require authentication (see below).*
|
@@ -471,7 +475,7 @@ To install on your system, run
|
|
471
475
|
|
472
476
|
To use inside a bundled Ruby project, add this line to the Gemfile:
|
473
477
|
|
474
|
-
gem 'yt', '~> 0.7.
|
478
|
+
gem 'yt', '~> 0.7.8'
|
475
479
|
|
476
480
|
Since the gem follows [Semantic Versioning](http://semver.org),
|
477
481
|
indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
|
data/lib/yt/actions/delete.rb
CHANGED
@@ -1,23 +1,18 @@
|
|
1
|
-
require 'yt/
|
1
|
+
require 'yt/actions/modify'
|
2
2
|
|
3
3
|
module Yt
|
4
4
|
module Actions
|
5
5
|
module Delete
|
6
|
+
include Modify
|
6
7
|
|
7
8
|
private
|
8
9
|
|
9
|
-
def do_delete(extra_delete_params = {})
|
10
|
-
|
11
|
-
response = request.run
|
12
|
-
yield response.body
|
10
|
+
def do_delete(extra_delete_params = {}, &block)
|
11
|
+
do_modify delete_params.merge(extra_delete_params), &block
|
13
12
|
end
|
14
13
|
|
15
14
|
def delete_params
|
16
|
-
|
17
|
-
params[:method] = :delete
|
18
|
-
params[:auth] = @auth
|
19
|
-
params[:expected_response] = Net::HTTPNoContent
|
20
|
-
end
|
15
|
+
modify_params.tap{|params| params[:method] = :delete}
|
21
16
|
end
|
22
17
|
end
|
23
18
|
end
|
data/lib/yt/actions/insert.rb
CHANGED
@@ -7,10 +7,10 @@ module Yt
|
|
7
7
|
private
|
8
8
|
|
9
9
|
def do_insert(extra_insert_params = {})
|
10
|
-
request = Yt::Request.new insert_params.
|
10
|
+
request = Yt::Request.new insert_params.deep_merge(extra_insert_params)
|
11
11
|
response = request.run
|
12
12
|
@items = []
|
13
|
-
new_item response
|
13
|
+
new_item extract_data_from(response)
|
14
14
|
end
|
15
15
|
|
16
16
|
def insert_params
|
@@ -23,6 +23,10 @@ module Yt
|
|
23
23
|
params[:expected_response] = Net::HTTPOK
|
24
24
|
end
|
25
25
|
end
|
26
|
+
|
27
|
+
def extract_data_from(response)
|
28
|
+
response.body
|
29
|
+
end
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'yt/models/request'
|
2
|
+
|
3
|
+
module Yt
|
4
|
+
module Actions
|
5
|
+
# Abstract module that contains methods common to Delete and Update
|
6
|
+
module Modify
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def do_modify(params = {})
|
11
|
+
request = Yt::Request.new params
|
12
|
+
response = request.run
|
13
|
+
yield response.body
|
14
|
+
end
|
15
|
+
|
16
|
+
def modify_params
|
17
|
+
path = "/youtube/v3/#{self.class.to_s.demodulize.pluralize.camelize :lower}"
|
18
|
+
|
19
|
+
{}.tap do |params|
|
20
|
+
params[:path] = path
|
21
|
+
params[:auth] = @auth
|
22
|
+
params[:expected_response] = Net::HTTPNoContent
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/yt/actions/update.rb
CHANGED
@@ -1,23 +1,18 @@
|
|
1
|
-
require 'yt/
|
1
|
+
require 'yt/actions/modify'
|
2
2
|
|
3
3
|
module Yt
|
4
4
|
module Actions
|
5
5
|
module Update
|
6
|
+
include Modify
|
6
7
|
|
7
8
|
private
|
8
9
|
|
9
|
-
def do_update(extra_update_params = {})
|
10
|
-
|
11
|
-
response = request.run
|
12
|
-
yield response.body
|
10
|
+
def do_update(extra_update_params = {}, &block)
|
11
|
+
do_modify update_params.deep_merge(extra_update_params), &block
|
13
12
|
end
|
14
13
|
|
15
14
|
def update_params
|
16
|
-
|
17
|
-
params[:method] = :put
|
18
|
-
params[:auth] = @auth
|
19
|
-
params[:expected_response] = Net::HTTPNoContent
|
20
|
-
end
|
15
|
+
modify_params.tap{|params| params[:method] = :put}
|
21
16
|
end
|
22
17
|
end
|
23
18
|
end
|
@@ -27,10 +27,21 @@ module Yt
|
|
27
27
|
def has_report(metric)
|
28
28
|
require 'yt/collections/reports'
|
29
29
|
|
30
|
+
define_metric_on_method metric
|
31
|
+
define_metric_method metric
|
32
|
+
define_range_metric_method metric
|
33
|
+
define_all_metric_method metric
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def define_metric_on_method(metric)
|
30
39
|
define_method "#{metric}_on" do |date|
|
31
40
|
send(metric, from: date, to: date).values.first
|
32
41
|
end
|
42
|
+
end
|
33
43
|
|
44
|
+
def define_metric_method(metric)
|
34
45
|
define_method metric do |options = {}|
|
35
46
|
from = options[:since] || options[:from] || 5.days.ago
|
36
47
|
to = options[:until] || options[:to] || 1.day.ago
|
@@ -43,14 +54,18 @@ module Yt
|
|
43
54
|
[date, instance_variable_get("@#{metric}")[date] ||= send("range_#{metric}", range)[date]]
|
44
55
|
end]
|
45
56
|
end
|
57
|
+
end
|
46
58
|
|
59
|
+
def define_range_metric_method(metric)
|
47
60
|
define_method "range_#{metric}" do |date_range|
|
48
61
|
ivar = instance_variable_get "@range_#{metric}"
|
49
62
|
instance_variable_set "@range_#{metric}", ivar || {}
|
50
63
|
instance_variable_get("@range_#{metric}")[date_range] ||= send("all_#{metric}").within date_range
|
51
64
|
end
|
52
65
|
private "range_#{metric}"
|
66
|
+
end
|
53
67
|
|
68
|
+
def define_all_metric_method(metric)
|
54
69
|
define_method "all_#{metric}" do
|
55
70
|
# @note Asking for the "earnings" metric of a day in which a channel
|
56
71
|
# made 0 USD returns the wrong "nil". But adding to the request the
|
@@ -1,28 +1,18 @@
|
|
1
|
-
require 'yt/collections/
|
2
|
-
require 'yt/models/channel'
|
1
|
+
require 'yt/collections/resources'
|
3
2
|
|
4
3
|
module Yt
|
5
4
|
module Collections
|
6
5
|
# Provides methods to interact with a collection of YouTube channels.
|
7
6
|
#
|
8
7
|
# Resources with channels are: {Yt::Models::Account accounts}.
|
9
|
-
class Channels <
|
8
|
+
class Channels < Resources
|
10
9
|
|
11
10
|
private
|
12
11
|
|
13
|
-
# @return [Yt::Models::Channel] a new channel initialized with one of
|
14
|
-
# the items returned by asking YouTube for a list of channels.
|
15
|
-
# @see https://developers.google.com/youtube/v3/docs/channels#resource
|
16
|
-
def new_item(data)
|
17
|
-
Yt::Channel.new id: data['id'], snippet: data['snippet'], auth: @auth
|
18
|
-
end
|
19
|
-
|
20
12
|
# @return [Hash] the parameters to submit to YouTube to list channels.
|
21
13
|
# @see https://developers.google.com/youtube/v3/docs/channels/list
|
22
14
|
def list_params
|
23
|
-
super.tap
|
24
|
-
params[:params] = {maxResults: 50, part: 'snippet', mine: true}
|
25
|
-
end
|
15
|
+
super.tap{|params| params[:params].merge! mine: true}
|
26
16
|
end
|
27
17
|
end
|
28
18
|
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'yt/collections/
|
1
|
+
require 'yt/collections/authentications'
|
2
2
|
require 'yt/models/device_flow'
|
3
3
|
|
4
4
|
module Yt
|
5
5
|
module Collections
|
6
|
-
class DeviceFlows <
|
6
|
+
class DeviceFlows < Authentications
|
7
7
|
attr_accessor :auth_params
|
8
8
|
|
9
9
|
private
|
@@ -14,19 +14,9 @@ module Yt
|
|
14
14
|
|
15
15
|
def list_params
|
16
16
|
super.tap do |params|
|
17
|
-
params[:host] = 'accounts.google.com'
|
18
17
|
params[:path] = '/o/oauth2/device/code'
|
19
|
-
params[:body_type] = :form
|
20
|
-
params[:method] = :post
|
21
|
-
params[:auth] = nil
|
22
|
-
params[:body] = auth_params
|
23
18
|
end
|
24
19
|
end
|
25
|
-
|
26
|
-
def next_page
|
27
|
-
request = Yt::Request.new list_params
|
28
|
-
Array.wrap request.run.body
|
29
|
-
end
|
30
20
|
end
|
31
21
|
end
|
32
22
|
end
|
@@ -1,9 +1,8 @@
|
|
1
|
-
require 'yt/collections/
|
2
|
-
require 'yt/models/playlist_item'
|
1
|
+
require 'yt/collections/resources'
|
3
2
|
|
4
3
|
module Yt
|
5
4
|
module Collections
|
6
|
-
class PlaylistItems <
|
5
|
+
class PlaylistItems < Resources
|
7
6
|
|
8
7
|
# attrs are id and kind
|
9
8
|
def insert(attrs = {}, options = {}) #
|
@@ -16,25 +15,12 @@ module Yt
|
|
16
15
|
raise error unless options[:ignore_errors] && ignorable_errors.any?
|
17
16
|
end
|
18
17
|
|
19
|
-
def delete_all(params = {})
|
20
|
-
do_delete_all params
|
21
|
-
end
|
22
|
-
|
23
18
|
private
|
24
19
|
|
25
|
-
# @return [Yt::Models::PlaylistItem] a new playlist item initialized with
|
26
|
-
# one of the items returned by asking YouTube for a list of items.
|
27
|
-
# @see https://developers.google.com/youtube/v3/docs/playlistItems#resource
|
28
|
-
def new_item(data)
|
29
|
-
Yt::PlaylistItem.new id: data['id'], snippet: data['snippet'], status: data['status'], auth: @auth
|
30
|
-
end
|
31
|
-
|
32
20
|
# @return [Hash] the parameters to submit to YouTube to list items.
|
33
21
|
# @see https://developers.google.com/youtube/v3/docs/playlistItems/list
|
34
22
|
def list_params
|
35
|
-
super.tap
|
36
|
-
params[:params] = {maxResults: 50, part: 'snippet,status', playlistId: @parent.id}
|
37
|
-
end
|
23
|
+
super.tap{|params| params[:params].merge! playlistId: @parent.id}
|
38
24
|
end
|
39
25
|
end
|
40
26
|
end
|
@@ -1,9 +1,8 @@
|
|
1
|
-
require 'yt/collections/
|
2
|
-
require 'yt/models/playlist'
|
1
|
+
require 'yt/collections/resources'
|
3
2
|
|
4
3
|
module Yt
|
5
4
|
module Collections
|
6
|
-
class Playlists <
|
5
|
+
class Playlists < Resources
|
7
6
|
|
8
7
|
# Valid body (no defaults) are: title (string), description (string), privacy_status (string),
|
9
8
|
# tags (array of strings)
|
@@ -19,25 +18,12 @@ module Yt
|
|
19
18
|
do_insert body: body, params: {part: 'snippet,status'}
|
20
19
|
end
|
21
20
|
|
22
|
-
def delete_all(params = {})
|
23
|
-
do_delete_all params
|
24
|
-
end
|
25
|
-
|
26
21
|
private
|
27
22
|
|
28
|
-
# @return [Yt::Models::Playlist] a new playlist initialized with
|
29
|
-
# one of the items returned by asking YouTube for a list of playlists.
|
30
|
-
# @see https://developers.google.com/youtube/v3/docs/playlists#resource
|
31
|
-
def new_item(data)
|
32
|
-
Yt::Playlist.new id: data['id'], snippet: data['snippet'], status: data['status'], auth: @auth
|
33
|
-
end
|
34
|
-
|
35
23
|
# @return [Hash] the parameters to submit to YouTube to list playlists.
|
36
24
|
# @see https://developers.google.com/youtube/v3/docs/playlist/list
|
37
25
|
def list_params
|
38
|
-
super.tap
|
39
|
-
params[:params] = {maxResults: 50, part: 'snippet,status', channelId: @parent.id}
|
40
|
-
end
|
26
|
+
super.tap{|params| params[:params].merge! channelId: @parent.id}
|
41
27
|
end
|
42
28
|
end
|
43
29
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'yt/collections/base'
|
2
|
+
|
3
|
+
module Yt
|
4
|
+
module Collections
|
5
|
+
class Resources < Base
|
6
|
+
def delete_all(params = {})
|
7
|
+
do_delete_all params
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# @return [resource_class] a new resource item initialized with
|
13
|
+
# one of the items returned by asking YouTube for a list of items.
|
14
|
+
# @see https://developers.google.com/youtube/v3/docs/playlistItems#resource
|
15
|
+
# @see https://developers.google.com/youtube/v3/docs/playlists#resource
|
16
|
+
# @see https://developers.google.com/youtube/v3/docs/channels#resource
|
17
|
+
def new_item(data)
|
18
|
+
resource_class.new id: data['id'], snippet: data['snippet'], status: data['status'], auth: @auth
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Hash] the parameters to submit to YouTube to list items.
|
22
|
+
# @see https://developers.google.com/youtube/v3/docs/playlistItems/list
|
23
|
+
# @see https://developers.google.com/youtube/v3/docs/playlists/list
|
24
|
+
def list_params
|
25
|
+
super.tap do |params|
|
26
|
+
params[:params] = {maxResults: 50, part: 'snippet,status'}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def resource_class
|
31
|
+
resource_name = list_resources.name.demodulize.singularize
|
32
|
+
require "yt/models/#{resource_name.underscore}"
|
33
|
+
"Yt::Models::#{resource_name}".constantize
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'yt/collections/base'
|
2
|
+
require 'yt/models/resumable_session'
|
3
|
+
|
4
|
+
module Yt
|
5
|
+
module Collections
|
6
|
+
# Provides methods to upload videos with the resumable upload protocol.
|
7
|
+
#
|
8
|
+
# Resources with resumable sessions are: {Yt::Models::Account accounts}.
|
9
|
+
#
|
10
|
+
# @see https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol
|
11
|
+
class ResumableSessions < Base
|
12
|
+
|
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] params the metadata to add to the uploaded video.
|
18
|
+
# @option params [String] :title The video’s title.
|
19
|
+
# @option params [String] :description The video’s description.
|
20
|
+
# @option params [Array<String>] :title The video’s tags.
|
21
|
+
# @option params [String] :privacy_status The video’s privacy status.
|
22
|
+
def insert(content_length, options = {})
|
23
|
+
@headers = headers_for content_length
|
24
|
+
body = {}
|
25
|
+
|
26
|
+
snippet = options.slice :title, :description, :tags
|
27
|
+
body[:snippet] = snippet if snippet.any?
|
28
|
+
|
29
|
+
status = options[:privacy_status]
|
30
|
+
body[:status] = {privacyStatus: status} if status
|
31
|
+
|
32
|
+
do_insert body: body, headers: @headers
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def new_item(data)
|
38
|
+
Yt::ResumableSession.new url: data['Location'], headers: @headers, auth: @auth
|
39
|
+
end
|
40
|
+
|
41
|
+
def insert_params
|
42
|
+
super.tap do |params|
|
43
|
+
params[:format] = nil
|
44
|
+
params[:path] = '/upload/youtube/v3/videos'
|
45
|
+
params[:params] = {part: 'snippet,status', uploadType: 'resumable'}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def headers_for(content_length)
|
50
|
+
{}.tap do |headers|
|
51
|
+
headers['x-upload-content-length'] = content_length
|
52
|
+
headers['X-Upload-Content-Type'] = 'video/*'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# The result is not in the body but in the headers
|
57
|
+
def extract_data_from(response)
|
58
|
+
response.header
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/yt/models/account.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'open-uri'
|
1
2
|
require 'yt/models/base'
|
2
3
|
|
3
4
|
module Yt
|
@@ -26,6 +27,26 @@ module Yt
|
|
26
27
|
|
27
28
|
has_authentication
|
28
29
|
|
30
|
+
# @!attribute [r] resumable_sessions
|
31
|
+
# @return [Yt::Collections::ResumableSessions] the sessions used to
|
32
|
+
# upload videos using the resumable upload protocol.
|
33
|
+
has_many :resumable_sessions
|
34
|
+
|
35
|
+
# Uploads a video
|
36
|
+
# @param [String] path_or_url the video to upload. Can either be the
|
37
|
+
# path of a local file or the URL of a remote file.
|
38
|
+
# @param [Hash] params the metadata to add to the uploaded video.
|
39
|
+
# @option params [String] :title The video’s title.
|
40
|
+
# @option params [String] :description The video’s description.
|
41
|
+
# @option params [Array<String>] :title The video’s tags.
|
42
|
+
# @option params [String] :privacy_status The video’s privacy status.
|
43
|
+
# @return [Yt::Models::Video] the newly uploaded video.
|
44
|
+
def upload_video(path_or_url, params = {})
|
45
|
+
file = open path_or_url, 'rb'
|
46
|
+
session = resumable_sessions.insert file.size, params
|
47
|
+
session.upload_video file
|
48
|
+
end
|
49
|
+
|
29
50
|
# @private
|
30
51
|
# Tells `has_many :videos` that account.videos should return all the
|
31
52
|
# videos *owned by* the account (public, private, unlisted).
|
data/lib/yt/models/annotation.rb
CHANGED
@@ -107,15 +107,19 @@ module Yt
|
|
107
107
|
|
108
108
|
def timestamps
|
109
109
|
@timestamps ||= positions.reject{|pos| pos['t'] == 'never'}.map do |pos|
|
110
|
-
|
111
|
-
match = pos['t'].match regex
|
112
|
-
hours = (match[:hours] || '0').to_i
|
113
|
-
minutes = (match[:min] || '0').to_i
|
114
|
-
seconds = (match[:sec]).to_i
|
115
|
-
(hours * 60 + minutes) * 60 + seconds
|
110
|
+
timestamp_of pos
|
116
111
|
end
|
117
112
|
end
|
118
113
|
|
114
|
+
def timestamp_of(position)
|
115
|
+
regex = %r{(?:|(?<hours>\d*):)(?:|(?<min>\d*):)(?<sec>\d*)\.(?<ms>\d*)}
|
116
|
+
match = position['t'].match regex
|
117
|
+
hours = (match[:hours] || '0').to_i
|
118
|
+
minutes = (match[:min] || '0').to_i
|
119
|
+
seconds = (match[:sec]).to_i
|
120
|
+
(hours * 60 + minutes) * 60 + seconds
|
121
|
+
end
|
122
|
+
|
119
123
|
def positions
|
120
124
|
@positions ||= Array.wrap region['rectRegion'] || region['anchoredRegion']
|
121
125
|
end
|
data/lib/yt/models/playlist.rb
CHANGED
@@ -75,25 +75,6 @@ module Yt
|
|
75
75
|
|
76
76
|
private
|
77
77
|
|
78
|
-
# @return [Hash] the parameters to submit to YouTube to delete a playlist.
|
79
|
-
# @see https://developers.google.com/youtube/v3/docs/playlists/delete
|
80
|
-
def delete_params
|
81
|
-
super.tap do |params|
|
82
|
-
params[:path] = '/youtube/v3/playlists'
|
83
|
-
params[:params] = {id: @id}
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# @return [Hash] the parameters to submit to YouTube to update a playlist.
|
88
|
-
# @see https://developers.google.com/youtube/v3/docs/playlists/update
|
89
|
-
def update_params
|
90
|
-
super.tap do |params|
|
91
|
-
params[:path] = '/youtube/v3/playlists'
|
92
|
-
params[:body_type] = :json
|
93
|
-
params[:expected_response] = Net::HTTPOK
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
78
|
def video_params(video_id)
|
98
79
|
{id: video_id, kind: :video}
|
99
80
|
end
|
@@ -16,17 +16,6 @@ module Yt
|
|
16
16
|
def exists?
|
17
17
|
!@id.nil?
|
18
18
|
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
# @return [Hash] the parameters to submit to YouTube to delete a playlist item.
|
23
|
-
# @see https://developers.google.com/youtube/v3/docs/playlistItems/delete
|
24
|
-
def delete_params
|
25
|
-
super.tap do |params|
|
26
|
-
params[:path] = '/youtube/v3/playlistItems'
|
27
|
-
params[:params] = {id: @id}
|
28
|
-
end
|
29
|
-
end
|
30
19
|
end
|
31
20
|
end
|
32
21
|
end
|
data/lib/yt/models/request.rb
CHANGED
@@ -16,6 +16,7 @@ module Yt
|
|
16
16
|
def initialize(options = {})
|
17
17
|
@auth = options[:auth]
|
18
18
|
@body = options[:body]
|
19
|
+
@file = options[:file]
|
19
20
|
@body_type = options.fetch :body_type, :json
|
20
21
|
@expected_response = options.fetch :expected_response, Net::HTTPSuccess
|
21
22
|
@format = options.fetch :format, :json
|
@@ -83,6 +84,7 @@ module Yt
|
|
83
84
|
case @body_type
|
84
85
|
when :json then request.body = @body.to_json
|
85
86
|
when :form then request.set_form_data @body
|
87
|
+
when :file then request.body = @body.read
|
86
88
|
end if @body
|
87
89
|
end
|
88
90
|
|
data/lib/yt/models/resource.rb
CHANGED
@@ -29,6 +29,24 @@ module Yt
|
|
29
29
|
def username
|
30
30
|
@url.username if @url
|
31
31
|
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# @return [Hash] the parameters to submit to YouTube to update a playlist.
|
36
|
+
# @see https://developers.google.com/youtube/v3/docs/playlists/update
|
37
|
+
# @see https://developers.google.com/youtube/v3/docs/videos/update
|
38
|
+
def update_params
|
39
|
+
super.tap do |params|
|
40
|
+
params[:body_type] = :json
|
41
|
+
params[:expected_response] = Net::HTTPOK
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Hash] the parameters to submit to YouTube to delete a playlist.
|
46
|
+
# @see https://developers.google.com/youtube/v3/docs/playlists/delete
|
47
|
+
def delete_params
|
48
|
+
super.tap{|params| params[:params] = {id: @id}}
|
49
|
+
end
|
32
50
|
end
|
33
51
|
end
|
34
52
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'yt/models/base'
|
3
|
+
|
4
|
+
module Yt
|
5
|
+
module Models
|
6
|
+
# Provides methods to upload videos with the resumable upload protocol.
|
7
|
+
# @see https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol
|
8
|
+
class ResumableSession < Base
|
9
|
+
# Sets up a resumable session using the URI returned by YouTube
|
10
|
+
def initialize(options = {})
|
11
|
+
@uri = URI.parse options[:url]
|
12
|
+
@auth = options[:auth]
|
13
|
+
@headers = options[:headers]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Uploads a video using the current resumable session
|
17
|
+
# @param [#read] file A binary object that contains the video content.
|
18
|
+
# 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
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def session_params
|
29
|
+
CGI::parse(@uri.query).tap{|hash| hash.each{|k,v| hash[k] = v.first}}
|
30
|
+
end
|
31
|
+
|
32
|
+
# @note: YouTube documentation states that a valid upload returns an HTTP
|
33
|
+
# code of 201 Created -- however it looks like the actual code is 200.
|
34
|
+
# To be sure to include both cases, HTTPSuccess is used
|
35
|
+
def update_params
|
36
|
+
super.tap do |params|
|
37
|
+
params[:body_type] = :file
|
38
|
+
params[:host] = @uri.host
|
39
|
+
params[:path] = @uri.path
|
40
|
+
params[:expected_response] = Net::HTTPSuccess
|
41
|
+
params[:headers] = @headers
|
42
|
+
params[:params] = session_params
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/yt/models/video.rb
CHANGED
@@ -129,18 +129,6 @@ module Yt
|
|
129
129
|
params['filters'] = "video==#{id}"
|
130
130
|
end
|
131
131
|
end
|
132
|
-
|
133
|
-
private
|
134
|
-
|
135
|
-
# @return [Hash] the parameters to submit to YouTube to update a video.
|
136
|
-
# @see https://developers.google.com/youtube/v3/docs/videos/update
|
137
|
-
def update_params
|
138
|
-
super.tap do |params|
|
139
|
-
params[:path] = '/youtube/v3/videos'
|
140
|
-
params[:body_type] = :json
|
141
|
-
params[:expected_response] = Net::HTTPOK
|
142
|
-
end
|
143
|
-
end
|
144
132
|
end
|
145
133
|
end
|
146
134
|
end
|
data/lib/yt/version.rb
CHANGED
@@ -28,4 +28,21 @@ describe Yt::Account, :device_app do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
describe '.upload_video' do
|
33
|
+
let(:video_params) { {title: 'Test Yt upload', privacy_status: 'private'} }
|
34
|
+
let(:video) { $account.upload_video path_or_url, video_params }
|
35
|
+
|
36
|
+
context 'given the path to a local video file' do
|
37
|
+
let(:path_or_url) { File.expand_path '../video.mp4', __FILE__ }
|
38
|
+
|
39
|
+
it { expect(video).to be_a Yt::Video }
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'given the URL of a remote video file' do
|
43
|
+
let(:path_or_url) { 'https://bit.ly/yt_test' }
|
44
|
+
|
45
|
+
it { expect(video).to be_a Yt::Video }
|
46
|
+
end
|
47
|
+
end
|
31
48
|
end
|
Binary file
|
data/spec/spec_helper.rb
CHANGED
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.7.
|
4
|
+
version: 0.7.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claudio Baccigalupo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -121,6 +121,7 @@ files:
|
|
121
121
|
- lib/yt/actions/delete_all.rb
|
122
122
|
- lib/yt/actions/insert.rb
|
123
123
|
- lib/yt/actions/list.rb
|
124
|
+
- lib/yt/actions/modify.rb
|
124
125
|
- lib/yt/actions/update.rb
|
125
126
|
- lib/yt/associations/has_authentication.rb
|
126
127
|
- lib/yt/associations/has_many.rb
|
@@ -138,6 +139,8 @@ files:
|
|
138
139
|
- lib/yt/collections/playlists.rb
|
139
140
|
- lib/yt/collections/ratings.rb
|
140
141
|
- lib/yt/collections/reports.rb
|
142
|
+
- lib/yt/collections/resources.rb
|
143
|
+
- lib/yt/collections/resumable_sessions.rb
|
141
144
|
- lib/yt/collections/snippets.rb
|
142
145
|
- lib/yt/collections/statistics_sets.rb
|
143
146
|
- lib/yt/collections/statuses.rb
|
@@ -167,6 +170,7 @@ files:
|
|
167
170
|
- lib/yt/models/rating.rb
|
168
171
|
- lib/yt/models/request.rb
|
169
172
|
- lib/yt/models/resource.rb
|
173
|
+
- lib/yt/models/resumable_session.rb
|
170
174
|
- lib/yt/models/snippet.rb
|
171
175
|
- lib/yt/models/statistics_set.rb
|
172
176
|
- lib/yt/models/status.rb
|
@@ -213,6 +217,7 @@ files:
|
|
213
217
|
- spec/requests/as_account/playlist_item_spec.rb
|
214
218
|
- spec/requests/as_account/playlist_spec.rb
|
215
219
|
- spec/requests/as_account/resource_spec.rb
|
220
|
+
- spec/requests/as_account/video.mp4
|
216
221
|
- spec/requests/as_account/video_spec.rb
|
217
222
|
- spec/requests/as_content_owner/channel_spec.rb
|
218
223
|
- spec/requests/as_content_owner/content_owner_spec.rb
|
@@ -291,6 +296,7 @@ test_files:
|
|
291
296
|
- spec/requests/as_account/playlist_item_spec.rb
|
292
297
|
- spec/requests/as_account/playlist_spec.rb
|
293
298
|
- spec/requests/as_account/resource_spec.rb
|
299
|
+
- spec/requests/as_account/video.mp4
|
294
300
|
- spec/requests/as_account/video_spec.rb
|
295
301
|
- spec/requests/as_content_owner/channel_spec.rb
|
296
302
|
- spec/requests/as_content_owner/content_owner_spec.rb
|