yt 0.7.7 → 0.7.8
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/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
|