yt 0.34.0 → 0.34.1
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 +11 -0
- data/MIT-LICENSE +2 -2
- data/lib/yt/actions/get.rb +3 -3
- data/lib/yt/actions/insert.rb +1 -1
- data/lib/yt/actions/list.rb +1 -1
- data/lib/yt/associations/has_authentication.rb +1 -1
- data/lib/yt/collections/branding_settings.rb +30 -0
- data/lib/yt/collections/channel_sections.rb +45 -0
- data/lib/yt/collections/live_cuepoints.rb +37 -0
- data/lib/yt/collections/reports.rb +14 -6
- data/lib/yt/models/account.rb +5 -0
- data/lib/yt/models/branding_setting.rb +29 -0
- data/lib/yt/models/caption.rb +33 -0
- data/lib/yt/models/channel.rb +29 -0
- data/lib/yt/models/channel_section.rb +25 -0
- data/lib/yt/models/content_owner.rb +4 -0
- data/lib/yt/models/group_info.rb +1 -1
- data/lib/yt/models/live_cuepoint.rb +23 -0
- data/lib/yt/models/playlist.rb +4 -1
- data/lib/yt/models/reference.rb +1 -1
- data/lib/yt/models/resource.rb +45 -22
- data/lib/yt/models/resumable_session.rb +1 -2
- data/lib/yt/models/user_info.rb +1 -0
- data/lib/yt/models/video.rb +5 -1
- data/lib/yt/models/video_group.rb +3 -0
- data/lib/yt/request.rb +5 -0
- data/lib/yt/version.rb +1 -1
- metadata +13 -61
- data/.gitignore +0 -27
- data/.rspec +0 -3
- data/.travis.yml +0 -7
- data/Gemfile +0 -4
- data/Rakefile +0 -11
- data/bin/console +0 -15
- data/bin/yt +0 -23
- data/gemfiles/Gemfile.activesupport-3.x +0 -4
- data/gemfiles/Gemfile.activesupport-4.x +0 -4
- data/yt.gemspec +0 -36
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d762b0553bfa8bd58e917e9ff11a1f38958c3b072fe35f0a1e77f19aa48926d0
|
|
4
|
+
data.tar.gz: 2b50a350f9d9c13f067fde5f35e7dfaf0aee824bdf98f1399690c6eddd74a730
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 839ac9877b734b3254fd2224091e88d82797621183c5a6b1893d70181fe5fe0391b8ca3a5829b7074a8b694198221968ba2d1151a1d47cc8d7dd67f4fed26943
|
|
7
|
+
data.tar.gz: cec4e6c32178f4de39919271f3875012c9ea56233236029135bc4ea7b1113859871319e90491963e27047cb0f0916e999fdd9d02675fd1c3aa3d93f7917a24d9
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,17 @@ 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.34.1 - 2026-01-08
|
|
10
|
+
|
|
11
|
+
* [FEATURE] Add channel.channel_sections
|
|
12
|
+
* [FEATURE] Add branding_setting.unsubscribed_trailer
|
|
13
|
+
* [FEATURE] Add engaged_views
|
|
14
|
+
* [FEATURE] Add account.sub (thank you @jkowens)
|
|
15
|
+
* [FEATURE] Add content_owner.live_cuepoints
|
|
16
|
+
* [FIX] Fetch channel_id from channel handle url
|
|
17
|
+
* [BUGFIX] upload_thumbnail and upload_video with path url (thank you @mrj)
|
|
18
|
+
* [IMPROVEMENT] Use `URI.decode_www_form` for Ruby 4.0 (thank you @jules-w2)
|
|
19
|
+
|
|
9
20
|
## 0.34.0 - 2024-08-25
|
|
10
21
|
|
|
11
22
|
* Ruby 2.1+ required https://github.com/nullscreen/yt/pull/425
|
data/MIT-LICENSE
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c) 2014–present
|
|
1
|
+
Copyright (c) 2014–present Nullscreen
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
4
|
a copy of this software and associated documentation files (the
|
|
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
17
17
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/yt/actions/get.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Yt
|
|
|
14
14
|
private
|
|
15
15
|
|
|
16
16
|
def get_request(params = {})
|
|
17
|
-
@
|
|
17
|
+
@get_request = Yt::Request.new(params).tap do |request|
|
|
18
18
|
print "#{request.as_curl}\n" if Yt.configuration.developing?
|
|
19
19
|
end
|
|
20
20
|
end
|
|
@@ -24,10 +24,10 @@ module Yt
|
|
|
24
24
|
params[:method] = :get
|
|
25
25
|
params[:host] = 'www.googleapis.com'
|
|
26
26
|
params[:auth] = @auth
|
|
27
|
-
params[:
|
|
27
|
+
params[:expected_response] = Net::HTTPOK
|
|
28
28
|
params[:api_key] = Yt.configuration.api_key if Yt.configuration.api_key
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
|
-
end
|
|
33
|
+
end
|
data/lib/yt/actions/insert.rb
CHANGED
data/lib/yt/actions/list.rb
CHANGED
|
@@ -117,7 +117,7 @@ module Yt
|
|
|
117
117
|
params[:host] = 'www.googleapis.com'
|
|
118
118
|
params[:auth] = @auth
|
|
119
119
|
params[:path] = path
|
|
120
|
-
params[:
|
|
120
|
+
params[:expected_response] = Net::HTTPOK
|
|
121
121
|
params[:api_key] = Yt.configuration.api_key if Yt.configuration.api_key
|
|
122
122
|
end
|
|
123
123
|
end
|
|
@@ -189,7 +189,7 @@ module Yt
|
|
|
189
189
|
params[:redirect_uri] = @redirect_uri
|
|
190
190
|
params[:response_type] = :code
|
|
191
191
|
params[:access_type] = :offline
|
|
192
|
-
params[:
|
|
192
|
+
params[:prompt] = :consent if @force
|
|
193
193
|
# params[:include_granted_scopes] = true
|
|
194
194
|
params[:state] = @state if @state
|
|
195
195
|
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'yt/collections/base'
|
|
2
|
+
require 'yt/models/branding_setting'
|
|
3
|
+
|
|
4
|
+
module Yt
|
|
5
|
+
module Collections
|
|
6
|
+
# @private
|
|
7
|
+
class BrandingSettings < Base
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def attributes_for_new_item(data)
|
|
12
|
+
{ data: data['brandingSettings'] }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [Hash] the parameters to submit to YouTube to get the
|
|
16
|
+
# branding_settings of a resource, for instance a channel.
|
|
17
|
+
# @see https://developers.google.com/youtube/v3/docs/channels#resource
|
|
18
|
+
def list_params
|
|
19
|
+
super.tap do |params|
|
|
20
|
+
params[:path] = "/youtube/v3/#{@parent.kind.pluralize}"
|
|
21
|
+
params[:params] = branding_settings_params
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def branding_settings_params
|
|
26
|
+
{ max_results: 50, part: 'brandingSettings', id: @parent.id }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'yt/collections/base'
|
|
2
|
+
require 'yt/models/channel_section'
|
|
3
|
+
|
|
4
|
+
module Yt
|
|
5
|
+
module Collections
|
|
6
|
+
# Provides methods for a collection of YouTube channel sections.
|
|
7
|
+
#
|
|
8
|
+
# Resources with channel_sections is {Yt::Models::Channel channels}.
|
|
9
|
+
class ChannelSections < Base
|
|
10
|
+
|
|
11
|
+
def attributes_for_new_item(data)
|
|
12
|
+
{}.tap do |attributes|
|
|
13
|
+
attributes[:id] = data['id']
|
|
14
|
+
attributes[:snippet] = data['snippet']
|
|
15
|
+
attributes[:content_details] = data['contentDetails']
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [Hash] the parameters to submit to YouTube to list channel sections.
|
|
20
|
+
# @see https://developers.google.com/youtube/v3/docs/channelSections/list
|
|
21
|
+
def list_params
|
|
22
|
+
super.tap do |params|
|
|
23
|
+
params[:params] = channel_sections_params
|
|
24
|
+
params[:path] = '/youtube/v3/channelSections'
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def channel_sections_params
|
|
29
|
+
{}.tap do |params|
|
|
30
|
+
params[:part] = 'snippet'
|
|
31
|
+
params.merge! @parent.channel_sections_params if @parent
|
|
32
|
+
# TODO: when to mine, when to on_behalf_of_content_owner
|
|
33
|
+
# if @parent.auth
|
|
34
|
+
# if @parent.auth.owner_name
|
|
35
|
+
# params[:on_behalf_of_content_owner] = @parent.auth.owner_name
|
|
36
|
+
# else
|
|
37
|
+
# params[:mine] = true
|
|
38
|
+
# end
|
|
39
|
+
# end
|
|
40
|
+
params
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'yt/collections/base'
|
|
2
|
+
require 'yt/models/live_cuepoint'
|
|
3
|
+
|
|
4
|
+
module Yt
|
|
5
|
+
module Collections
|
|
6
|
+
# Provides methods to insert live cuepoints.
|
|
7
|
+
#
|
|
8
|
+
# Resources with live_cuepoints are: {Yt::Models::ContentOwner content owners}.
|
|
9
|
+
class LiveCuepoints < Base
|
|
10
|
+
def insert(attributes = {})
|
|
11
|
+
underscore_keys! attributes
|
|
12
|
+
body = attributes.slice(*body_params)
|
|
13
|
+
params = {on_behalf_of_content_owner: @auth.owner_name}
|
|
14
|
+
apply_where_params! params
|
|
15
|
+
do_insert(params: params, body: body)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def body_params
|
|
21
|
+
[:id, :cue_type, :insertion_offset_time_ms, :walltime_ms, :duration_secs]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @return [Hash] the parameters to submit to YouTube to add a live cuepoint.
|
|
25
|
+
# @see https://developers.google.com/youtube/v3/live/docs/liveBroadcasts/cuepoint
|
|
26
|
+
def insert_params
|
|
27
|
+
super.tap do |params|
|
|
28
|
+
params[:path] = '/youtube/v3/liveBroadcasts/cuepoint'
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def attributes_for_new_item(data)
|
|
33
|
+
{data: data, auth: @auth, id: data['id']}
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -47,19 +47,28 @@ module Yt
|
|
|
47
47
|
playlist_page: 'YT_PLAYLIST_PAGE',
|
|
48
48
|
campaign_card: 'CAMPAIGN_CARD',
|
|
49
49
|
end_screen: 'END_SCREEN',
|
|
50
|
-
info_card: 'INFO_CARD'
|
|
50
|
+
info_card: 'INFO_CARD',
|
|
51
|
+
hashtags: 'HASHTAGS',
|
|
52
|
+
live_redirect: 'LIVE_REDIRECT',
|
|
53
|
+
product_page: 'PRODUCT_PAGE',
|
|
54
|
+
shorts: 'SHORTS',
|
|
55
|
+
sound_page: 'SOUND_PAGE',
|
|
56
|
+
video_remixes: 'VIDEO_REMIXES',
|
|
57
|
+
immersive_live: 'IMMERSIVE_LIVE',
|
|
58
|
+
shorts_content_links: 'SHORTS_CONTENT_LINKS'
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
# @see https://developers.google.com/youtube/analytics/
|
|
61
|
+
# @see https://developers.google.com/youtube/analytics/dimensions#Playback_Location_Dimensions
|
|
54
62
|
PLAYBACK_LOCATIONS = {
|
|
55
63
|
channel: 'CHANNEL',
|
|
56
64
|
watch: 'WATCH',
|
|
57
65
|
embedded: 'EMBEDDED',
|
|
58
66
|
other: 'YT_OTHER',
|
|
59
67
|
external_app: 'EXTERNAL_APP',
|
|
60
|
-
search: 'SEARCH',
|
|
61
|
-
browse: 'BROWSE',
|
|
62
|
-
mobile: 'MOBILE' # only present for data < September 10, 2013
|
|
68
|
+
search: 'SEARCH',
|
|
69
|
+
browse: 'BROWSE',
|
|
70
|
+
mobile: 'MOBILE', # only present for data < September 10, 2013
|
|
71
|
+
shorts_feed: 'SHORTS_FEED' # undocumented but returned by the API
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
# @see https://developers.google.com/youtube/analytics/v1/dimsmets/dims#Playback_Detail_Dimensions
|
|
@@ -203,7 +212,6 @@ module Yt
|
|
|
203
212
|
params[:filters] = ((params[:filters] || '').split(';') + ["country==US"]).compact.uniq.join(';') if @dimension == :state && !@state
|
|
204
213
|
params[:filters] = ((params[:filters] || '').split(';') + ["country==#{@country}"]).compact.uniq.join(';') if @country && !@state
|
|
205
214
|
params[:filters] = ((params[:filters] || '').split(';') + ["province==US-#{@state}"]).compact.uniq.join(';') if @state
|
|
206
|
-
params[:filters] = ((params[:filters] || '').split(';') + ['isCurated==1']).compact.uniq.join(';') if @dimension == :playlist
|
|
207
215
|
params[:filters] = ((params[:filters] || '').split(';') + ['insightPlaybackLocationType==EMBEDDED']).compact.uniq.join(';') if @dimension == :embedded_player_location
|
|
208
216
|
params[:filters] = ((params[:filters] || '').split(';') + ['insightTrafficSourceType==RELATED_VIDEO']).compact.uniq.join(';') if @dimension == :related_video
|
|
209
217
|
params[:filters] = ((params[:filters] || '').split(';') + ['insightTrafficSourceType==YT_SEARCH']).compact.uniq.join(';') if @dimension == :search_term
|
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
|
|
@@ -14,6 +15,10 @@ module Yt
|
|
|
14
15
|
# @return [String] the (Google+) account’s ID.
|
|
15
16
|
delegate :id, to: :user_info
|
|
16
17
|
|
|
18
|
+
# @!attribute [r] sub
|
|
19
|
+
# @return [String] the (Google) account’s unique ID.
|
|
20
|
+
delegate :sub, to: :user_info
|
|
21
|
+
|
|
17
22
|
# @!attribute [r] email
|
|
18
23
|
# @return [String] the account’s email address.
|
|
19
24
|
delegate :email, to: :user_info
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'yt/models/base'
|
|
2
|
+
|
|
3
|
+
module Yt
|
|
4
|
+
module Models
|
|
5
|
+
# @private
|
|
6
|
+
# Encapsulates branding settings about the resource, such as trailer on channel
|
|
7
|
+
# @see https://developers.google.com/youtube/v3/docs/channels#resource-representation
|
|
8
|
+
class BrandingSetting < Base
|
|
9
|
+
attr_reader :data
|
|
10
|
+
|
|
11
|
+
def initialize(options = {})
|
|
12
|
+
@data = options[:data]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
has_attribute :channel, default: {}
|
|
16
|
+
|
|
17
|
+
def unsubscribed_trailer
|
|
18
|
+
channel['unsubscribedTrailer']
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
has_attribute :image, default: {}
|
|
22
|
+
|
|
23
|
+
def banner_external_url
|
|
24
|
+
image['bannerExternalUrl']
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
data/lib/yt/models/caption.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'yt/models/resource'
|
|
2
|
+
require "fileutils"
|
|
2
3
|
|
|
3
4
|
module Yt
|
|
4
5
|
module Models
|
|
@@ -14,6 +15,38 @@ module Yt
|
|
|
14
15
|
delegate :language, to: :snippet
|
|
15
16
|
delegate :name, to: :snippet
|
|
16
17
|
delegate :status, to: :snippet
|
|
18
|
+
|
|
19
|
+
# Downloads a caption file.
|
|
20
|
+
# @param [String] path A name for the downloaded file with caption content.
|
|
21
|
+
# @see https://developers.google.com/youtube/v3/docs/captions#resource
|
|
22
|
+
def download(path)
|
|
23
|
+
case io
|
|
24
|
+
when StringIO then File.open(path, 'w') { |f| f.write(io.read) }
|
|
25
|
+
when Tempfile then io.close; FileUtils.mv(io.path, path)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def io
|
|
30
|
+
@io ||= get_request(download_params).open_uri
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
# @return [Hash] the parameters to submit to YouTube to download caption.
|
|
36
|
+
# @see https://developers.google.com/youtube/v3/docs/captions/download
|
|
37
|
+
def download_params
|
|
38
|
+
{}.tap do |params|
|
|
39
|
+
params[:method] = :get
|
|
40
|
+
params[:host] = 'youtube.googleapis.com'
|
|
41
|
+
params[:auth] = @auth
|
|
42
|
+
params[:exptected_response] = Net::HTTPOK
|
|
43
|
+
params[:api_key] = Yt.configuration.api_key if Yt.configuration.api_key
|
|
44
|
+
params[:path] = "/youtube/v3/captions/#{@id}"
|
|
45
|
+
if @auth.owner_name
|
|
46
|
+
params[:params] = {on_behalf_of_content_owner: @auth.owner_name}
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
17
50
|
end
|
|
18
51
|
end
|
|
19
52
|
end
|
data/lib/yt/models/channel.rb
CHANGED
|
@@ -126,6 +126,10 @@ module Yt
|
|
|
126
126
|
# explicitly select the option to keep all subscriptions private.
|
|
127
127
|
has_many :subscribed_channels
|
|
128
128
|
|
|
129
|
+
# @!attribute [r] channel_sections
|
|
130
|
+
# @return [Yt::Collections::ChannelSections] the channel’s channel sections.
|
|
131
|
+
has_many :channel_sections
|
|
132
|
+
|
|
129
133
|
### ANALYTICS ###
|
|
130
134
|
|
|
131
135
|
# @macro reports
|
|
@@ -133,6 +137,9 @@ module Yt
|
|
|
133
137
|
# @macro report_by_channel_dimensions
|
|
134
138
|
has_report :views, Integer
|
|
135
139
|
|
|
140
|
+
# @macro report_by_channel_dimensions
|
|
141
|
+
has_report :engaged_views, Integer
|
|
142
|
+
|
|
136
143
|
# @macro report_by_channel_dimensions
|
|
137
144
|
has_report :estimated_minutes_watched, Integer
|
|
138
145
|
|
|
@@ -229,6 +236,18 @@ module Yt
|
|
|
229
236
|
statistics_set.hidden_subscriber_count == false
|
|
230
237
|
end
|
|
231
238
|
|
|
239
|
+
### BRANDING SETTINGS ###
|
|
240
|
+
|
|
241
|
+
has_one :branding_setting
|
|
242
|
+
|
|
243
|
+
# @!attribute [r] unsubscribed_trailer
|
|
244
|
+
# @return [String] the channel’s trailer video id.
|
|
245
|
+
delegate :unsubscribed_trailer, to: :branding_setting
|
|
246
|
+
|
|
247
|
+
# @!attribute [r] banner_external_url
|
|
248
|
+
# @return [String] the channel’s banner image URL.
|
|
249
|
+
delegate :banner_external_url, to: :branding_setting
|
|
250
|
+
|
|
232
251
|
### CONTENT OWNER DETAILS ###
|
|
233
252
|
|
|
234
253
|
has_one :content_owner_detail
|
|
@@ -286,6 +305,16 @@ module Yt
|
|
|
286
305
|
if options[:content_owner_details]
|
|
287
306
|
@content_owner_detail = ContentOwnerDetail.new data: options[:content_owner_details]
|
|
288
307
|
end
|
|
308
|
+
if options[:branding_settings]
|
|
309
|
+
@branding_setting = BrandingSetting.new data: options[:branding_settings]
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# @private
|
|
314
|
+
# Used for `has_many :channel_sections` to return all youtube#channelSection items
|
|
315
|
+
# of the channel.
|
|
316
|
+
def channel_sections_params
|
|
317
|
+
{channel_id: id}
|
|
289
318
|
end
|
|
290
319
|
|
|
291
320
|
# @private
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'yt/models/base'
|
|
2
|
+
|
|
3
|
+
module Yt
|
|
4
|
+
module Models
|
|
5
|
+
class ChannelSection < Base
|
|
6
|
+
attr_reader :data
|
|
7
|
+
|
|
8
|
+
# @private
|
|
9
|
+
def initialize(options = {})
|
|
10
|
+
@id = options[:id]
|
|
11
|
+
@data = options[:snippet]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
has_attribute :type
|
|
15
|
+
has_attribute :channel_id
|
|
16
|
+
has_attribute :position, type: Integer
|
|
17
|
+
|
|
18
|
+
### ID ###
|
|
19
|
+
|
|
20
|
+
# @!attribute [r] id
|
|
21
|
+
# @return [String] the ID that YouTube uses to identify each resource.
|
|
22
|
+
attr_reader :id
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -11,6 +11,10 @@ module Yt
|
|
|
11
11
|
# @return [Yt::Collections::PartneredChannels] the channels managed by the CMS account.
|
|
12
12
|
has_many :partnered_channels
|
|
13
13
|
|
|
14
|
+
# @!attribute [r] live_cuepoints
|
|
15
|
+
# @return [Yt::Collections::LiveCuepoints] the live_cuepoints inserted by the content owner.
|
|
16
|
+
has_many :live_cuepoints
|
|
17
|
+
|
|
14
18
|
# @!attribute [r] claims
|
|
15
19
|
# @return [Yt::Collections::Claims] the claims administered by the content owner.
|
|
16
20
|
has_many :claims
|
data/lib/yt/models/group_info.rb
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'yt/models/base'
|
|
2
|
+
|
|
3
|
+
module Yt
|
|
4
|
+
module Models
|
|
5
|
+
# Provides methods to interact with YouTube Content ID live cuepoints.
|
|
6
|
+
# @see https://developers.google.com/youtube/v3/live/docs/liveCuepoints
|
|
7
|
+
class LiveCuepoint < Base
|
|
8
|
+
def initialize(options = {})
|
|
9
|
+
@data = options[:data]
|
|
10
|
+
@id = options[:id]
|
|
11
|
+
@auth = options[:auth]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @return [String] the ID that YouTube assigns and uses to uniquely
|
|
15
|
+
# identify the live_cuepoint.
|
|
16
|
+
has_attribute :id
|
|
17
|
+
|
|
18
|
+
# @return [String] the ID that uniquely identifies the broadcast that the
|
|
19
|
+
# live_cuepoint is associated with.
|
|
20
|
+
has_attribute :broadcast_id
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/yt/models/playlist.rb
CHANGED
|
@@ -160,6 +160,9 @@ module Yt
|
|
|
160
160
|
# @macro report_by_playlist_dimensions
|
|
161
161
|
has_report :views, Integer
|
|
162
162
|
|
|
163
|
+
# @macro report_by_playlist_dimensions
|
|
164
|
+
has_report :engaged_views, Integer
|
|
165
|
+
|
|
163
166
|
# @macro report_by_playlist_dimensions
|
|
164
167
|
has_report :estimated_minutes_watched, Integer
|
|
165
168
|
|
|
@@ -202,7 +205,7 @@ module Yt
|
|
|
202
205
|
else
|
|
203
206
|
params[:ids] = "channel==#{channel_id}"
|
|
204
207
|
end
|
|
205
|
-
params[:filters] = "playlist==#{id}
|
|
208
|
+
params[:filters] = "playlist==#{id}"
|
|
206
209
|
end
|
|
207
210
|
end
|
|
208
211
|
|
data/lib/yt/models/reference.rb
CHANGED
data/lib/yt/models/resource.rb
CHANGED
|
@@ -12,13 +12,7 @@ module Yt
|
|
|
12
12
|
|
|
13
13
|
# @!attribute [r] id
|
|
14
14
|
# @return [String] the ID that YouTube uses to identify each resource.
|
|
15
|
-
|
|
16
|
-
if @id.nil? && @match && @match[:kind] == :channel
|
|
17
|
-
@id ||= fetch_channel_id
|
|
18
|
-
else
|
|
19
|
-
@id
|
|
20
|
-
end
|
|
21
|
-
end
|
|
15
|
+
attr_reader :id
|
|
22
16
|
|
|
23
17
|
### STATUS ###
|
|
24
18
|
|
|
@@ -51,7 +45,11 @@ module Yt
|
|
|
51
45
|
if options[:url]
|
|
52
46
|
@url = options[:url]
|
|
53
47
|
@match = find_pattern_match
|
|
54
|
-
|
|
48
|
+
if kind == "channel" && @match.key?('format')
|
|
49
|
+
@id ||= fetch_channel_id
|
|
50
|
+
else
|
|
51
|
+
@id = @match['id']
|
|
52
|
+
end
|
|
55
53
|
else
|
|
56
54
|
@id = options[:id]
|
|
57
55
|
end
|
|
@@ -98,7 +96,8 @@ module Yt
|
|
|
98
96
|
# @return [Array<Regexp>] patterns matching URLs of YouTube channels.
|
|
99
97
|
CHANNEL_PATTERNS = [
|
|
100
98
|
%r{^(?:https?://)?(?:www\.)?youtube\.com/channel/(?<id>UC[a-zA-Z0-9_-]{22})},
|
|
101
|
-
%r{^(?:https?://)?(?:www\.)?youtube\.com/(?<format>c/|user/)?(?<name>[a-zA-Z0-9_-]+)}
|
|
99
|
+
%r{^(?:https?://)?(?:www\.)?youtube\.com/(?<format>c/|user/)?(?<name>[a-zA-Z0-9_-]+)},
|
|
100
|
+
%r{^(?:https?://)?(?:www\.)?youtube\.com/(?<format>@)(?<name>[a-zA-Z0-9_-]+)}
|
|
102
101
|
]
|
|
103
102
|
|
|
104
103
|
private
|
|
@@ -106,8 +105,7 @@ module Yt
|
|
|
106
105
|
def find_pattern_match
|
|
107
106
|
patterns.find do |kind, regex|
|
|
108
107
|
if data = @url.match(regex)
|
|
109
|
-
|
|
110
|
-
break data.names.zip(data.captures).to_h.merge kind: kind
|
|
108
|
+
break data.named_captures.merge kind: kind
|
|
111
109
|
end
|
|
112
110
|
end || {kind: :unknown}
|
|
113
111
|
end
|
|
@@ -123,19 +121,44 @@ module Yt
|
|
|
123
121
|
end
|
|
124
122
|
|
|
125
123
|
def fetch_channel_id
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
124
|
+
api_key = Yt.configuration.api_key if Yt.configuration.api_key
|
|
125
|
+
case @match['format']
|
|
126
|
+
when "@"
|
|
127
|
+
handle = "@#{@match['name']}"
|
|
128
|
+
response = Net::HTTP.start 'youtube.googleapis.com', 443, use_ssl: true do |http|
|
|
129
|
+
http.request Net::HTTP::Get.new("/youtube/v3/channels?part=snippet&forHandle=#{handle}&key=#{api_key}")
|
|
130
|
+
end
|
|
131
|
+
if response.is_a?(Net::HTTPOK) && item = JSON(response.body)['items']&.first
|
|
132
|
+
item['id']
|
|
133
|
+
else
|
|
134
|
+
raise Yt::Errors::NoItems
|
|
135
|
+
end
|
|
136
|
+
when "user/"
|
|
137
|
+
username = @match['name']
|
|
138
|
+
response = Net::HTTP.start 'youtube.googleapis.com', 443, use_ssl: true do |http|
|
|
139
|
+
http.request Net::HTTP::Get.new("/youtube/v3/channels?part=snippet&forUsername=#{username}&key=#{api_key}")
|
|
140
|
+
end
|
|
141
|
+
if response.is_a?(Net::HTTPOK) && item = JSON(response.body)['items']&.first
|
|
142
|
+
item['id']
|
|
143
|
+
else
|
|
144
|
+
raise Yt::Errors::NoItems
|
|
145
|
+
end
|
|
146
|
+
else # "c/", nil
|
|
130
147
|
response = Net::HTTP.start 'www.youtube.com', 443, use_ssl: true do |http|
|
|
131
|
-
http.request Net::HTTP::Get.new(
|
|
148
|
+
http.request Net::HTTP::Get.new("/#{@match['format']}#{@match['name']}")
|
|
149
|
+
end
|
|
150
|
+
if response.is_a?(Net::HTTPRedirection)
|
|
151
|
+
response = Net::HTTP.start 'www.youtube.com', 443, use_ssl: true do |http|
|
|
152
|
+
http.request Net::HTTP::Get.new(response['location'])
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
# puts response.body
|
|
156
|
+
regex = %r{(?<id>UC[a-zA-Z0-9_-]{22})}
|
|
157
|
+
if data = response.body.match(regex)
|
|
158
|
+
data[:id]
|
|
159
|
+
else
|
|
160
|
+
raise Yt::Errors::NoItems
|
|
132
161
|
end
|
|
133
|
-
end
|
|
134
|
-
regex = %r{<meta itemprop="channelId" content="(?<id>UC[a-zA-Z0-9_-]{22})">}
|
|
135
|
-
if data = response.body.match(regex)
|
|
136
|
-
data[:id]
|
|
137
|
-
else
|
|
138
|
-
raise Yt::Errors::NoItems
|
|
139
162
|
end
|
|
140
163
|
end
|
|
141
164
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require 'cgi'
|
|
2
1
|
require 'yt/models/base'
|
|
3
2
|
|
|
4
3
|
module Yt
|
|
@@ -30,7 +29,7 @@ module Yt
|
|
|
30
29
|
private
|
|
31
30
|
|
|
32
31
|
def session_params
|
|
33
|
-
|
|
32
|
+
URI.decode_www_form(@uri.query || "").to_h
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
# @note: YouTube documentation states that a valid upload returns an HTTP
|
data/lib/yt/models/user_info.rb
CHANGED
data/lib/yt/models/video.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'open-uri'
|
|
1
2
|
require 'yt/models/resource'
|
|
2
3
|
|
|
3
4
|
module Yt
|
|
@@ -421,6 +422,9 @@ module Yt
|
|
|
421
422
|
# @macro report_by_video_dimensions
|
|
422
423
|
has_report :views, Integer
|
|
423
424
|
|
|
425
|
+
# @macro report_by_video_dimensions
|
|
426
|
+
has_report :engaged_views, Integer
|
|
427
|
+
|
|
424
428
|
# @macro report_by_video_dimensions
|
|
425
429
|
has_report :estimated_minutes_watched, Integer
|
|
426
430
|
|
|
@@ -546,7 +550,7 @@ module Yt
|
|
|
546
550
|
# @raise [Yt::Errors::RequestError] if path_or_url is not a valid path
|
|
547
551
|
# or URL.
|
|
548
552
|
def upload_thumbnail(path_or_url)
|
|
549
|
-
file = URI.open(path_or_url)
|
|
553
|
+
file = URI.open(path_or_url)
|
|
550
554
|
session = resumable_sessions.insert file.size
|
|
551
555
|
|
|
552
556
|
session.update(body: file) do |data|
|
data/lib/yt/request.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'net/http' # for Net::HTTP.start
|
|
2
2
|
require 'uri' # for URI.json
|
|
3
3
|
require 'json' # for JSON.parse
|
|
4
|
+
require "open-uri" # for URI.open
|
|
4
5
|
require 'active_support' # does not load anything by default, but is required
|
|
5
6
|
require 'active_support/core_ext' # for Hash.from_xml, Hash.to_param
|
|
6
7
|
|
|
@@ -84,6 +85,10 @@ module Yt
|
|
|
84
85
|
end
|
|
85
86
|
end
|
|
86
87
|
|
|
88
|
+
def open_uri
|
|
89
|
+
URI.open(uri.to_s, 'Authorization' => "Bearer #{@auth.access_token}")
|
|
90
|
+
end
|
|
91
|
+
|
|
87
92
|
# Returns the +cURL+ version of the request, useful to re-run the request
|
|
88
93
|
# in a shell terminal.
|
|
89
94
|
# @return [String] the +cURL+ version of the request.
|
data/lib/yt/version.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.34.
|
|
4
|
+
version: 0.34.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- Nullscreen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -24,20 +24,6 @@ dependencies:
|
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0'
|
|
27
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: bundler
|
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
|
30
|
-
requirements:
|
|
31
|
-
- - ">="
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0'
|
|
34
|
-
type: :development
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - ">="
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0'
|
|
41
27
|
- !ruby/object:Gem::Dependency
|
|
42
28
|
name: rspec
|
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,34 +38,6 @@ dependencies:
|
|
|
52
38
|
- - ">="
|
|
53
39
|
- !ruby/object:Gem::Version
|
|
54
40
|
version: '0'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: rake
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - ">="
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0'
|
|
62
|
-
type: :development
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - ">="
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0'
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: pry
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - ">="
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: '0'
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - ">="
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: '0'
|
|
83
41
|
- !ruby/object:Gem::Dependency
|
|
84
42
|
name: vcr
|
|
85
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -110,27 +68,16 @@ dependencies:
|
|
|
110
68
|
version: '0'
|
|
111
69
|
description: Youtube V3 API client.
|
|
112
70
|
email:
|
|
113
|
-
-
|
|
114
|
-
executables:
|
|
115
|
-
- console
|
|
116
|
-
- yt
|
|
71
|
+
- nullscreen.code@gmail.com
|
|
72
|
+
executables: []
|
|
117
73
|
extensions: []
|
|
118
74
|
extra_rdoc_files: []
|
|
119
75
|
files:
|
|
120
|
-
- ".gitignore"
|
|
121
|
-
- ".rspec"
|
|
122
|
-
- ".travis.yml"
|
|
123
76
|
- ".yardopts"
|
|
124
77
|
- CHANGELOG.md
|
|
125
|
-
- Gemfile
|
|
126
78
|
- MIT-LICENSE
|
|
127
79
|
- README.md
|
|
128
|
-
- Rakefile
|
|
129
80
|
- YOUTUBE_IT.md
|
|
130
|
-
- bin/console
|
|
131
|
-
- bin/yt
|
|
132
|
-
- gemfiles/Gemfile.activesupport-3.x
|
|
133
|
-
- gemfiles/Gemfile.activesupport-4.x
|
|
134
81
|
- lib/yt.rb
|
|
135
82
|
- lib/yt/actions/base.rb
|
|
136
83
|
- lib/yt/actions/delete.rb
|
|
@@ -151,9 +98,11 @@ files:
|
|
|
151
98
|
- lib/yt/collections/assets.rb
|
|
152
99
|
- lib/yt/collections/authentications.rb
|
|
153
100
|
- lib/yt/collections/base.rb
|
|
101
|
+
- lib/yt/collections/branding_settings.rb
|
|
154
102
|
- lib/yt/collections/bulk_report_jobs.rb
|
|
155
103
|
- lib/yt/collections/bulk_reports.rb
|
|
156
104
|
- lib/yt/collections/captions.rb
|
|
105
|
+
- lib/yt/collections/channel_sections.rb
|
|
157
106
|
- lib/yt/collections/channels.rb
|
|
158
107
|
- lib/yt/collections/claim_histories.rb
|
|
159
108
|
- lib/yt/collections/claims.rb
|
|
@@ -165,6 +114,7 @@ files:
|
|
|
165
114
|
- lib/yt/collections/file_details.rb
|
|
166
115
|
- lib/yt/collections/group_infos.rb
|
|
167
116
|
- lib/yt/collections/group_items.rb
|
|
117
|
+
- lib/yt/collections/live_cuepoints.rb
|
|
168
118
|
- lib/yt/collections/live_streaming_details.rb
|
|
169
119
|
- lib/yt/collections/ownerships.rb
|
|
170
120
|
- lib/yt/collections/partnered_channels.rb
|
|
@@ -205,10 +155,12 @@ files:
|
|
|
205
155
|
- lib/yt/models/asset_snippet.rb
|
|
206
156
|
- lib/yt/models/authentication.rb
|
|
207
157
|
- lib/yt/models/base.rb
|
|
158
|
+
- lib/yt/models/branding_setting.rb
|
|
208
159
|
- lib/yt/models/bulk_report.rb
|
|
209
160
|
- lib/yt/models/bulk_report_job.rb
|
|
210
161
|
- lib/yt/models/caption.rb
|
|
211
162
|
- lib/yt/models/channel.rb
|
|
163
|
+
- lib/yt/models/channel_section.rb
|
|
212
164
|
- lib/yt/models/claim.rb
|
|
213
165
|
- lib/yt/models/claim_event.rb
|
|
214
166
|
- lib/yt/models/claim_history.rb
|
|
@@ -223,6 +175,7 @@ files:
|
|
|
223
175
|
- lib/yt/models/group_info.rb
|
|
224
176
|
- lib/yt/models/group_item.rb
|
|
225
177
|
- lib/yt/models/id.rb
|
|
178
|
+
- lib/yt/models/live_cuepoint.rb
|
|
226
179
|
- lib/yt/models/live_streaming_detail.rb
|
|
227
180
|
- lib/yt/models/match_policy.rb
|
|
228
181
|
- lib/yt/models/ownership.rb
|
|
@@ -249,8 +202,7 @@ files:
|
|
|
249
202
|
- lib/yt/models/video_group.rb
|
|
250
203
|
- lib/yt/request.rb
|
|
251
204
|
- lib/yt/version.rb
|
|
252
|
-
|
|
253
|
-
homepage: http://github.com/Fullscreen/yt
|
|
205
|
+
homepage: http://github.com/nullscreen/yt
|
|
254
206
|
licenses:
|
|
255
207
|
- MIT
|
|
256
208
|
metadata: {}
|
|
@@ -269,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
269
221
|
- !ruby/object:Gem::Version
|
|
270
222
|
version: '0'
|
|
271
223
|
requirements: []
|
|
272
|
-
rubygems_version: 3.
|
|
224
|
+
rubygems_version: 3.4.20
|
|
273
225
|
signing_key:
|
|
274
226
|
specification_version: 4
|
|
275
227
|
summary: Yt makes it easy to interact with Youtube V3 API by providing a modular,
|
data/.gitignore
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
|
2
|
-
#
|
|
3
|
-
# If you find yourself ignoring temporary files generated by your text editor
|
|
4
|
-
# or operating system, you probably want to add a global ignore instead:
|
|
5
|
-
# git config --global core.excludesfile '~/.gitignore_global'
|
|
6
|
-
|
|
7
|
-
# Ignore bundler config.
|
|
8
|
-
/.bundle
|
|
9
|
-
|
|
10
|
-
# Ignore the default SQLite database.
|
|
11
|
-
/db/*.sqlite3
|
|
12
|
-
/db/*.sqlite3-journal
|
|
13
|
-
|
|
14
|
-
coverage/
|
|
15
|
-
Gemfile.lock
|
|
16
|
-
|
|
17
|
-
# Ignore all logfiles and tempfiles.
|
|
18
|
-
/log/*.log
|
|
19
|
-
/tmp
|
|
20
|
-
**/tmp
|
|
21
|
-
*.gem
|
|
22
|
-
*.sqlite3
|
|
23
|
-
|
|
24
|
-
doc/
|
|
25
|
-
.yardoc/
|
|
26
|
-
_site/
|
|
27
|
-
TODO.md
|
data/.rspec
DELETED
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
data/bin/console
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require "bundler/setup"
|
|
5
|
-
require "yt"
|
|
6
|
-
|
|
7
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
-
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
-
|
|
10
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
-
require "pry"
|
|
12
|
-
Pry.start
|
|
13
|
-
|
|
14
|
-
# require "irb"
|
|
15
|
-
# IRB.start(__FILE__)
|
data/bin/yt
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
begin
|
|
4
|
-
require 'yt'
|
|
5
|
-
rescue LoadError
|
|
6
|
-
require 'rubygems'
|
|
7
|
-
require 'yt'
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
Yt.configuration.log_level = :debug
|
|
11
|
-
id = ARGV[1] || 'rdwz7QiG0lk'
|
|
12
|
-
|
|
13
|
-
case ARGV[0]
|
|
14
|
-
when 'info'
|
|
15
|
-
puts "Yt version #{Yt::VERSION}"
|
|
16
|
-
video = Yt::Video.new id: id
|
|
17
|
-
puts video.title
|
|
18
|
-
when 'video'
|
|
19
|
-
video = Yt::Video.new id: id
|
|
20
|
-
views = "#{video.view_count} #{'view'.pluralize video.view_count}"
|
|
21
|
-
likes = "#{video.like_count} #{'like'.pluralize video.like_count}"
|
|
22
|
-
puts "'#{video.title}' by #{video.channel_title} has #{views} and #{likes}"
|
|
23
|
-
end
|
data/yt.gemspec
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
lib = File.expand_path('../lib', __FILE__)
|
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
-
require 'yt/version'
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = "yt"
|
|
7
|
-
spec.version = Yt::VERSION
|
|
8
|
-
spec.authors = ["Claudio Baccigalupo"]
|
|
9
|
-
spec.email = ["claudio@fullscreen.net"]
|
|
10
|
-
spec.description = %q{Youtube V3 API client.}
|
|
11
|
-
spec.summary = %q{Yt makes it easy to interact with Youtube V3 API by
|
|
12
|
-
providing a modular, intuitive and tested Ruby-style API.}
|
|
13
|
-
spec.homepage = "http://github.com/Fullscreen/yt"
|
|
14
|
-
spec.license = "MIT"
|
|
15
|
-
|
|
16
|
-
spec.required_ruby_version = '>= 2.1'
|
|
17
|
-
|
|
18
|
-
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
19
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
20
|
-
end
|
|
21
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
22
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
23
|
-
spec.require_paths = ["lib"]
|
|
24
|
-
|
|
25
|
-
spec.add_dependency 'activesupport'
|
|
26
|
-
|
|
27
|
-
# For development / Code coverage / Documentation
|
|
28
|
-
spec.add_development_dependency 'bundler'
|
|
29
|
-
spec.add_development_dependency 'rspec'
|
|
30
|
-
spec.add_development_dependency 'rake'
|
|
31
|
-
# spec.add_development_dependency 'yard'
|
|
32
|
-
# spec.add_development_dependency 'coveralls'
|
|
33
|
-
spec.add_development_dependency 'pry'
|
|
34
|
-
spec.add_development_dependency 'vcr'
|
|
35
|
-
spec.add_development_dependency 'webmock'
|
|
36
|
-
end
|