yt 0.25.3 → 0.25.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +1 -1
- data/YOUTUBE_IT.md +35 -67
- data/lib/yt/actions/list.rb +7 -3
- data/lib/yt/collections/related_playlists.rb +43 -0
- data/lib/yt/models/account.rb +6 -0
- data/lib/yt/models/channel.rb +6 -0
- data/lib/yt/version.rb +1 -1
- data/spec/requests/as_account/account_spec.rb +21 -0
- data/spec/requests/as_account/channel_spec.rb +18 -0
- data/spec/requests/as_server_app/channel_spec.rb +2 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b97dd069350cac3eb417bd71f95e954002f18e95
|
4
|
+
data.tar.gz: 967cb4ed7350c7b451097d25e021e2b1deaa0543
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 573902e507215412b8fd4481ed9446a84cb6f57fe068f0e41ea9c52b7136c35a7da06b6ca2f48e4a5ba962b3715d63ac0d361dd93079fd45b410d105ed23f015
|
7
|
+
data.tar.gz: 09c85fe37c9cdec1b9d9037f0cd60b05135544db9e8a125e11769f652889ab42899184bff45607b38434f7a98b408701c859cb7eed745d5fb845beef91063973
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,10 @@ 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.25.4 - 2015-07-27
|
10
|
+
|
11
|
+
* [FEATURE] Add `channel.related_playlist` and `account.related_playlists` to access "Liked Videos", "Uploads", etc.
|
12
|
+
|
9
13
|
## 0.25.3 - 2015-07-23
|
10
14
|
|
11
15
|
* [BUGFIX] Don’t run an infinite loop when calling `.playlist_items.includes(:video)` on a playlist with only private or deleted videos
|
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.25.
|
44
|
+
gem 'yt', '~> 0.25.4'
|
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/YOUTUBE_IT.md
CHANGED
@@ -180,38 +180,19 @@ channel = Yt::Channel.new url: 'youtube.com/liz'
|
|
180
180
|
channel.videos.where(q: 'penguin')
|
181
181
|
```
|
182
182
|
|
183
|
-
<!--
|
184
|
-
|
185
|
-
TODO: Although FAVORITE is somehow deprecated, it can still be retrieved with
|
186
|
-
V3. First, get the contentDetails of the account's channel and you'll get
|
187
|
-
|
188
|
-
{"relatedPlaylists"=>
|
189
|
-
{"likes"=>"LLrWYT-_Xncr1BLPfPNr50sQ",
|
190
|
-
"favorites"=>"FLrWYT-_Xncr1BLPfPNr50sQ",
|
191
|
-
"uploads"=>"UUrWYT-_Xncr1BLPfPNr50sQ",
|
192
|
-
"watchHistory"=>"HLrWYT-_Xncr1BLPfPNr50sQ",
|
193
|
-
"watchLater"=>"WLrWYT-_Xncr1BLPfPNr50sQ"},
|
194
|
-
|
195
|
-
Then you can list the videos of the "favorites" playlist. That playlist does
|
196
|
-
not exist for new YouTube account, but you can still add a video to it, and
|
197
|
-
it will magically appear (and also, DELETE PLAYLIST will be disabled)
|
198
|
-
|
199
183
|
List videos favorited by user:
|
200
184
|
|
201
185
|
```ruby
|
202
186
|
# with youtube_it
|
203
187
|
client = YouTubeIt::Client.new
|
204
188
|
client.videos_by(:favorites, :user => 'liz')
|
205
|
-
# with yt:
|
206
|
-
|
207
|
-
|
208
|
-
|
189
|
+
# with yt: note that only *old* channels have a "Favorites" playlist, since
|
190
|
+
# "Favorites" has been deprecated by YouTube in favor of "Liked Videos".
|
191
|
+
channel = Yt::Channel.new url: 'youtube.com/liz'
|
192
|
+
channel.related_playlists.find{|p| p.title == 'Favorites'}
|
209
193
|
```
|
210
194
|
|
211
195
|
|
212
|
-
|
213
|
-
-->
|
214
|
-
|
215
196
|
Retrieve video by ID:
|
216
197
|
|
217
198
|
```ruby
|
@@ -509,32 +490,16 @@ client.delete_comment(video_id, comment_id)
|
|
509
490
|
# with yt: not supported (was removed from YouTube API V3)
|
510
491
|
```
|
511
492
|
|
512
|
-
<!--
|
513
493
|
List Favorites:
|
514
494
|
|
515
|
-
|
516
|
-
TODO: Although FAVORITE is somehow deprecated, it can still be retrieved with
|
517
|
-
V3. First, get the contentDetails of the account's channel and you'll get
|
518
|
-
|
519
|
-
{"relatedPlaylists"=>
|
520
|
-
{"likes"=>"LLrWYT-_Xncr1BLPfPNr50sQ",
|
521
|
-
"favorites"=>"FLrWYT-_Xncr1BLPfPNr50sQ",
|
522
|
-
"uploads"=>"UUrWYT-_Xncr1BLPfPNr50sQ",
|
523
|
-
"watchHistory"=>"HLrWYT-_Xncr1BLPfPNr50sQ",
|
524
|
-
"watchLater"=>"WLrWYT-_Xncr1BLPfPNr50sQ"},
|
525
|
-
|
526
|
-
Then you can list the videos of the "favorites" playlist. That playlist does
|
527
|
-
not exist for new YouTube account, but you can still add a video to it, and
|
528
|
-
it will magically appear (and also, DELETE PLAYLIST will be disabled)
|
529
|
-
|
530
|
-
|
531
495
|
```ruby
|
532
496
|
# with youtube_it
|
533
497
|
client = # new client initialized with either OAuth or AuthSub
|
534
498
|
client.favorites(user) # default: current user
|
535
|
-
# with yt
|
536
|
-
|
537
|
-
|
499
|
+
# with yt: note that only *old* channels have a "Favorites" playlist, since
|
500
|
+
# "Favorites" has been deprecated by YouTube in favor of "Liked Videos".
|
501
|
+
account = Yt::Account.new access_token: 'access_token'
|
502
|
+
account.related_playlists.find{|p| p.title == 'Favorites'}
|
538
503
|
```
|
539
504
|
|
540
505
|
Add Favorite:
|
@@ -723,36 +688,39 @@ playlist_item = Yt::PlaylistItem.new id: playlist_entry_id, auth: account
|
|
723
688
|
playlist_item.update position: position
|
724
689
|
```
|
725
690
|
|
726
|
-
<!--
|
727
|
-
|
728
|
-
|
729
|
-
TODO: Although WATCHLATER is somehow deprecated, it can still be retrieved with
|
730
|
-
V3. First, get the contentDetails of the account's channel and you'll get
|
731
|
-
|
732
|
-
{"relatedPlaylists"=>
|
733
|
-
{"likes"=>"LLrWYT-_Xncr1BLPfPNr50sQ",
|
734
|
-
"favorites"=>"FLrWYT-_Xncr1BLPfPNr50sQ",
|
735
|
-
"uploads"=>"UUrWYT-_Xncr1BLPfPNr50sQ",
|
736
|
-
"watchHistory"=>"HLrWYT-_Xncr1BLPfPNr50sQ",
|
737
|
-
"watchLater"=>"WLrWYT-_Xncr1BLPfPNr50sQ"},
|
738
|
-
|
739
|
-
Then you can list the videos of the "watch later" playlist. That playlist does
|
740
|
-
not exist for new YouTube account, but you can still add a video to it, and
|
741
|
-
it will magically appear (and also, DELETE PLAYLIST will be disabled)
|
742
|
-
|
743
|
-
|
744
691
|
Select All Videos From your Watch Later Playlist:
|
745
|
-
|
746
|
-
|
692
|
+
|
693
|
+
```ruby
|
694
|
+
# with youtube_it
|
695
|
+
watcher_later = client.watcherlater(user) #default: current user
|
696
|
+
watcher_later.videos
|
697
|
+
# with yt
|
698
|
+
account = Yt::Account.new access_token: 'access_token'
|
699
|
+
watch_later = account.related_playlists.find{|p| p.title == 'Watch Later'}
|
700
|
+
watch_later.playlist_items.map{|item| item.video}
|
701
|
+
```
|
747
702
|
|
748
703
|
Add Video To Watcher Later Playlist:
|
749
|
-
$ client.add_video_to_watchlater(video_id)
|
750
704
|
|
751
|
-
|
752
|
-
|
705
|
+
```ruby
|
706
|
+
# with youtube_it
|
707
|
+
client.add_video_to_watchlater(video_id)
|
708
|
+
# with yt
|
709
|
+
account = Yt::Account.new access_token: 'access_token'
|
710
|
+
watch_later = account.related_playlists.find{|p| p.title == 'Watch Later'}
|
711
|
+
watch_later.add_video video_id
|
712
|
+
```
|
753
713
|
|
754
|
-
|
714
|
+
Remove Video From Watch Later Playlist:
|
755
715
|
|
716
|
+
```ruby
|
717
|
+
# with youtube_it
|
718
|
+
client.delete_video_from_watchlater(watchlater_entry_id)
|
719
|
+
# with yt
|
720
|
+
account = Yt::Account.new access_token: 'access_token'
|
721
|
+
watch_later = account.related_playlists.find{|p| p.title == 'Watch Later'}
|
722
|
+
watch_later.delete_playlist_items video_id: video_id
|
723
|
+
```
|
756
724
|
|
757
725
|
<!-- TODO: Add using https://developers.google.com/youtube/v3/docs/search/list#relatedToVideoId
|
758
726
|
|
data/lib/yt/actions/list.rb
CHANGED
@@ -7,7 +7,7 @@ module Yt
|
|
7
7
|
module Actions
|
8
8
|
module List
|
9
9
|
delegate :any?, :count, :each, :each_cons, :each_slice, :find, :first,
|
10
|
-
:flat_map, :map, :size, to: :list
|
10
|
+
:flat_map, :map, :select, :size, to: :list
|
11
11
|
|
12
12
|
def first!
|
13
13
|
first.tap{|item| raise Errors::NoItems, error_message unless item}
|
@@ -41,7 +41,7 @@ module Yt
|
|
41
41
|
def total_results
|
42
42
|
response = list_request(list_params).run
|
43
43
|
total_results = response.body.fetch('pageInfo', {})['totalResults']
|
44
|
-
total_results ||= response.body
|
44
|
+
total_results ||= extract_items(response.body).size
|
45
45
|
end
|
46
46
|
|
47
47
|
def find_next
|
@@ -93,7 +93,7 @@ module Yt
|
|
93
93
|
def fetch_page(params = {})
|
94
94
|
@last_response = list_request(params).run
|
95
95
|
token = @last_response.body['nextPageToken']
|
96
|
-
items = @last_response.body
|
96
|
+
items = extract_items @last_response.body
|
97
97
|
{items: items, token: token}
|
98
98
|
end
|
99
99
|
|
@@ -123,6 +123,10 @@ module Yt
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
+
def extract_items(list)
|
127
|
+
list.fetch items_key, []
|
128
|
+
end
|
129
|
+
|
126
130
|
def items_key
|
127
131
|
'items'
|
128
132
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'yt/collections/playlists'
|
2
|
+
|
3
|
+
module Yt
|
4
|
+
module Collections
|
5
|
+
class RelatedPlaylists < Playlists
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
# Retrieving related playlists requires to hit the /channels endpoint.
|
10
|
+
def list_resources
|
11
|
+
'channels'
|
12
|
+
end
|
13
|
+
|
14
|
+
# The related playlists are included in the content details of a channel.
|
15
|
+
def playlists_params
|
16
|
+
{part: 'contentDetails', id: @parent.id}
|
17
|
+
end
|
18
|
+
|
19
|
+
# The object to create is "Yt::Models::Playlist", not "RelatedPlaylist"
|
20
|
+
def resource_class
|
21
|
+
Yt::Models::Playlist
|
22
|
+
end
|
23
|
+
|
24
|
+
# The related playlists are nested inside the "relatedPlaylists" key.
|
25
|
+
def extract_items(list)
|
26
|
+
if (items = super).any?
|
27
|
+
items.first['contentDetails'].fetch 'relatedPlaylists', {}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Since there are at most 5 related playlists, they can be eager-loaded.
|
32
|
+
def eager_load_items_from(items)
|
33
|
+
conditions = {id: items.values.join(','), part: 'snippet,status'}
|
34
|
+
Collections::Playlists.new(auth: @auth).where conditions
|
35
|
+
end
|
36
|
+
|
37
|
+
# Related playlists are eager-loaded, there’s no need to load them again.
|
38
|
+
def new_item(playlist)
|
39
|
+
playlist
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/yt/models/account.rb
CHANGED
@@ -134,6 +134,12 @@ module Yt
|
|
134
134
|
# @return [Yt::Collections::Playlists] the playlists owned by the account.
|
135
135
|
delegate :playlists, to: :channel
|
136
136
|
|
137
|
+
# @!attribute [r] related_playlists
|
138
|
+
# @return [Yt::Collections::Playlists] the playlists associated with the
|
139
|
+
# account, such as the playlist of uploaded or liked videos.
|
140
|
+
# @see https://developers.google.com/youtube/v3/docs/channels#contentDetails.relatedPlaylists
|
141
|
+
delegate :related_playlists, to: :channel
|
142
|
+
|
137
143
|
# @!attribute [r] subscribed_channels
|
138
144
|
# @return [Yt::Collections::SubscribedChannels] the channels that the
|
139
145
|
# account is subscribed to.
|
data/lib/yt/models/channel.rb
CHANGED
@@ -94,6 +94,12 @@ module Yt
|
|
94
94
|
# @return [Yt::Collections::Playlists] the channel’s playlists.
|
95
95
|
has_many :playlists
|
96
96
|
|
97
|
+
# @!attribute [r] related_playlists
|
98
|
+
# @return [Yt::Collections::Playlists] the playlists associated with the
|
99
|
+
# channel, such as the playlist of uploaded or liked videos.
|
100
|
+
# @see https://developers.google.com/youtube/v3/docs/channels#contentDetails.relatedPlaylists
|
101
|
+
has_many :related_playlists
|
102
|
+
|
97
103
|
# @!attribute [r] subscribed_channels
|
98
104
|
# @return [Yt::Collections::SubscribedChannels] the channels that this
|
99
105
|
# channel is subscribed to.
|
data/lib/yt/version.rb
CHANGED
@@ -15,6 +15,27 @@ describe Yt::Account, :device_app do
|
|
15
15
|
it { expect($account.subscribed_channels.first).to be_a Yt::Channel }
|
16
16
|
it { expect($account.user_info).to be_a Yt::UserInfo }
|
17
17
|
|
18
|
+
describe '.related_playlists' do
|
19
|
+
let(:related_playlists) { $account.related_playlists }
|
20
|
+
|
21
|
+
specify 'returns the list of associated playlist (Liked Videos, Uploads, ...)' do
|
22
|
+
expect(related_playlists.first).to be_a Yt::Playlist
|
23
|
+
end
|
24
|
+
|
25
|
+
specify 'includes public related playlists (such as Liked Videos)' do
|
26
|
+
uploads = related_playlists.select{|p| p.title.starts_with? 'Uploads'}
|
27
|
+
expect(uploads).not_to be_empty
|
28
|
+
end
|
29
|
+
|
30
|
+
specify 'includes private playlists (such as Watch Later or History)' do
|
31
|
+
watch_later = related_playlists.select{|p| p.title == 'Watch Later'}
|
32
|
+
expect(watch_later).not_to be_empty
|
33
|
+
|
34
|
+
history = related_playlists.select{|p| p.title == 'History'}
|
35
|
+
expect(history).not_to be_empty
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
18
39
|
describe '.videos' do
|
19
40
|
let(:video) { $account.videos.where(order: 'viewCount').first }
|
20
41
|
|
@@ -102,6 +102,24 @@ describe Yt::Channel, :device_app do
|
|
102
102
|
it { expect(channel.playlists.first).to be_a Yt::Playlist }
|
103
103
|
it { expect{channel.delete_playlists}.to raise_error Yt::Errors::RequestError }
|
104
104
|
|
105
|
+
describe '.related_playlists' do
|
106
|
+
let(:related_playlists) { channel.related_playlists }
|
107
|
+
|
108
|
+
specify 'returns the list of associated playlist (Liked Videos, Uploads, ...)' do
|
109
|
+
expect(related_playlists.first).to be_a Yt::Playlist
|
110
|
+
end
|
111
|
+
|
112
|
+
specify 'includes public related playlists (such as Liked Videos)' do
|
113
|
+
uploads = related_playlists.select{|p| p.title.starts_with? 'Uploads'}
|
114
|
+
expect(uploads).not_to be_empty
|
115
|
+
end
|
116
|
+
|
117
|
+
specify 'does not includes private playlists (such as Watch Later)' do
|
118
|
+
watch_later = related_playlists.select{|p| p.title.starts_with? 'Watch'}
|
119
|
+
expect(watch_later).to be_empty
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
105
123
|
specify 'with a public list of subscriptions' do
|
106
124
|
expect(channel.subscribed_channels.first).to be_a Yt::Channel
|
107
125
|
end
|
@@ -21,6 +21,8 @@ describe Yt::Channel, :server_app do
|
|
21
21
|
it { expect(channel.videos.first).to be_a Yt::Video }
|
22
22
|
it { expect(channel.playlists).to be_a Yt::Collections::Playlists }
|
23
23
|
it { expect(channel.playlists.first).to be_a Yt::Playlist }
|
24
|
+
it { expect(channel.related_playlists).to be_a Yt::Collections::Playlists }
|
25
|
+
it { expect(channel.related_playlists.first).to be_a Yt::Playlist }
|
24
26
|
|
25
27
|
specify 'with a public list of subscriptions' do
|
26
28
|
expect(channel.subscribed_channels.first).to be_a Yt::Channel
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.25.
|
4
|
+
version: 0.25.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claudio Baccigalupo
|
@@ -152,6 +152,7 @@ files:
|
|
152
152
|
- lib/yt/collections/policies.rb
|
153
153
|
- lib/yt/collections/ratings.rb
|
154
154
|
- lib/yt/collections/references.rb
|
155
|
+
- lib/yt/collections/related_playlists.rb
|
155
156
|
- lib/yt/collections/reports.rb
|
156
157
|
- lib/yt/collections/resources.rb
|
157
158
|
- lib/yt/collections/resumable_sessions.rb
|