yt 0.14.1 → 0.14.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|