1

I want to get all of the YouTube videos in a specified playlist. The API currently allows you to pull 50 records at a time but you can pull the next set of records by passing a next page token.

I am still new to Angular and I am having trouble accomplishing this task.

Here is what I currently have:

var app = angular.module('ph', []);
        var key = '';

        app.factory('youtubeService', ['$http', function ($http) {

            function getPlaylists(channelId) {
                return $.get("https://www.googleapis.com/youtube/v3/playlists", { part: 'snippet', channelId: channelId, key: key, maxResults: 50 });
            }

            function getPlaylistVideos(playlistId) {

                var items = [];
                var nextPageToken = "";

                $.get('https://www.googleapis.com/youtube/v3/playlistItems', { part: 'snippet', maxResults: 50, playlistId: playlistId, key: key }).then(function (firstResponse) {

                    items = firstResponse.items;
                    var numberOfPages = Math.ceil(firstResponse.pageInfo.totalResults / 50);

                    for (var page = 1; page <= numberOfPages; page++) {
                        $.get('https://www.googleapis.com/youtube/v3/playlistItems', { part: 'snippet', maxResults: 50, pageToken: nextPageToken, playlistId: playlistId, key: key }).then(function(response) {
                            items = items.concat(response.items);
                            nextPageToken = response.nextPageToken;
                        });
                    }
                });

                return items;
            }

            function getVideos(keyword) {
                return $.get('https://www.googleapis.com/youtube/v3/search', { part: 'snippet', q: keyword, key: key, type: 'video' });
            }

            return { getPlaylists: getPlaylists, getPlaylistVideos: getPlaylistVideos, getVideos: getVideos }

        }]);


        app.controller('ctrl', ['$http', '$scope', 'youtubeService', function ($http, $scope, youtubeService) {

            youtubeService.getPlaylists('UC-9-kyTW8ZkZNDHQJ6FgpwQ').then(function (response) {
                $scope.$apply(function () {
                    $scope.playlists = response.items;
                });
            });

            $scope.getPlaylistVideos = function (selection) {
                youtubeService.getPlaylistVideos(selection.id).then(function (response) {
                    $scope.$apply(function () {
                        $scope.playlistvideos = response.items;
                    });
                });
            }

            $scope.getVideos = function (selection) {
                youtubeService.getVideos(selection).then(function (response) {
                    $scope.$apply(function () {
                        $scope.videos = response.items;
                    });
                });
            }
        }]);

What do I need to do to the getPlaylistVideos function to get it to return all of the videos in a playlist? Rather than just 50.

This is the code that I had before for just returning first page:

function getPlaylistVideos(playlistId) {
    return $.get('https://www.googleapis.com/youtube/v3/playlistItems', { part: 'snippet', maxResults: 50, playlistId: playlistId, key: key});
}

An example playlist id is PLFPg_IUxqnZNTAbUMEZ76_snWd-ED5en7.

Any help is much appreciated!

Modified Answer

$scope.getPlaylistVideos = function (selection) {
    // pass the nextPageToken attribute to the getPlaylistVideos method.
    youtubeService.getPlaylistVideos("PLFPg_IUxqnZNTAbUMEZ76_snWd-ED5en7", $scope.nextPageToken).then(function (response) {
        $scope.$apply(function () {
            angular.forEach(response.items, function (item) {
                $scope.playlistvideos.push(item);
            });

            if (typeof response.nextPageToken != 'undefined') {
                $scope.nextPageToken = response.nextPageToken;
                // call the get playlist function again
                $scope.getPlaylistVideos(selection);
            }
        });
    });
}
Aaron
  • 1,061
  • 3
  • 14
  • 22
  • Possible duplicate of [Retrieve all videos from youtube playlist using youtube v3 API](http://stackoverflow.com/questions/18804904/retrieve-all-videos-from-youtube-playlist-using-youtube-v3-api) – Sandeep Sukhija Jun 23 '16 at 05:38
  • @SandeepSukhija I saw that question but I am looking for help with the angular portion of it. I already know about the pagination and my code is attempting to use it. I am just not sure how to modify my function so I can get it to work using Angular – Aaron Jun 23 '16 at 05:52
  • @Aaron I know this is quite an old question, but do you have a better working example of the above? Or a sample of it in action? – Dan Whiteside May 25 '17 at 10:42

1 Answers1

2

You need to use the pageToken attribute to fetch the next page.

From the documentation, Use the nextPageToken attribute from the api response.Call the API one or more times to retrieve all items in the list. As long as the API response returns a nextPageToken, there are still more items to retrieve.

In your controller, define a local variable nextPageToken to retrieve the next page and call the getPlaylistVideos with the nextPageToken attribute recursively until all the results are retrieved.

app.controller('ctrl', ['$http', '$scope', 'youtubeService', function ($http, $scope, youtubeService) {

        // define a local variable pageToken, it is gonna be undefined for the first time and will be initialized with next page token after subsequent responses
        $scope.nextPageToken;
        $scope.playlistVideos = [];

        youtubeService.getPlaylists('UC-9-kyTW8ZkZNDHQJ6FgpwQ').then(function (response) {
            $scope.$apply(function () {
                $scope.playlists = response.items;
            });
        });

        $scope.getPlaylistVideos = function (selection) {
            // pass the nextPageToken attribute to the getPlaylistVideos method.
            youtubeService.getPlaylistVideos(selection.id, $scope.nextPageToken).then(function (response) {
                $scope.$apply(function () {
                    $scope.playlistVideos.push(response.items);

                    if(typeof response.nextPageToken != 'undefined'){
                          $scope.nextPageToken = response.nextPageToken;
                          // call the get playlist function again
                          $scope.getPlaylistVideos(selection);
                    } 
                });
            });
        }

        $scope.getVideos = function (selection) {
            youtubeService.getVideos(selection).then(function (response) {
                $scope.$apply(function () {
                    $scope.videos = response.items;
                });
            });
        }
}]);

In your service, pass the pageToken attribute to the api to fetch the next page.

function getPlaylistVideos(playlistId, pageToken) {
...
     // pass the page token as a parameter to the API
     $.get('https://www.googleapis.com/youtube/v3/playlistItems', { part: 'snippet', maxResults: 50, playlistId: playlistId, key: key, pageToken: pageToken })
...
}
Sandeep Sukhija
  • 1,156
  • 16
  • 30
  • I have tried adding your code and it still does not seem to work. In the getPlaylistVideos shouldn't it be returning something? Also, should the recursive call have the nextpage token in the parameter. Is this working on your end? – Aaron Jun 24 '16 at 00:00
  • Have updated answer. The function `getPlaylistVideos` doesn't return anything, it updates the `$scope.playlistVideos` variable with the fetched playlist items. Also the function `getPlaylistVideos` uses the scope variable `nextPageToken` to fetch next page. – Sandeep Sukhija Jun 24 '16 at 07:27
  • So had to add the return to the getPlaylistVideos as well as push the items onto the array rather pushing an actual array to playlistvideos. I have added my change to my question. really appreciate your help. – Aaron Jun 25 '16 at 01:55