akoscz / YouTubePlaylist

A sample Android application which demonstrates the use of the YouTube Data v3 API.
Apache License 2.0
153 stars 84 forks source link

Get only last video of playlist #18

Closed Jhduou closed 7 years ago

Jhduou commented 7 years ago

Hello,

First, thank's for your project. I want to know if it's possible to take only the last video of a playlist ?

Thank you

akoscz commented 7 years ago

Hi @Jhduou, sure it's possible to only display the last video of the playlist. You would need to change some code do make that happen. If you are on the Master branch, you would most likely want to implement a new AsyncTask to download all the video items in the playlist all at once instead of the current paginated results. Once you have all the video items, then you would just return the last one in the list. You would also need to make changes in YouTubeRecyclerViewFragment.java to get rid of the pagination logic. Hope that helps.

akoscz commented 7 years ago

If you use the dependency-injection branch then it becomes a lot easier. This branch uses RxJava to perform the YouTube API calls. Using RxJava you can manipulate the API responses much easier than having to mess around with AsynTasks. Here's what you would do.

  1. Edit YouTubeRecyclerViewFragment.java and increase the YOUTUBE_PLAYLIST_MAX_RESULTS to 50. This is the max number of items that the YouTube API will allow in a playlist response.
    Then add a couple of extra operators to the Observable in the fetchPlaylist() method.
  2. Add a skipWhile operator to ignore playlist responses until we're on the last page. In other words, playlistItemListResponse.getNextPageToken() != null. When we're on the last page the next page token will be null.
  3. Then add a last() operator to the observable that maps the playlist items to videoId's. This will grab only the last videoId on the page of the playlist result.
  4. And lastly add a doOnTerminate() operator to recursively call fetchPlaylist() if we are not on the last page.

Here's a diff

diff --git a/app/src/main/java/com/akoscz/youtube/YouTubeRecyclerViewFragment.java b/app/src/main/java/com/akoscz/youtube/YouTubeRecyclerViewFragment.java
index d2f78cf..dd42ca1 100644
--- a/app/src/main/java/com/akoscz/youtube/YouTubeRecyclerViewFragment.java
+++ b/app/src/main/java/com/akoscz/youtube/YouTubeRecyclerViewFragment.java
@@ -54,7 +54,7 @@ public class YouTubeRecyclerViewFragment extends Fragment {
     private static final String YOUTUBE_VIDEOS_PART = "snippet,contentDetails,statistics"; // video resource properties that the response will include.
     private static final String YOUTUBE_VIDEOS_FIELDS = "items(id,snippet(title,description,thumbnails/high),contentDetails/duration,statistics)"; // selector specifying which fields to include in a partial response.
     // the max number of playlist results to receive per request
-    private static final Long YOUTUBE_PLAYLIST_MAX_RESULTS = 10L;
+    private static final Long YOUTUBE_PLAYLIST_MAX_RESULTS = 50L;
     // number of times to retry network operations
     private static final int RETRY_COUNT = 5;

@@ -157,9 +157,12 @@ public class YouTubeRecyclerViewFragment extends Fragment {
                 }
             }
         })
+        // skip processing the response if we're not on the last page
+        .skipWhile(playlistItemListResponse -> (playlistItemListResponse.getNextPageToken() != null))
         .flatMap(playlistItemListResponse -> {
             return Observable.from(playlistItemListResponse.getItems()) // emit list on stream
                     .map((PlaylistItem item) -> item.getSnippet().getResourceId().getVideoId()) // map to video ids
+                    .last() // grab only the last item in the list
                     .toList(); // flatten back to list
         })
         .map(videoIdsList -> {
@@ -183,6 +186,12 @@ public class YouTubeRecyclerViewFragment extends Fragment {
         .observeOn(AndroidSchedulers.mainThread())
         .retry(RETRY_COUNT) // retry before we give up
         .filter(videoListItems -> (videoListItems != null && videoListItems.size() != 0))
+        .doOnTerminate(() -> {
+            // if we're not on the last page, fetch the next page
+            if (mPlaylist.getNextPageToken() != null) {
+                fetchPlaylist();
+            }
+        })
         .subscribe(videoListItems -> {
             final int startPosition = mPlaylist.size();
             mPlaylist.addAll(videoListItems);

You can then do some cleanup of the rest of the code because you will no longer need any callbacks on the LastItemReachedListener. You can remove all references to it because there's no more pagination happening since we're recursively traversing all the pages in the playlist response.