yt 0.14.1 → 0.14.2
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 +6 -0
- data/README.md +1 -1
- data/bin/yt +19 -95
- data/lib/yt/collections/base.rb +11 -0
- data/lib/yt/collections/partnered_channels.rb +2 -9
- data/lib/yt/collections/reports.rb +5 -5
- data/lib/yt/collections/videos.rb +27 -1
- data/lib/yt/models/annotation.rb +2 -2
- data/lib/yt/models/content_detail.rb +1 -0
- data/lib/yt/models/snippet.rb +3 -1
- data/lib/yt/models/statistics_set.rb +2 -0
- data/lib/yt/models/status.rb +2 -0
- data/lib/yt/version.rb +1 -1
- data/spec/models/annotation_spec.rb +7 -0
- data/spec/models/content_detail_spec.rb +7 -0
- data/spec/models/snippet_spec.rb +7 -0
- data/spec/models/statistics_set_spec.rb +7 -0
- data/spec/models/status_spec.rb +7 -0
- data/spec/requests/as_account/account_spec.rb +27 -0
- data/spec/requests/as_account/channel_spec.rb +62 -24
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ab7c0d75dc3c575f9c55dd9e222505f70db290f
|
4
|
+
data.tar.gz: 1594d3e696c068d0a439396591e6a41efb292dd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5205274ae1d25ce04a75f6d5cd92742e1cfa77930695795a13879f463dcbaf0c5d5d25e56ef799bf90506c0494a29e732133faab705da4c9c32d2cf54bbb7d38
|
7
|
+
data.tar.gz: 42810660757c546f295d1f8b038ce2b7cefb74b30c20327cc7d1548e19562c07c06cfc3e53b867d604ef0156edc4be96bfcdc656acaeda030c87d1ef89441f2a
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,12 @@ 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.14.2 - 2015-04-08
|
10
|
+
|
11
|
+
* [FEATURE] Make `Annotation#text` a public method.
|
12
|
+
* [FEATURE] Make `data` a public method for Snippet, Status, ContentDetail and StatisticsSet.
|
13
|
+
* [FEATURE] Add .includes to .videos, so you can eager load snippet, status, statistics and content details for a collection of videos
|
14
|
+
|
9
15
|
## 0.14.1 - 2015-03-30
|
10
16
|
|
11
17
|
* [FEATURE] New `monetized playbacks` report for channels.
|
data/README.md
CHANGED
@@ -41,7 +41,7 @@ To install on your system, run
|
|
41
41
|
|
42
42
|
To use inside a bundled Ruby project, add this line to the Gemfile:
|
43
43
|
|
44
|
-
gem 'yt', '~> 0.14.
|
44
|
+
gem 'yt', '~> 0.14.2'
|
45
45
|
|
46
46
|
Since the gem follows [Semantic Versioning](http://semver.org),
|
47
47
|
indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
|
data/bin/yt
CHANGED
@@ -7,100 +7,24 @@ rescue LoadError
|
|
7
7
|
require 'yt'
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
10
|
+
Yt.configuration.log_level = :debug
|
11
|
+
id = ARGV[1] || 'BPNYv0vd78A'
|
12
|
+
|
13
|
+
case ARGV[0]
|
14
|
+
when 'info'
|
15
|
+
puts "Yt version #{Yt::VERSION}"
|
16
|
+
video = Yt::Video.new id: id
|
17
|
+
puts video.annotations.first.text
|
18
|
+
when 'annotations'
|
19
|
+
video = Yt::Video.new id: id
|
20
|
+
count = video.annotations.size
|
21
|
+
puts "Video #{id} has #{count} #{'annotation'.pluralize count}"
|
22
|
+
video.annotations.each.with_index do |annotation, i|
|
23
|
+
puts "#{i+1}) #{annotation.text}"
|
22
24
|
end
|
25
|
+
when 'video'
|
26
|
+
video = Yt::Video.new id: id
|
27
|
+
views = "#{video.view_count} #{'view'.pluralize video.view_count}"
|
28
|
+
likes = "#{video.like_count} #{'like'.pluralize video.like_count}"
|
29
|
+
puts "'#{video.title}' by #{video.channel_title} has #{views} and #{likes}"
|
23
30
|
end
|
24
|
-
|
25
|
-
puts "\nACCOUNT:\n"
|
26
|
-
puts " ID: #{account.id}"
|
27
|
-
puts " Email: #{account.email}"
|
28
|
-
puts " Email verified? #{account.has_verified_email?}"
|
29
|
-
puts " Gender: #{account.gender}"
|
30
|
-
puts " Name: #{account.name}"
|
31
|
-
puts " Given Name: #{account.given_name}"
|
32
|
-
puts " Family Name: #{account.family_name}"
|
33
|
-
puts " Profile URL: #{account.profile_url}"
|
34
|
-
puts " Avatar URL: #{account.avatar_url}"
|
35
|
-
puts " Locale: #{account.locale}"
|
36
|
-
puts " Hd? #{account.hd}"
|
37
|
-
|
38
|
-
puts "\nCHANNEL:\n"
|
39
|
-
channel = account.channel
|
40
|
-
puts " Title: #{channel.title}"
|
41
|
-
puts " Description: #{channel.description.truncate(30)}"
|
42
|
-
puts " Thumbnail URL: #{channel.thumbnail_url}"
|
43
|
-
puts " Published at: #{channel.published_at}"
|
44
|
-
puts " Public? #{channel.public?}"
|
45
|
-
puts " Views: #{channel.view_count}"
|
46
|
-
puts " Comments: #{channel.comment_count}"
|
47
|
-
puts " Videos: #{channel.video_count}"
|
48
|
-
puts " Subscribers: #{channel.subscriber_count}"
|
49
|
-
puts " Subscribers are visible? #{channel.subscriber_count_visible?}"
|
50
|
-
# These are not available with a device auth :(
|
51
|
-
# puts " Views: #{channel.views}"
|
52
|
-
# puts " Comments: #{channel.comments}"
|
53
|
-
# puts " Likes: #{channel.likes}"
|
54
|
-
# puts " Dislikes: #{channel.dislikes}"
|
55
|
-
# puts " Shares: #{channel.shares}"
|
56
|
-
# puts " Viewers: #{channel.viewer_percentages}"
|
57
|
-
|
58
|
-
account.videos.first(5).each.with_index do |video, i|
|
59
|
-
puts "\nVIDEO #{i+1}:\n"
|
60
|
-
puts " Title: #{video.title}"
|
61
|
-
puts " Description: #{video.description.truncate(30)}"
|
62
|
-
puts " Thumbnail URL: #{video.thumbnail_url}"
|
63
|
-
puts " Published at: #{video.published_at}"
|
64
|
-
puts " Tags: #{video.tags}"
|
65
|
-
puts " Channel ID: #{video.channel_id}"
|
66
|
-
puts " Channel Title: #{video.channel_title}"
|
67
|
-
puts " Category ID: #{video.category_id}"
|
68
|
-
puts " Live content? #{video.live_broadcast_content}"
|
69
|
-
puts " Public? #{video.public?}"
|
70
|
-
puts " Views: #{video.view_count}"
|
71
|
-
puts " Comments: #{video.comment_count}"
|
72
|
-
puts " Likes: #{video.like_count}"
|
73
|
-
puts " Dislikes: #{video.dislike_count}"
|
74
|
-
puts " Favorites: #{video.favorite_count}"
|
75
|
-
puts " Duration: #{video.duration}s"
|
76
|
-
puts " HD: #{video.hd?}"
|
77
|
-
puts " stereoscopic? #{video.stereoscopic?}"
|
78
|
-
puts " captioned? #{video.captioned?}"
|
79
|
-
puts " licensed? #{video.licensed?}"
|
80
|
-
# These are not available with a device auth :(
|
81
|
-
# puts " Views: #{video.views}"
|
82
|
-
# puts " Comments: #{video.comments}"
|
83
|
-
# puts " Likes: #{video.likes}"
|
84
|
-
# puts " Dislikes: #{video.dislikes}"
|
85
|
-
# puts " Shares: #{video.shares}"
|
86
|
-
# puts " Viewers: #{video.viewer_percentages}"
|
87
|
-
puts " Annotations: #{video.annotations.count}"
|
88
|
-
end
|
89
|
-
|
90
|
-
account.playlists.first(5).each.with_index do |playlist, i|
|
91
|
-
puts "\nPLAYLIST #{i+1}:\n"
|
92
|
-
puts " Title: #{playlist.title}"
|
93
|
-
puts " Description: #{playlist.description.truncate(30)}"
|
94
|
-
puts " Thumbnail URL: #{playlist.thumbnail_url}"
|
95
|
-
puts " Published at: #{playlist.published_at}"
|
96
|
-
puts " Tags: #{playlist.tags}"
|
97
|
-
puts " Channel ID: #{playlist.channel_id}"
|
98
|
-
puts " Channel Title: #{playlist.channel_title}"
|
99
|
-
puts " Public? #{playlist.public?}"
|
100
|
-
puts " Playlist items: #{playlist.playlist_items.count}"
|
101
|
-
playlist.playlist_items.first(5).each.with_index do |playlist_item, j|
|
102
|
-
puts " \nPLAYLIST ITEM #{j+1}:\n"
|
103
|
-
puts " Position: #{playlist_item.position + 1}"
|
104
|
-
puts " Video ID: #{playlist_item.video_id}"
|
105
|
-
end
|
106
|
-
end
|
data/lib/yt/collections/base.rb
CHANGED
@@ -41,11 +41,22 @@ module Yt
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def includes(*relationships)
|
45
|
+
self.tap do
|
46
|
+
@items = []
|
47
|
+
@included_relationships = relationships
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
44
51
|
private
|
45
52
|
|
46
53
|
def apply_where_params!(params = {})
|
47
54
|
params.merge!(@where_params ||= {})
|
48
55
|
end
|
56
|
+
|
57
|
+
def included_relationships
|
58
|
+
@included_relationships || []
|
59
|
+
end
|
49
60
|
end
|
50
61
|
end
|
51
62
|
end
|
@@ -4,13 +4,6 @@ module Yt
|
|
4
4
|
module Collections
|
5
5
|
class PartneredChannels < Channels
|
6
6
|
|
7
|
-
def includes(relationship)
|
8
|
-
self.tap do
|
9
|
-
@items = []
|
10
|
-
@includes_relationship = relationship
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
7
|
private
|
15
8
|
|
16
9
|
def attributes_for_new_item(data)
|
@@ -20,7 +13,7 @@ module Yt
|
|
20
13
|
end
|
21
14
|
|
22
15
|
def eager_load_items_from(items)
|
23
|
-
if
|
16
|
+
if included_relationships.include? :viewer_percentages
|
24
17
|
filters = "channel==#{items.map{|item| item['id']}.join(',')}"
|
25
18
|
ids = "contentOwner==#{@auth.owner_name}"
|
26
19
|
conditions = {ids: ids, filters: filters}
|
@@ -30,7 +23,7 @@ module Yt
|
|
30
23
|
item['viewerPercentages'] = viewer_percentages[item['id']]
|
31
24
|
end
|
32
25
|
end
|
33
|
-
|
26
|
+
super
|
34
27
|
end
|
35
28
|
|
36
29
|
# @private
|
@@ -3,10 +3,10 @@ require 'yt/collections/base'
|
|
3
3
|
module Yt
|
4
4
|
module Collections
|
5
5
|
class Reports < Base
|
6
|
-
DIMENSIONS = Hash.new({name: 'day', parse: ->
|
7
|
-
hash[:traffic_source] = {name: 'insightTrafficSourceType', parse: ->
|
8
|
-
hash[:video] = {name: 'video', parse: ->
|
9
|
-
hash[:playlist] = {name: 'playlist', parse: ->
|
6
|
+
DIMENSIONS = Hash.new({name: 'day', parse: ->(day) {Date.iso8601 day} }).tap do |hash|
|
7
|
+
hash[:traffic_source] = {name: 'insightTrafficSourceType', parse: ->(type) {TRAFFIC_SOURCES.key type} }
|
8
|
+
hash[:video] = {name: 'video', parse: ->(video_id) { Yt::Video.new id: video_id, auth: @auth } }
|
9
|
+
hash[:playlist] = {name: 'playlist', parse: ->(playlist_id) { Yt::Playlist.new id: playlist_id, auth: @auth } }
|
10
10
|
end
|
11
11
|
|
12
12
|
# @see https://developers.google.com/youtube/analytics/v1/dimsmets/dims#Traffic_Source_Dimensions
|
@@ -80,4 +80,4 @@ module Yt
|
|
80
80
|
end
|
81
81
|
end
|
82
82
|
end
|
83
|
-
end
|
83
|
+
end
|
@@ -8,12 +8,16 @@ module Yt
|
|
8
8
|
# Resources with videos are: {Yt::Models::Channel channels} and
|
9
9
|
# {Yt::Models::Account accounts}.
|
10
10
|
class Videos < Base
|
11
|
+
def where(requirements = {})
|
12
|
+
@published_before = nil
|
13
|
+
super
|
14
|
+
end
|
11
15
|
|
12
16
|
private
|
13
17
|
|
14
18
|
def attributes_for_new_item(data)
|
15
19
|
id = use_list_endpoint? ? data['id'] : data['id']['videoId']
|
16
|
-
snippet = data['snippet'].
|
20
|
+
snippet = data['snippet'].reverse_merge includes_tags: false if data['snippet']
|
17
21
|
{}.tap do |attributes|
|
18
22
|
attributes[:id] = id
|
19
23
|
attributes[:snippet] = snippet
|
@@ -24,6 +28,28 @@ module Yt
|
|
24
28
|
end
|
25
29
|
end
|
26
30
|
|
31
|
+
def eager_load_items_from(items)
|
32
|
+
if included_relationships.any?
|
33
|
+
ids = items.map{|item| item['id']['videoId']}
|
34
|
+
parts = included_relationships.map{|r| r.to_s.camelize(:lower)}
|
35
|
+
conditions = {id: ids.join(','), part: parts.join(',')}
|
36
|
+
videos = Collections::Videos.new(auth: @auth).where conditions
|
37
|
+
|
38
|
+
items.each do |item|
|
39
|
+
video = videos.find{|v| v.id == item['id']['videoId']}
|
40
|
+
parts.each do |part|
|
41
|
+
item[part] = case part
|
42
|
+
when 'snippet' then video.snippet.data.merge includes_tags: true
|
43
|
+
when 'status' then video.status.data
|
44
|
+
when 'statistics' then video.statistics_set.data
|
45
|
+
when 'contentDetails' then video.content_detail.data
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
27
53
|
# @return [Hash] the parameters to submit to YouTube to list videos.
|
28
54
|
# @see https://developers.google.com/youtube/v3/docs/search/list
|
29
55
|
def list_params
|
data/lib/yt/models/annotation.rb
CHANGED
data/lib/yt/models/snippet.rb
CHANGED
@@ -12,6 +12,8 @@ module Yt
|
|
12
12
|
# @see https://developers.google.com/youtube/v3/docs/playlists#resource
|
13
13
|
# @see https://developers.google.com/youtube/v3/docs/playlistItems#resource
|
14
14
|
class Snippet < Base
|
15
|
+
attr_reader :data
|
16
|
+
|
15
17
|
def initialize(options = {})
|
16
18
|
@data = options[:data]
|
17
19
|
@auth = options[:auth]
|
@@ -153,7 +155,7 @@ module Yt
|
|
153
155
|
# @see https://developers.google.com/youtube/v3/docs/videos
|
154
156
|
# @return [Boolean] whether YouTube API includes tags in this snippet.
|
155
157
|
def includes_tags
|
156
|
-
@includes_tags ||=
|
158
|
+
@includes_tags ||= data.fetch :includes_tags, true
|
157
159
|
end
|
158
160
|
|
159
161
|
private
|
data/lib/yt/models/status.rb
CHANGED
@@ -12,6 +12,8 @@ module Yt
|
|
12
12
|
# @see https://developers.google.com/youtube/v3/docs/playlists#resource
|
13
13
|
# @see https://developers.google.com/youtube/v3/docs/playlistItems#resource
|
14
14
|
class Status < Base
|
15
|
+
attr_reader :data
|
16
|
+
|
15
17
|
def initialize(options = {})
|
16
18
|
@data = options[:data]
|
17
19
|
end
|
data/lib/yt/version.rb
CHANGED
@@ -43,6 +43,13 @@ describe Yt::Annotation do
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
describe '#text' do
|
47
|
+
context 'given an annotation with text' do
|
48
|
+
let(:xml) { '<TEXT>Hello, world!</TEXT>' }
|
49
|
+
it { expect(annotation.text).to eq 'Hello, world!' }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
46
53
|
describe '#has_link_to_subscribe?' do
|
47
54
|
context 'given an annotation with a link of class 5' do
|
48
55
|
let(:xml) { '<action type="openUrl"><url link_class="5"/></action>' }
|
@@ -4,6 +4,13 @@ require 'yt/models/content_detail'
|
|
4
4
|
describe Yt::ContentDetail do
|
5
5
|
subject(:content_detail) { Yt::ContentDetail.new data: data }
|
6
6
|
|
7
|
+
describe '#data' do
|
8
|
+
let(:data) { {"key"=>"value"} }
|
9
|
+
specify 'returns the data the content detail was initialized with' do
|
10
|
+
expect(content_detail.data).to eq data
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
7
14
|
describe '#duration' do
|
8
15
|
context 'given a content_detail with duration in weeks, days, hours, minutes' do
|
9
16
|
let(:data) { {"duration"=>"P1W2DT6H21M32S"}}
|
data/spec/models/snippet_spec.rb
CHANGED
@@ -5,6 +5,13 @@ describe Yt::Snippet do
|
|
5
5
|
subject(:snippet) { Yt::Snippet.new data: data }
|
6
6
|
let(:data) { {} }
|
7
7
|
|
8
|
+
describe '#data' do
|
9
|
+
let(:data) { {"key"=>"value"} }
|
10
|
+
specify 'returns the data the snippet was initialized with' do
|
11
|
+
expect(snippet.data).to eq data
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
8
15
|
describe '#title' do
|
9
16
|
context 'given a snippet with a title' do
|
10
17
|
let(:data) { {"title"=>"Fullscreen"} }
|
@@ -5,6 +5,13 @@ describe Yt::StatisticsSet do
|
|
5
5
|
subject(:statistics_set) { Yt::StatisticsSet.new data: data }
|
6
6
|
let(:value) { 42 }
|
7
7
|
|
8
|
+
describe '#data' do
|
9
|
+
let(:data) { {"key"=>"value"} }
|
10
|
+
specify 'returns the data the statistics set was initialized with' do
|
11
|
+
expect(statistics_set.data).to eq data
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
8
15
|
describe '#view_count' do
|
9
16
|
context 'given a video with views' do
|
10
17
|
let(:data) { {"viewCount"=>value} }
|
data/spec/models/status_spec.rb
CHANGED
@@ -4,6 +4,13 @@ require 'yt/models/status'
|
|
4
4
|
describe Yt::Status do
|
5
5
|
subject(:status) { Yt::Status.new data: data }
|
6
6
|
|
7
|
+
describe '#data' do
|
8
|
+
let(:data) { {"key"=>"value"} }
|
9
|
+
specify 'returns the data the status was initialized with' do
|
10
|
+
expect(status.data).to eq data
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
7
14
|
describe '#public?' do
|
8
15
|
context 'given fetching a status returns privacyStatus "public"' do
|
9
16
|
let(:data) { {"privacyStatus"=>"public"} }
|
@@ -49,6 +49,33 @@ describe Yt::Account, :device_app do
|
|
49
49
|
let(:other_video) { $account.videos.where(order: 'viewCount', chart: 'invalid').first }
|
50
50
|
it { expect(other_video.id).to eq video.id }
|
51
51
|
end
|
52
|
+
|
53
|
+
describe '.includes(:snippet)' do
|
54
|
+
let(:video) { $account.videos.includes(:snippet).first }
|
55
|
+
|
56
|
+
specify 'eager-loads the *full* snippet of each video' do
|
57
|
+
expect(video.instance_variable_defined? :@snippet).to be true
|
58
|
+
expect(video.channel_title).to be
|
59
|
+
expect(video.snippet.includes_tags).to be true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '.includes(:statistics, :status)' do
|
64
|
+
let(:video) { $account.videos.includes(:statistics, :status).first }
|
65
|
+
|
66
|
+
specify 'eager-loads the statistics and status of each video' do
|
67
|
+
expect(video.instance_variable_defined? :@statistics_set).to be true
|
68
|
+
expect(video.instance_variable_defined? :@status).to be true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '.includes(:content_details)' do
|
73
|
+
let(:video) { $account.videos.includes(:content_details).first }
|
74
|
+
|
75
|
+
specify 'eager-loads the statistics of each video' do
|
76
|
+
expect(video.instance_variable_defined? :@content_detail).to be true
|
77
|
+
end
|
78
|
+
end
|
52
79
|
end
|
53
80
|
|
54
81
|
describe '.upload_video' do
|
@@ -21,7 +21,68 @@ describe Yt::Channel, :device_app do
|
|
21
21
|
expect(channel.subscriber_count_visible?).to be_in [true, false]
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
describe '.videos' do
|
25
|
+
let(:video) { channel.videos.first }
|
26
|
+
|
27
|
+
specify 'returns the videos in the channel without their tags' do
|
28
|
+
expect(video).to be_a Yt::Video
|
29
|
+
expect(video.snippet.includes_tags).to be false
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '.where(id: *anything*)' do
|
33
|
+
let(:video) { channel.videos.where(id: 'invalid').first }
|
34
|
+
|
35
|
+
specify 'is ignored (all the channel’s videos are returned)' do
|
36
|
+
expect(video).to be_a Yt::Video
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '.where(chart: *anything*)' do
|
41
|
+
let(:video) { channel.videos.where(chart: 'invalid').first }
|
42
|
+
|
43
|
+
specify 'is ignored (all the channel’s videos are returned)' do
|
44
|
+
expect(video).to be_a Yt::Video
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '.includes(:statistics, :status)' do
|
49
|
+
let(:video) { channel.videos.includes(:statistics, :status).first }
|
50
|
+
|
51
|
+
specify 'eager-loads the statistics and status of each video' do
|
52
|
+
expect(video.instance_variable_defined? :@statistics_set).to be true
|
53
|
+
expect(video.instance_variable_defined? :@status).to be true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '.includes(:content_details)' do
|
58
|
+
let(:video) { channel.videos.includes(:content_details).first }
|
59
|
+
|
60
|
+
specify 'eager-loads the statistics of each video' do
|
61
|
+
expect(video.instance_variable_defined? :@content_detail).to be true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
describe 'when the channel has more than 500 videos' do
|
67
|
+
let(:id) { 'UCsmvakQZlvGsyjyOhmhvOsw' }
|
68
|
+
|
69
|
+
specify 'the estimated and actual number of videos can be retrieved' do
|
70
|
+
# @note: in principle, the following three counters should match, but
|
71
|
+
# in reality +video_count+ and +size+ are only approximations.
|
72
|
+
expect(channel.video_count).to be > 500
|
73
|
+
expect(channel.videos.size).to be > 500
|
74
|
+
end
|
75
|
+
|
76
|
+
specify 'over 500 videos can only be retrieved when sorting by date' do
|
77
|
+
# @note: these tests are slow because they go through multiple pages
|
78
|
+
# of results to test that we can overcome YouTube’s limitation of only
|
79
|
+
# returning the first 500 results when ordered by date.
|
80
|
+
expect(channel.videos.count).to be > 500
|
81
|
+
expect(channel.videos.where(order: 'viewCount').count).to be 500
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
25
86
|
it { expect(channel.playlists.first).to be_a Yt::Playlist }
|
26
87
|
it { expect{channel.delete_playlists}.to raise_error Yt::Errors::RequestError }
|
27
88
|
|
@@ -70,29 +131,6 @@ describe Yt::Channel, :device_app do
|
|
70
131
|
it { expect(channel.subscribe!).to be_truthy }
|
71
132
|
end
|
72
133
|
end
|
73
|
-
|
74
|
-
describe 'filtering by ID is ignored when listing videos' do
|
75
|
-
it { expect(channel.videos.where(id: 'invalid').first).to be_a Yt::Video }
|
76
|
-
end
|
77
|
-
|
78
|
-
describe 'filtering by chart is ignored when listing videos' do
|
79
|
-
it { expect(channel.videos.where(chart: 'invalid').first).to be_a Yt::Video }
|
80
|
-
end
|
81
|
-
|
82
|
-
context 'with more than 500 videos' do
|
83
|
-
let(:id) { 'UCsmvakQZlvGsyjyOhmhvOsw' }
|
84
|
-
# @note: in principle, the following three counters should match, but in
|
85
|
-
# reality +video_count+ and +size+ are only approximations.
|
86
|
-
it { expect(channel.video_count).to be > 500 }
|
87
|
-
it { expect(channel.videos.size).to be > 500 }
|
88
|
-
context 'with default order (by date)' do
|
89
|
-
# @note: these tests are slow because they go through multiple pages of
|
90
|
-
# results and do so to test that we can overcome YouTube’s limitation of
|
91
|
-
# only returning the first 500 results when ordered by date.
|
92
|
-
it { expect(channel.videos.count).to be > 500 }
|
93
|
-
it { expect(channel.videos.where(order: 'viewCount').count).to be 500 }
|
94
|
-
end
|
95
|
-
end
|
96
134
|
end
|
97
135
|
|
98
136
|
context 'given my own channel' do
|
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.14.
|
4
|
+
version: 0.14.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claudio Baccigalupo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|