nullscreen / yt

The reliable YouTube API Ruby client
MIT License
738 stars 159 forks source link

How to specify which page I want to see when I search? #104

Closed hakunin closed 9 years ago

hakunin commented 9 years ago

Hi, I am switching from youtube_it and to avoid too much rewriting I need to be able to search with page attribute, is that somehow possible?

That is, when I say page: 1 I get only the first page and so on.

claudiofullscreen commented 9 years ago

@hakunin YouTube API V3 changed the way in which pagination works.

Unfortunately, it does not let you go directly to a specific page (such as page 3): each page includes a nextPageToken that only lets you go to the next page.

In other words, if you want to see the results from page 3 with YouTube API V3, you have to load page 1, read the nextPageToken, obtain page 2 with this token, read the new nextPageToken, and with this finally obtain page 3.

If you could tell me which endpoint you are trying to get, I can help you write the code with Yt. Thanks!

hakunin commented 9 years ago

Thanks, now I see why its not in the gem.

Would it be possible to get only the first page somehow and then get each other page via separate call?

I am importing videos from youtube and need to slice it somehow.

claudiofullscreen commented 9 years ago

@hakunin What you get back with .videos is an Enumerator which automatically loads the next page from the YouTube API as required, so you don't have to.

Therefore, when you use Yt, you don't have to worry about "how many pages" to data to load, just how many "items" you want to load.

If the number of items you want to load is less than the maximum number of items that YouTube returns per page (50), then Yt will only make one call to the YouTube API. If it's between 51 and 100, then Yt will make 2 calls to the API and so on. All of this is transparent to you.


Here is an example:

Say you want to load the videos from this channel.

First you might want to know how many videos this channel has in total:

# Set your key/secret here
channel = Yt::Channel.new id: 'UCsmvakQZlvGsyjyOhmhvOsw'
channel.videos.size
# curl -X GET -H "content-length: 0" -H "user-agent: Yt::Request (gzip)" "https://www.googleapis.com/youtube/v3/search?channelId=UCsmvakQZlvGsyjyOhmhvOsw&key=...&maxResults=50&order=date&part=snippet&type=video"
# => 1031

As you can see the channel has 1,031 videos.

Now if you only want to retrieve the first 10, you can simply type:

channel.videos.each.with_index do |video, i|
  p "Video #{i+1}: #{video.title}"
  break if i == 9
end  
# curl -X GET -H "content-length: 0" -H "user-agent: Yt::Request (gzip)" "https://www.googleapis.com/youtube/v3/search?channelId=UCsmvakQZlvGsyjyOhmhvOsw&key=...&maxResults=50&order=date&part=snippet&type=video"
# "Video 1: Dying Light - Dying Highlight TRAPS (PS4)"
# "Video 2: Samurai Warriors Chronicle 3 『戦国無双 Chronicle 3』 - Promotional Video [Japan] (PS Vita)"
# "Video 3: Phantasy Star Online 2 -  Episode 3 PV [Japan] (PS Vita)"
# "Video 4: Dead or Alive 5 Last Round - RAIDOU vs AYANE [1080p/60fps] (PS4, PS3)"
# "Video 5: Dead or Alive 5 Last Round - RAIDOU vs HAYATE [1080p/60fps] (PS4, PS3)"
# "Video 6: Dead or Alive 5 Last Round - RAIDOU vs RYU HAYABUSA [1080p/60fps] (PS4, PS3)"
# "Video 7: Dead or Alive 5 Last Round - Raidou Reveal Trailer (PS4, PS3)"
# "Video 8: Gunship X - Announcement Trailer (PS4, PS Vita)"
# "Video 9: Monster Hunter Frontier G6 - Promotional Movie [Japan] (PS Vita, PS3)"
# "Video 10: htoL#NiQ: The Firefly Diary - New Gameplay Trailer (PS Vita)"

As you can see, only one request to the YouTube API was made because you requested less than 50 videos (which is the maximum number of items returned by YouTube per page).

If you ask for more, you will see more requests being made: just remember to set Yt.configuration.log_level = "devel" to see the curl request in your output.

Was this helpful?

hakunin commented 9 years ago

Thanks, while its nice that this is handled for me, its complicating things when I need to grab videos from channel which has a few thousands of them, but thats mostly because youtube ditched the simple pagination.

Is it possible to read the next page token from the enumerator somehow?

claudiofullscreen commented 9 years ago

The next page token is stored in an instance variable on the enumerator that is not part of the public API of YT.

In other words, you can access it with the following code, but the following code is not guaranteed to work in future versions :sweat_smile: – I did not create a public method because I never had to need to access it.

channel = Yt::Channel.new id: 'UCsmvakQZlvGsyjyOhmhvOsw'
channel.videos.first
channel.videos.instance_variable_get :@page_token
# => "CDIQAA"

That is the the page token that will let you get the second page of results (50–100). Once you read them, the instance variable gets updated, and so on.

hakunin commented 9 years ago

Thanks! This will be handy.

bmalets commented 9 years ago

Hi all, I see that it's pretty old closed issue, but currently I'm trying to resolve similar problem. I have read a documentation and didn't found any example of pagination requests for videos. But I see in source of gem methods like next_page or where which may help me.

For example, if there are a channel with more than 500 videos and I want to receive per one request: 15 videos and next_page_token to the next 15 videos. So, is it somehow possible to change maxResults and nextPageToken parameters?

I need something like:

channel = Yt::Channel.new id: 'UCsmvakQZlvGsyjyOhmhvOsw'
channel.videos.first(15)
token = channel.videos.instance_variable_get :@page_token
puts token
# => nil :(

Thanks kindly, and sorry for disturbing!