diff --git a/proto/youtube.js b/proto/youtube.js index 3b82e27..1547522 100644 --- a/proto/youtube.js +++ b/proto/youtube.js @@ -3,15 +3,15 @@ const { search_sort, search_filters, search, search_continuation, search_options } = require('./build/youtube_pb'); -function bin_b64(binary){ - return Buffer.from(binary).toString('base64').replaceAll('+', '-').replaceAll('/', '_'); +function binary_to_b64_no_pad(binary){ + return Buffer.from(binary).toString('base64url'); } -function binary_to_b64_no_pad(binary){ - var str = bin_b64(binary), - index = str.indexOf('='); - if(index != -1) - str = str.substring(0, index); +function bin_b64(binary){ + var str = binary_to_b64_no_pad(binary); + + while(str.length & 3) + str += '='; return str; } @@ -19,7 +19,32 @@ function binary_to_b64url(binary){ return encodeURIComponent(bin_b64(binary)); } +function b64url_to_binary(input){ + return Buffer.from(decodeURIComponent(input), 'base64'); +} + module.exports = { + playlist_next_offset(continuation){ + var p = playlist.deserializeBinary(b64url_to_binary(continuation)); + var cont = p.getContinuation(); + + if(!cont) + return undefined; + var params = cont.getParams(); + + if(!params) + return undefined; + params = playlist_params.deserializeBinary(b64url_to_binary(params)); + + var offset = params.getOffset(); + + if(!offset) + return undefined; + var p_offset = playlist_offset.deserializeBinary(b64url_to_binary(offset.substring('PT:'.length))); + + return p_offset.getOffset(); + }, + gen_playlist_continuation(id, offset){ var p_offset = new playlist_offset(), p_params = new playlist_params(), p_cont = new playlist.playlist_continuation(), p = new playlist(); diff --git a/src/api/Youtube.js b/src/api/Youtube.js index 7fb8e68..a0b6e6a 100755 --- a/src/api/Youtube.js +++ b/src/api/Youtube.js @@ -3,7 +3,7 @@ const Request = require('../Request'); const SourceError = require('../SourceError'); const {Track, TrackImage, TrackResults, TrackPlaylist, TrackStream, TrackStreams} = require('../Track'); -const {gen_playlist_continuation, gen_search_options} = require('../../proto/youtube'); +const {gen_playlist_continuation, gen_search_options, playlist_next_offset} = require('../../proto/youtube'); function get_property(array, prop){ if(!(array instanceof Array)) @@ -174,7 +174,7 @@ class YoutubePlaylist extends TrackPlaylist{ for(var item of data){ if(item.continuationItemRenderer) - this.next_offset = offset + this.length; + this.next_offset = playlist_next_offset(item.continuationItemRenderer.continuationEndpoint.continuationCommand.token); else if(item.playlistVideoRenderer) this.push(new YoutubeTrack().from_playlist(item.playlistVideoRenderer)); }