yt-andrewroth 0.25.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +27 -0
- data/.rspec +3 -0
- data/.travis.yml +9 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +732 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.md +489 -0
- data/Rakefile +11 -0
- data/YOUTUBE_IT.md +835 -0
- data/bin/yt +30 -0
- data/gemfiles/Gemfile.activesupport-3.x +4 -0
- data/gemfiles/Gemfile.activesupport-4.x +4 -0
- data/lib/yt.rb +21 -0
- data/lib/yt/actions/base.rb +32 -0
- data/lib/yt/actions/delete.rb +19 -0
- data/lib/yt/actions/delete_all.rb +32 -0
- data/lib/yt/actions/insert.rb +42 -0
- data/lib/yt/actions/list.rb +139 -0
- data/lib/yt/actions/modify.rb +37 -0
- data/lib/yt/actions/patch.rb +19 -0
- data/lib/yt/actions/update.rb +19 -0
- data/lib/yt/associations/has_attribute.rb +55 -0
- data/lib/yt/associations/has_authentication.rb +214 -0
- data/lib/yt/associations/has_many.rb +22 -0
- data/lib/yt/associations/has_one.rb +22 -0
- data/lib/yt/associations/has_reports.rb +320 -0
- data/lib/yt/collections/advertising_options_sets.rb +34 -0
- data/lib/yt/collections/annotations.rb +62 -0
- data/lib/yt/collections/assets.rb +58 -0
- data/lib/yt/collections/authentications.rb +47 -0
- data/lib/yt/collections/base.rb +62 -0
- data/lib/yt/collections/channels.rb +31 -0
- data/lib/yt/collections/claim_histories.rb +34 -0
- data/lib/yt/collections/claims.rb +56 -0
- data/lib/yt/collections/content_details.rb +30 -0
- data/lib/yt/collections/content_owner_details.rb +34 -0
- data/lib/yt/collections/content_owners.rb +32 -0
- data/lib/yt/collections/device_flows.rb +23 -0
- data/lib/yt/collections/file_details.rb +30 -0
- data/lib/yt/collections/ids.rb +27 -0
- data/lib/yt/collections/live_streaming_details.rb +30 -0
- data/lib/yt/collections/ownerships.rb +34 -0
- data/lib/yt/collections/partnered_channels.rb +28 -0
- data/lib/yt/collections/players.rb +30 -0
- data/lib/yt/collections/playlist_items.rb +53 -0
- data/lib/yt/collections/playlists.rb +28 -0
- data/lib/yt/collections/policies.rb +28 -0
- data/lib/yt/collections/ratings.rb +23 -0
- data/lib/yt/collections/references.rb +46 -0
- data/lib/yt/collections/related_playlists.rb +43 -0
- data/lib/yt/collections/reports.rb +161 -0
- data/lib/yt/collections/resources.rb +57 -0
- data/lib/yt/collections/resumable_sessions.rb +51 -0
- data/lib/yt/collections/snippets.rb +27 -0
- data/lib/yt/collections/statistics_sets.rb +30 -0
- data/lib/yt/collections/statuses.rb +27 -0
- data/lib/yt/collections/subscribed_channels.rb +46 -0
- data/lib/yt/collections/subscribers.rb +33 -0
- data/lib/yt/collections/subscriptions.rb +50 -0
- data/lib/yt/collections/user_infos.rb +36 -0
- data/lib/yt/collections/video_categories.rb +35 -0
- data/lib/yt/collections/videos.rb +137 -0
- data/lib/yt/config.rb +54 -0
- data/lib/yt/errors/forbidden.rb +13 -0
- data/lib/yt/errors/missing_auth.rb +81 -0
- data/lib/yt/errors/no_items.rb +13 -0
- data/lib/yt/errors/request_error.rb +74 -0
- data/lib/yt/errors/server_error.rb +13 -0
- data/lib/yt/errors/unauthorized.rb +50 -0
- data/lib/yt/models/account.rb +216 -0
- data/lib/yt/models/advertising_options_set.rb +38 -0
- data/lib/yt/models/annotation.rb +132 -0
- data/lib/yt/models/asset.rb +111 -0
- data/lib/yt/models/asset_metadata.rb +38 -0
- data/lib/yt/models/asset_snippet.rb +46 -0
- data/lib/yt/models/authentication.rb +83 -0
- data/lib/yt/models/base.rb +32 -0
- data/lib/yt/models/channel.rb +302 -0
- data/lib/yt/models/claim.rb +156 -0
- data/lib/yt/models/claim_event.rb +67 -0
- data/lib/yt/models/claim_history.rb +29 -0
- data/lib/yt/models/configuration.rb +70 -0
- data/lib/yt/models/content_detail.rb +65 -0
- data/lib/yt/models/content_owner.rb +48 -0
- data/lib/yt/models/content_owner_detail.rb +18 -0
- data/lib/yt/models/description.rb +58 -0
- data/lib/yt/models/device_flow.rb +16 -0
- data/lib/yt/models/file_detail.rb +21 -0
- data/lib/yt/models/id.rb +9 -0
- data/lib/yt/models/iterator.rb +16 -0
- data/lib/yt/models/live_streaming_detail.rb +23 -0
- data/lib/yt/models/match_policy.rb +34 -0
- data/lib/yt/models/ownership.rb +75 -0
- data/lib/yt/models/player.rb +18 -0
- data/lib/yt/models/playlist.rb +218 -0
- data/lib/yt/models/playlist_item.rb +112 -0
- data/lib/yt/models/policy.rb +36 -0
- data/lib/yt/models/policy_rule.rb +124 -0
- data/lib/yt/models/rating.rb +37 -0
- data/lib/yt/models/reference.rb +172 -0
- data/lib/yt/models/resource.rb +136 -0
- data/lib/yt/models/resumable_session.rb +52 -0
- data/lib/yt/models/right_owner.rb +58 -0
- data/lib/yt/models/snippet.rb +50 -0
- data/lib/yt/models/statistics_set.rb +26 -0
- data/lib/yt/models/status.rb +32 -0
- data/lib/yt/models/subscription.rb +38 -0
- data/lib/yt/models/timestamp.rb +13 -0
- data/lib/yt/models/url.rb +90 -0
- data/lib/yt/models/user_info.rb +26 -0
- data/lib/yt/models/video.rb +630 -0
- data/lib/yt/models/video_category.rb +12 -0
- data/lib/yt/request.rb +278 -0
- data/lib/yt/version.rb +3 -0
- data/spec/collections/claims_spec.rb +30 -0
- data/spec/collections/playlist_items_spec.rb +44 -0
- data/spec/collections/playlists_spec.rb +27 -0
- data/spec/collections/policies_spec.rb +30 -0
- data/spec/collections/references_spec.rb +30 -0
- data/spec/collections/reports_spec.rb +30 -0
- data/spec/collections/subscriptions_spec.rb +25 -0
- data/spec/collections/videos_spec.rb +43 -0
- data/spec/errors/forbidden_spec.rb +10 -0
- data/spec/errors/missing_auth_spec.rb +24 -0
- data/spec/errors/no_items_spec.rb +10 -0
- data/spec/errors/request_error_spec.rb +44 -0
- data/spec/errors/server_error_spec.rb +10 -0
- data/spec/errors/unauthorized_spec.rb +10 -0
- data/spec/models/account_spec.rb +138 -0
- data/spec/models/annotation_spec.rb +180 -0
- data/spec/models/asset_spec.rb +20 -0
- data/spec/models/channel_spec.rb +127 -0
- data/spec/models/claim_event_spec.rb +62 -0
- data/spec/models/claim_history_spec.rb +27 -0
- data/spec/models/claim_spec.rb +211 -0
- data/spec/models/configuration_spec.rb +44 -0
- data/spec/models/content_detail_spec.rb +45 -0
- data/spec/models/content_owner_detail_spec.rb +6 -0
- data/spec/models/description_spec.rb +94 -0
- data/spec/models/file_detail_spec.rb +13 -0
- data/spec/models/live_streaming_detail_spec.rb +6 -0
- data/spec/models/ownership_spec.rb +59 -0
- data/spec/models/player_spec.rb +13 -0
- data/spec/models/playlist_item_spec.rb +120 -0
- data/spec/models/playlist_spec.rb +138 -0
- data/spec/models/policy_rule_spec.rb +63 -0
- data/spec/models/policy_spec.rb +41 -0
- data/spec/models/rating_spec.rb +12 -0
- data/spec/models/reference_spec.rb +249 -0
- data/spec/models/request_spec.rb +163 -0
- data/spec/models/resource_spec.rb +57 -0
- data/spec/models/right_owner_spec.rb +71 -0
- data/spec/models/snippet_spec.rb +13 -0
- data/spec/models/statistics_set_spec.rb +13 -0
- data/spec/models/status_spec.rb +13 -0
- data/spec/models/subscription_spec.rb +30 -0
- data/spec/models/url_spec.rb +78 -0
- data/spec/models/video_category_spec.rb +21 -0
- data/spec/models/video_spec.rb +669 -0
- data/spec/requests/as_account/account_spec.rb +125 -0
- data/spec/requests/as_account/authentications_spec.rb +139 -0
- data/spec/requests/as_account/channel_spec.rb +259 -0
- data/spec/requests/as_account/channels_spec.rb +18 -0
- data/spec/requests/as_account/playlist_item_spec.rb +56 -0
- data/spec/requests/as_account/playlist_spec.rb +244 -0
- data/spec/requests/as_account/resource_spec.rb +18 -0
- data/spec/requests/as_account/thumbnail.jpg +0 -0
- data/spec/requests/as_account/video.mp4 +0 -0
- data/spec/requests/as_account/video_spec.rb +408 -0
- data/spec/requests/as_content_owner/account_spec.rb +25 -0
- data/spec/requests/as_content_owner/advertising_options_set_spec.rb +15 -0
- data/spec/requests/as_content_owner/asset_spec.rb +20 -0
- data/spec/requests/as_content_owner/channel_spec.rb +1934 -0
- data/spec/requests/as_content_owner/claim_history_spec.rb +20 -0
- data/spec/requests/as_content_owner/content_owner_spec.rb +241 -0
- data/spec/requests/as_content_owner/match_policy_spec.rb +17 -0
- data/spec/requests/as_content_owner/ownership_spec.rb +25 -0
- data/spec/requests/as_content_owner/playlist_spec.rb +782 -0
- data/spec/requests/as_content_owner/video_spec.rb +1239 -0
- data/spec/requests/as_server_app/channel_spec.rb +74 -0
- data/spec/requests/as_server_app/playlist_item_spec.rb +30 -0
- data/spec/requests/as_server_app/playlist_spec.rb +53 -0
- data/spec/requests/as_server_app/video_spec.rb +58 -0
- data/spec/requests/as_server_app/videos_spec.rb +40 -0
- data/spec/requests/unauthenticated/video_spec.rb +22 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/fail_matcher.rb +15 -0
- data/spec/support/global_hooks.rb +48 -0
- data/yt.gemspec +32 -0
- metadata +416 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'yt/collections/base'
|
2
|
+
require 'yt/models/user_info'
|
3
|
+
|
4
|
+
module Yt
|
5
|
+
module Collections
|
6
|
+
# @private
|
7
|
+
class UserInfos < Base
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# @return [Hash] the parameters to submit to YouTube to get the
|
12
|
+
# user info of an account
|
13
|
+
# @see https://developers.google.com/+/api/latest/people/getOpenIdConnect
|
14
|
+
def list_params
|
15
|
+
super.tap do |params|
|
16
|
+
params[:path] = '/oauth2/v2/userinfo'
|
17
|
+
params[:expected_response] = Net::HTTPOK
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# next_page is overloaded here because, differently from the other
|
22
|
+
# endpoints, asking for the user info does not return a paginated result,
|
23
|
+
# so @page_token has to be explcitly set to nil, and the result wrapped
|
24
|
+
# in an Array.
|
25
|
+
def next_page
|
26
|
+
request = Yt::Request.new(list_params).tap do |request|
|
27
|
+
print "#{request.as_curl}\n" if Yt.configuration.developing?
|
28
|
+
end
|
29
|
+
response = request.run
|
30
|
+
@page_token = nil
|
31
|
+
|
32
|
+
Array.wrap response.body
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'yt/collections/base'
|
2
|
+
require 'yt/models/video_category'
|
3
|
+
|
4
|
+
module Yt
|
5
|
+
module Collections
|
6
|
+
class VideoCategories < Base
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def attributes_for_new_item(data)
|
11
|
+
{}.tap do |attributes|
|
12
|
+
attributes[:id] = data['id']
|
13
|
+
attributes[:snippet] = data['snippet']
|
14
|
+
attributes[:auth] = @auth
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [Hash] the parameters to submit to YouTube to list video categories.
|
19
|
+
# @see https://developers.google.com/youtube/v3/docs/videoCategories/list
|
20
|
+
def list_params
|
21
|
+
super.tap do |params|
|
22
|
+
params[:params] = video_categories_params
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def video_categories_params
|
27
|
+
{}.tap do |params|
|
28
|
+
params[:part] = 'snippet'
|
29
|
+
params[:id] = @parent.category_id if @parent
|
30
|
+
apply_where_params! params
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'yt/collections/base'
|
2
|
+
require 'yt/models/video'
|
3
|
+
|
4
|
+
module Yt
|
5
|
+
module Collections
|
6
|
+
# Provides methods to interact with a collection of YouTube videos.
|
7
|
+
#
|
8
|
+
# Resources with videos are: {Yt::Models::Channel channels} and
|
9
|
+
# {Yt::Models::Account accounts}.
|
10
|
+
class Videos < Base
|
11
|
+
def where(requirements = {})
|
12
|
+
@published_before = nil
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def attributes_for_new_item(data)
|
19
|
+
id = use_list_endpoint? ? data['id'] : data['id']['videoId']
|
20
|
+
snippet = data['snippet'].reverse_merge complete: false if data['snippet']
|
21
|
+
{}.tap do |attributes|
|
22
|
+
attributes[:id] = id
|
23
|
+
attributes[:snippet] = snippet
|
24
|
+
attributes[:status] = data['status']
|
25
|
+
attributes[:content_details] = data['contentDetails']
|
26
|
+
attributes[:statistics] = data['statistics']
|
27
|
+
attributes[:video_category] = data['videoCategory']
|
28
|
+
attributes[:auth] = @auth
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def eager_load_items_from(items)
|
33
|
+
if included_relationships.any?
|
34
|
+
include_category = included_relationships.delete(:category)
|
35
|
+
included_relationships.append(:snippet).uniq! if include_category
|
36
|
+
|
37
|
+
ids = items.map{|item| item['id']['videoId']}
|
38
|
+
parts = included_relationships.map{|r| r.to_s.camelize(:lower)}
|
39
|
+
conditions = {id: ids.join(','), part: parts.join(',')}
|
40
|
+
videos = Collections::Videos.new(auth: @auth).where conditions
|
41
|
+
|
42
|
+
items.each do |item|
|
43
|
+
video = videos.find{|v| v.id == item['id']['videoId']}
|
44
|
+
parts.each do |part|
|
45
|
+
item[part] = case part
|
46
|
+
when 'snippet' then video.snippet.data.merge complete: true
|
47
|
+
when 'status' then video.status.data
|
48
|
+
when 'statistics' then video.statistics_set.data
|
49
|
+
when 'contentDetails' then video.content_detail.data
|
50
|
+
end
|
51
|
+
end if video
|
52
|
+
end
|
53
|
+
|
54
|
+
if include_category
|
55
|
+
category_ids = items.map{|item| item['snippet']['categoryId']}.uniq
|
56
|
+
conditions = {id: category_ids.join(',')}
|
57
|
+
video_categories = Collections::VideoCategories.new(auth: @auth).where conditions
|
58
|
+
|
59
|
+
items.each do |item|
|
60
|
+
video_category = video_categories.find{|v| v.id == item['snippet']['categoryId']}
|
61
|
+
item['videoCategory'] = video_category.data
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Hash] the parameters to submit to YouTube to list videos.
|
69
|
+
# @see https://developers.google.com/youtube/v3/docs/search/list
|
70
|
+
def list_params
|
71
|
+
super.tap do |params|
|
72
|
+
params[:params] = videos_params
|
73
|
+
params[:path] = videos_path
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def next_page
|
78
|
+
super.tap do |items|
|
79
|
+
halt_list if use_list_endpoint? && items.empty? && @page_token.nil?
|
80
|
+
add_offset_to(items) if !use_list_endpoint? && @page_token.nil? && videos_params[:order] == 'date'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# According to http://stackoverflow.com/a/23256768 YouTube does not
|
85
|
+
# provide more than 500 results for any query. In order to overcome
|
86
|
+
# that limit, the query is restarted with a publishedBefore filter in
|
87
|
+
# case there are more videos to be listed for a channel
|
88
|
+
def add_offset_to(items)
|
89
|
+
if items.count == videos_params[:max_results]
|
90
|
+
last_published = items.last['snippet']['publishedAt']
|
91
|
+
@page_token, @published_before = '', last_published
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# If we ask for a list of videos matching specific IDs and no video is
|
96
|
+
# returned (e.g. they are all private/deleted), then we don’t want to
|
97
|
+
# switch from /videos to /search and keep on looking for videos, but
|
98
|
+
# simply return an empty array of items
|
99
|
+
def halt_list
|
100
|
+
@halt_list = true
|
101
|
+
end
|
102
|
+
|
103
|
+
def more_pages?
|
104
|
+
(@last_index.zero? && !@halt_list) || !@page_token.nil?
|
105
|
+
end
|
106
|
+
|
107
|
+
def videos_params
|
108
|
+
{}.tap do |params|
|
109
|
+
params[:type] = :video
|
110
|
+
params[:max_results] = 50
|
111
|
+
params[:part] = 'snippet'
|
112
|
+
params[:order] = 'date'
|
113
|
+
params.merge! @parent.videos_params if @parent
|
114
|
+
apply_where_params! params
|
115
|
+
params[:published_before] = @published_before if @published_before
|
116
|
+
params
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def videos_path
|
121
|
+
use_list_endpoint? ? '/youtube/v3/videos' : '/youtube/v3/search'
|
122
|
+
end
|
123
|
+
|
124
|
+
# @private
|
125
|
+
# YouTube API provides two different endpoints to get a list of videos:
|
126
|
+
# /videos should be used when the query specifies video IDs or a chart,
|
127
|
+
# /search otherwise.
|
128
|
+
# @return [Boolean] whether to use the /videos endpoint.
|
129
|
+
# @todo: This is one of three places outside of base.rb where @where_params
|
130
|
+
# is accessed; it should be replaced with a filter on params instead.
|
131
|
+
def use_list_endpoint?
|
132
|
+
@where_params ||= {}
|
133
|
+
@parent.nil? && (@where_params.keys & [:id, :chart]).any?
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/yt/config.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'yt/models/configuration'
|
2
|
+
|
3
|
+
module Yt
|
4
|
+
# Provides methods to read and write global configuration settings.
|
5
|
+
#
|
6
|
+
# A typical usage is to set the API keys retrieved from the
|
7
|
+
# {http://console.developers.google.com Google Developers Console}.
|
8
|
+
#
|
9
|
+
# @example Set the API key for a server-only YouTube app:
|
10
|
+
# Yt.configure do |config|
|
11
|
+
# config.api_key = 'ABCDEFGHIJ1234567890'
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# @example Set the API client id/secret for a web-client YouTube app:
|
15
|
+
# Yt.configure do |config|
|
16
|
+
# config.client_id = 'ABCDEFGHIJ1234567890'
|
17
|
+
# config.client_secret = 'ABCDEFGHIJ1234567890'
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Note that Yt.configure has precedence over values through with
|
21
|
+
# environment variables (see {Yt::Models::Configuration}).
|
22
|
+
#
|
23
|
+
module Config
|
24
|
+
# Yields the global configuration to the given block.
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# Yt.configure do |config|
|
28
|
+
# config.api_key = 'ABCDEFGHIJ1234567890'
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# @yield [Yt::Models::Configuration] The global configuration.
|
32
|
+
def configure
|
33
|
+
yield configuration if block_given?
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the global {Yt::Models::Configuration} object.
|
37
|
+
#
|
38
|
+
# While this method _can_ be used to read and write configuration settings,
|
39
|
+
# it is easier to use {Yt::Config#configure} Yt.configure}.
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# Yt.configuration.api_key = 'ABCDEFGHIJ1234567890'
|
43
|
+
#
|
44
|
+
# @return [Yt::Models::Configuration] The global configuration.
|
45
|
+
def configuration
|
46
|
+
@configuration ||= Yt::Configuration.new
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @note Config is the only module auto-loaded in the Yt module,
|
51
|
+
# in order to have a syntax as easy as Yt.configure
|
52
|
+
|
53
|
+
extend Config
|
54
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'yt/errors/request_error'
|
2
|
+
|
3
|
+
module Yt
|
4
|
+
module Errors
|
5
|
+
class MissingAuth < RequestError
|
6
|
+
def message
|
7
|
+
<<-MSG.gsub(/^ {8}/, '')
|
8
|
+
A request to YouTube API was sent without a valid authentication.
|
9
|
+
|
10
|
+
#{more_details}
|
11
|
+
MSG
|
12
|
+
end
|
13
|
+
|
14
|
+
def more_details
|
15
|
+
if scopes && authentication_url && redirect_uri
|
16
|
+
more_details_with_authentication_url
|
17
|
+
elsif scopes && user_code && verification_url
|
18
|
+
more_details_with_verification_url
|
19
|
+
else
|
20
|
+
more_details_without_url
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def more_details_with_authentication_url
|
27
|
+
<<-MSG.gsub(/^ {8}/, '')
|
28
|
+
You can ask YouTube accounts to authenticate your app for the scopes
|
29
|
+
#{scopes} by directing them to #{authentication_url}.
|
30
|
+
|
31
|
+
After they provide access to their account, they will be redirected to
|
32
|
+
#{redirect_uri} with a 'code' query parameter that you can read and use
|
33
|
+
to build an authorized account object by running:
|
34
|
+
|
35
|
+
Yt::Account.new authorization_code: code, redirect_uri: "#{redirect_uri}"
|
36
|
+
MSG
|
37
|
+
end
|
38
|
+
|
39
|
+
def more_details_with_verification_url
|
40
|
+
<<-MSG.gsub(/^ {8}/, '')
|
41
|
+
Please authenticate your app by visiting the page #{verification_url}
|
42
|
+
and entering the code #{user_code} before continuing.
|
43
|
+
MSG
|
44
|
+
end
|
45
|
+
|
46
|
+
def more_details_without_url
|
47
|
+
<<-MSG.gsub(/^ {8}/, '')
|
48
|
+
If you know the access token of the YouTube you want to authenticate
|
49
|
+
with, build an authorized account object by running:
|
50
|
+
|
51
|
+
Yt::Account.new access_token: access_token
|
52
|
+
|
53
|
+
If you know the refresh token of the YouTube you want to authenticate
|
54
|
+
with, build an authorized account object by running:
|
55
|
+
|
56
|
+
Yt::Account.new refresh_token: refresh_token
|
57
|
+
MSG
|
58
|
+
end
|
59
|
+
|
60
|
+
def scopes
|
61
|
+
@msg[:scopes]
|
62
|
+
end
|
63
|
+
|
64
|
+
def authentication_url
|
65
|
+
@msg[:authentication_url]
|
66
|
+
end
|
67
|
+
|
68
|
+
def redirect_uri
|
69
|
+
@msg[:redirect_uri]
|
70
|
+
end
|
71
|
+
|
72
|
+
def user_code
|
73
|
+
@msg[:user_code]
|
74
|
+
end
|
75
|
+
|
76
|
+
def verification_url
|
77
|
+
@msg[:verification_url]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'yt/config'
|
2
|
+
|
3
|
+
module Yt
|
4
|
+
module Errors
|
5
|
+
class RequestError < StandardError
|
6
|
+
def initialize(msg = {})
|
7
|
+
@msg = msg
|
8
|
+
super msg
|
9
|
+
end
|
10
|
+
|
11
|
+
def message
|
12
|
+
<<-MSG.gsub(/^ {8}/, '')
|
13
|
+
#{explanation}:
|
14
|
+
#{Yt.configuration.debugging? ? details : no_details }
|
15
|
+
MSG
|
16
|
+
end
|
17
|
+
|
18
|
+
def kind
|
19
|
+
response_body.fetch 'error', {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def reasons
|
23
|
+
case kind
|
24
|
+
when Hash then kind.fetch('errors', []).map{|e| e['reason']}
|
25
|
+
else kind
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def explanation
|
32
|
+
'A request to YouTube API failed'
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def details
|
37
|
+
<<-MSG.gsub(/^ {8}/, '')
|
38
|
+
#{response_body}
|
39
|
+
|
40
|
+
You can retry the same request manually by running:
|
41
|
+
#{request_curl}
|
42
|
+
#{more_details}
|
43
|
+
MSG
|
44
|
+
end
|
45
|
+
|
46
|
+
def no_details
|
47
|
+
<<-MSG.gsub(/^ {8}/, '')
|
48
|
+
To display more verbose errors, change the configuration of Yt with:
|
49
|
+
|
50
|
+
Yt.configure do |config|
|
51
|
+
config.log_level = :debug
|
52
|
+
end
|
53
|
+
MSG
|
54
|
+
end
|
55
|
+
|
56
|
+
def more_details
|
57
|
+
end
|
58
|
+
|
59
|
+
def response_body
|
60
|
+
json['response_body'].is_a?(Hash) ? json['response_body'] : {}
|
61
|
+
end
|
62
|
+
|
63
|
+
def request_curl
|
64
|
+
json['request_curl']
|
65
|
+
end
|
66
|
+
|
67
|
+
def json
|
68
|
+
@json ||= JSON(@msg) rescue {}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Error = Errors::RequestError
|
74
|
+
end
|