package com.distantfuture.videos.youtube; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.text.TextUtils; import com.distantfuture.videos.database.YouTubeData; import com.distantfuture.videos.misc.Auth; import com.distantfuture.videos.misc.DUtils; import com.distantfuture.videos.misc.Utils; import com.google.android.youtube.player.YouTubeIntents; import com.google.android.youtube.player.YouTubeStandalonePlayer; import com.google.api.client.extensions.android.json.AndroidJsonFactory; import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAuthIOException; import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; import com.google.api.client.googleapis.json.GoogleJsonResponseException; import com.google.api.client.http.HttpRequestInitializer; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.services.youtube.YouTube; import com.google.api.services.youtube.model.Channel; import com.google.api.services.youtube.model.ChannelContentDetails; import com.google.api.services.youtube.model.ChannelListResponse; import com.google.api.services.youtube.model.Playlist; import com.google.api.services.youtube.model.PlaylistItem; import com.google.api.services.youtube.model.PlaylistItemListResponse; import com.google.api.services.youtube.model.PlaylistListResponse; import com.google.api.services.youtube.model.SearchListResponse; import com.google.api.services.youtube.model.SearchResult; import com.google.api.services.youtube.model.Subscription; import com.google.api.services.youtube.model.SubscriptionListResponse; import com.google.api.services.youtube.model.Thumbnail; import com.google.api.services.youtube.model.ThumbnailDetails; import com.google.api.services.youtube.model.Video; import com.google.api.services.youtube.model.VideoCategory; import com.google.api.services.youtube.model.VideoCategoryListResponse; import com.google.api.services.youtube.model.VideoListResponse; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; import java.util.Map; public class YouTubeAPI { public static final int REQ_PLAYER_CODE = 334443; private static final int mYouTubeMaxResultsLimit = 50; private boolean highQualityImages = true; private Context mContext; private YouTubeAPIListener mListener; private YouTube youTube; private boolean mUseAuthCredentials = false; // needs to check Content or something to get this for realz private boolean mUseDefaultAccount; public YouTubeAPI(Context context, boolean useAuthCredentials, boolean useDefaultAccount, YouTubeAPIListener listener) { super(); mListener = listener; mContext = context.getApplicationContext(); mUseAuthCredentials = useAuthCredentials; mUseDefaultAccount = useDefaultAccount; } public static void playMovie(Activity activity, String movieID, boolean fullScreen) { Intent intent = YouTubeStandalonePlayer.createVideoIntent(activity, Auth.devKey(), movieID, 0, true, !fullScreen); activity.startActivityForResult(intent, REQ_PLAYER_CODE); } public static void playMovieUsingIntent(Context context, String videoId) { Intent intent = YouTubeIntents.createPlayVideoIntent(context, videoId); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // need this to start activity if we just have a plain context (not an Activity) context.startActivity(intent); } public static void openPlaylistUsingIntent(Activity activity, String playlistId) { Intent intent = YouTubeIntents.createOpenPlaylistIntent(activity, playlistId); activity.startActivity(intent); } public static int youTubeMaxResultsLimit() { return mYouTubeMaxResultsLimit; } public YouTube youTube() { if (youTube == null) { try { HttpRequestInitializer credentials; if (mUseAuthCredentials) credentials = Auth.getCredentials(mContext, mUseDefaultAccount); else credentials = Auth.nullCredentials(mContext); youTube = new YouTube.Builder(new NetHttpTransport(), new AndroidJsonFactory(), credentials).setApplicationName("YouTubeAPI") .build(); } catch (Exception e) { e.printStackTrace(); } catch (Throwable t) { t.printStackTrace(); } } return youTube; } // pass null for your personal channelID public String channelID(String userName) { String result = null; try { YouTube.Channels.List channelRequest = youTube().channels().list("id"); if (userName != null) channelRequest.setForUsername(userName); // for example: JamesBurkeConnection else channelRequest.setMine(true); channelRequest.setMaxResults(1L); channelRequest.setFields("items/id"); channelRequest.setKey(Auth.devKey()); ChannelListResponse channelResult = channelRequest.execute(); List<Channel> channelsList = channelResult.getItems(); result = channelsList.get(0).getId(); } catch (UserRecoverableAuthIOException e) { handleException(e); } catch (Exception e) { handleException(e); } return result; } public VideosFromPlaylistResults videosFromPlaylistResults(String playlistID) { return new VideosFromPlaylistResults(playlistID); } public ChannelPlaylistsResults channelPlaylistsResults(String channelID, boolean addRelatedPlaylists) { return new ChannelPlaylistsResults(channelID, addRelatedPlaylists); } public PlaylistInfoListResults playlistInfoListResults(List<String> playlistIds) { return new PlaylistInfoListResults(playlistIds); } public SearchListResults searchListResults(String query, boolean searchChannels) { return new SearchListResults(query, searchChannels); } public SubscriptionListResults subscriptionListResults(boolean channelOnly) { return new SubscriptionListResults(channelOnly); } public CategoriesListResults categoriesListResults(String regionCode) { return new CategoriesListResults(regionCode); } public LikedVideosListResults likedVideosListResults() { return new LikedVideosListResults(); } public VideoInfoListResults videoInfoListResults(List<String> videoIds) { return new VideoInfoListResults(videoIds); } // pass null for channelid to get our own channel public String relatedPlaylistID(RelatedPlaylistType type, String channelID) { Map<RelatedPlaylistType, String> playlistMap = relatedPlaylistIDs(channelID); return playlistMap.get(type); } // pass null for channelid to get our own channel public List<YouTubeData> channelInfo(List<String> channelIds) { List<YouTubeData> result = new ArrayList<YouTubeData>(); try { YouTube.Channels.List channelRequest = youTube().channels().list("id, snippet"); if (channelIds != null) { channelRequest.setId(TextUtils.join(",", channelIds)); } else { channelRequest.setMine(true); } channelRequest.setFields(String.format("items(id, snippet/title, snippet/description, %s)", thumbnailField())); channelRequest.setKey(Auth.devKey()); ChannelListResponse channelResult = channelRequest.execute(); List<Channel> channelsList = channelResult.getItems(); if (channelsList != null) { for (Channel channel : channelsList) { YouTubeData data = new YouTubeData(); data.mChannel = channel.getId(); data.mTitle = channel.getSnippet().getTitle(); data.mDescription = channel.getSnippet() .getDescription(); // we want the returns, so don't strip data.mThumbnail = thumbnailURL(channel.getSnippet().getThumbnails()); result.add(data); } } } catch (UserRecoverableAuthIOException e) { handleException(e); } catch (Exception e) { handleException(e); } return result; } public String channelIdFromUsername(String userName) { String result = null; try { YouTube.Channels.List channelRequest = youTube().channels().list("id"); channelRequest.setForUsername(userName); channelRequest.setFields("items/id"); channelRequest.setKey(Auth.devKey()); ChannelListResponse channelResult = channelRequest.execute(); List<Channel> channelsList = channelResult.getItems(); if (channelsList != null) { for (Channel channel : channelsList) { result = channel.getId(); break; // we only want the first item? } } } catch (UserRecoverableAuthIOException e) { handleException(e); } catch (Exception e) { handleException(e); } return result; } private void doHandleAuthIntent(Intent authIntent) { Utils.toast(mContext, "Need Authorization"); if (mListener != null) mListener.handleAuthIntent(authIntent); } private void doHandleExceptionMessage(String message) { Utils.toast(mContext, message); } // pass null for channelid to get our own channel private Map<RelatedPlaylistType, String> relatedPlaylistIDs(String channelID) { Map<RelatedPlaylistType, String> result = new EnumMap<RelatedPlaylistType, String>(RelatedPlaylistType.class); try { YouTube.Channels.List channelRequest = youTube().channels().list("contentDetails"); if (channelID != null) { channelRequest.setId(channelID); } else { channelRequest.setMine(true); } channelRequest.setFields("items/contentDetails, nextPageToken"); channelRequest.setKey(Auth.devKey()); ChannelListResponse channelResult = channelRequest.execute(); List<Channel> channelsList = channelResult.getItems(); if (channelsList != null) { ChannelContentDetails.RelatedPlaylists relatedPlaylists = channelsList.get(0) .getContentDetails() .getRelatedPlaylists(); result.put(RelatedPlaylistType.FAVORITES, relatedPlaylists.getFavorites()); result.put(RelatedPlaylistType.LIKES, relatedPlaylists.getLikes()); result.put(RelatedPlaylistType.UPLOADS, relatedPlaylists.getUploads()); result.put(RelatedPlaylistType.WATCHED, relatedPlaylists.getWatchHistory()); result.put(RelatedPlaylistType.WATCHLATER, relatedPlaylists.getWatchLater()); } } catch (UserRecoverableAuthIOException e) { handleException(e); } catch (Exception e) { handleException(e); } return result; } public List<YouTubeData> relatedPlaylists(String channelID) { List<YouTubeData> related = new ArrayList<YouTubeData>(); Map<RelatedPlaylistType, String> playlistMap = relatedPlaylistIDs(channelID); for (Map.Entry<RelatedPlaylistType, String> entry : playlistMap.entrySet()) { String playlistID = entry.getValue(); if (playlistID != null) { YouTubeData map = new YouTubeData(); map.mPlaylist = playlistID; switch (entry.getKey()) { case FAVORITES: map.mTitle = "Favorites"; break; case LIKES: map.mTitle = "LIKES"; break; case UPLOADS: map.mTitle = "UPLOADS"; break; case WATCHED: map.mTitle = "WATCHED"; break; case WATCHLATER: map.mTitle = "WATCHLATER"; break; } related.add(map); } } return related; } private void handleException(Exception e) { if (e.getClass().equals(UserRecoverableAuthIOException.class)) { UserRecoverableAuthIOException r = (UserRecoverableAuthIOException) e; Intent intent = null; try { intent = r.getIntent(); } catch (Exception ee) { // ignore, this happens if we kill the activity quickly before our async task finishes } if (intent != null) doHandleAuthIntent(intent); } else if (e.getClass().equals(GoogleAuthIOException.class)) { // could be a bad user name, let's pass it to the listener to check doHandleAuthIntent(null); } else if (e.getClass().equals(GoogleJsonResponseException.class)) { GoogleJsonResponseException r = (GoogleJsonResponseException) e; e.printStackTrace(); doHandleExceptionMessage("JSON Error: " + r.getDetails().getCode() + " : " + r.getDetails() .getMessage()); } else { doHandleExceptionMessage("Exception Occurred: " + e.toString()); e.printStackTrace(); } } private String thumbnailField() { String result = "snippet/thumbnails/default/url"; if (highQualityImages) result = "snippet/thumbnails/high/url"; return result; } private String thumbnailURL(ThumbnailDetails details) { String result = null; if (details != null) { Thumbnail thumbnail = details.getMaxres(); // is this necessary? not sure if (thumbnail == null) { thumbnail = details.getHigh(); } if (thumbnail == null) { thumbnail = details.getDefault(); } if (thumbnail != null) { result = thumbnail.getUrl(); } } return result; } public enum RelatedPlaylistType {FAVORITES, LIKES, UPLOADS, WATCHED, WATCHLATER} public interface YouTubeAPIListener { public void handleAuthIntent(final Intent authIntent); } // ======================================================== // VideoListResults public class VideosFromPlaylistResults extends BaseListResults { private String mPlaylistID; public VideosFromPlaylistResults(String playlistID) { super(); mPlaylistID = playlistID; mPart = "contentDetails"; mFields = "items(contentDetails/videoId), nextPageToken"; } protected List<YouTubeData> itemsForNextToken(String token, long maxResults) { List<PlaylistItem> playlistItemList = null; if (mPlaylistID != null) { try { YouTube.PlaylistItems.List listRequest = youTube().playlistItems().list(mPart); listRequest.setPlaylistId(mPlaylistID); listRequest.setFields(mFields); listRequest.setPageToken(token); listRequest.setMaxResults(maxResults); listRequest.setKey(Auth.devKey()); PlaylistItemListResponse playListResponse = listRequest.execute(); playlistItemList = playListResponse.getItems(); response = playListResponse; } catch (UserRecoverableAuthIOException e) { handleResultsException(e); } catch (Exception e) { handleResultsException(e); } } return itemsToMap(playlistItemList); } private List<YouTubeData> itemsToMap(List<PlaylistItem> playlistItemList) { // check parameters if (playlistItemList == null) return null; List<YouTubeData> result = new ArrayList<YouTubeData>(); // convert the list into hash maps of video info for (PlaylistItem playlistItem : playlistItemList) { YouTubeData map = new YouTubeData(); map.mVideo = playlistItem.getContentDetails().getVideoId(); result.add(map); } return result; } } // ======================================================== // SearchListResults public class SearchListResults extends BaseListResults { private String query; private boolean searchChannels = false; public SearchListResults(String query, boolean searchChannels) { this.searchChannels = searchChannels; this.query = query; mPart = "id, snippet"; String idType = "videoId"; if (searchChannels) idType = "channelId"; mFields = String.format("items(id/%s, snippet/title, snippet/description, %s), nextPageToken", idType, thumbnailField()); } protected List<YouTubeData> itemsForNextToken(String token, long maxResults) { List<SearchResult> result = new ArrayList<SearchResult>(); SearchListResponse searchListResponse; try { YouTube.Search.List listRequest = youTube().search().list(mPart); listRequest.setQ(query); listRequest.setKey(Auth.devKey()); listRequest.setType(searchChannels ? "channel" : "video"); listRequest.setFields(mFields); listRequest.setMaxResults(maxResults); listRequest.setPageToken(token); searchListResponse = listRequest.execute(); // nasty double cast? response = searchListResponse; result.addAll(searchListResponse.getItems()); } catch (UserRecoverableAuthIOException e) { handleResultsException(e); } catch (Exception e) { handleResultsException(e); } return itemsToMap(result); } private List<YouTubeData> itemsToMap(List<SearchResult> playlistItemList) { List<YouTubeData> result = new ArrayList<YouTubeData>(); // convert the list into hash maps of video info for (SearchResult playlistItem : playlistItemList) { YouTubeData map = new YouTubeData(); if (searchChannels) map.mChannel = playlistItem.getId().getChannelId(); else map.mVideo = playlistItem.getId().getVideoId(); map.mTitle = playlistItem.getSnippet().getTitle(); map.mDescription = Utils.condenseWhiteSpace(playlistItem.getSnippet().getDescription()); map.mThumbnail = thumbnailURL(playlistItem.getSnippet().getThumbnails()); result.add(map); } return result; } } // ======================================================== // LikedVideosListResults public class LikedVideosListResults extends BaseListResults { public LikedVideosListResults() { mPart = "id, snippet, contentDetails"; mFields = String.format("items(id, snippet/title, snippet/description, contentDetails/duration, %s), nextPageToken", thumbnailField()); } protected List<YouTubeData> itemsForNextToken(String token, long maxResults) { List<Video> result = new ArrayList<Video>(); VideoListResponse searchListResponse; try { YouTube.Videos.List listRequest = youTube().videos().list(mPart); listRequest.setKey(Auth.devKey()); listRequest.setFields(mFields); listRequest.setMyRating("like"); listRequest.setMaxResults(maxResults); listRequest.setPageToken(token); searchListResponse = listRequest.execute(); // nasty double cast? response = searchListResponse; result.addAll(searchListResponse.getItems()); } catch (UserRecoverableAuthIOException e) { handleResultsException(e); } catch (Exception e) { handleResultsException(e); } return itemsToMap(result); } private List<YouTubeData> itemsToMap(List<Video> playlistItemList) { List<YouTubeData> result = new ArrayList<YouTubeData>(); // convert the list into hash maps of video info for (Video playlistItem : playlistItemList) { YouTubeData map = new YouTubeData(); map.mVideo = playlistItem.getId(); map.mTitle = playlistItem.getSnippet().getTitle(); map.mDescription = Utils.condenseWhiteSpace(playlistItem.getSnippet().getDescription()); map.mThumbnail = thumbnailURL(playlistItem.getSnippet().getThumbnails()); map.mDuration = Utils.durationToDuration((String) playlistItem.getContentDetails() .get("duration")); result.add(map); } return result; } } // ======================================================== // VideoInfoListResults public class VideoInfoListResults extends BaseListResults { List<String> mVideoIds; public VideoInfoListResults(List<String> videoIds) { mVideoIds = videoIds; if (mVideoIds.size() > mYouTubeMaxResultsLimit) { DUtils.log("VideoInfoListResults can only handle 50 videos at a time."); mVideoIds = videoIds.subList(0, mYouTubeMaxResultsLimit); } mPart = "id, contentDetails, snippet"; mFields = String.format("items(id, contentDetails/duration, snippet/title, snippet/description, snippet/publishedAt, %s)", thumbnailField()); } protected List<YouTubeData> itemsForNextToken(String tokenNotUsed, long maxResultsNotUsed) { List<Video> result = new ArrayList<Video>(); VideoListResponse searchListResponse; try { YouTube.Videos.List listRequest = youTube().videos().list(mPart); listRequest.setKey(Auth.devKey()); listRequest.setFields(mFields); listRequest.setId(TextUtils.join(",", mVideoIds)); searchListResponse = listRequest.execute(); result.addAll(searchListResponse.getItems()); } catch (UserRecoverableAuthIOException e) { handleResultsException(e); } catch (Exception e) { handleResultsException(e); } return itemsToMap(result); } private List<YouTubeData> itemsToMap(List<Video> playlistItemList) { List<YouTubeData> result = new ArrayList<YouTubeData>(); // convert the list into hash maps of video info for (Video playlistItem : playlistItemList) { YouTubeData map = new YouTubeData(); map.mVideo = playlistItem.getId(); map.mDuration = Utils.durationToDuration((String) playlistItem.getContentDetails() .get("duration")); map.mTitle = playlistItem.getSnippet().getTitle(); map.mDescription = Utils.condenseWhiteSpace(playlistItem.getSnippet().getDescription()); map.mThumbnail = thumbnailURL(playlistItem.getSnippet().getThumbnails()); map.mPublishedDate = playlistItem.getSnippet().getPublishedAt().getValue(); result.add(map); } return result; } } // ======================================================== // CategoriesListResults public class CategoriesListResults extends BaseListResults { String mRegionCode; public CategoriesListResults(String regionCode) { mPart = "snippet"; mFields = "items(snippet/title, snippet/channelId)"; mRegionCode = regionCode; } protected List<YouTubeData> itemsForNextToken(String token, long maxResults) { List<VideoCategory> result = new ArrayList<VideoCategory>(); VideoCategoryListResponse categoryListResponse; try { YouTube.VideoCategories.List listRequest = youTube().videoCategories().list(mPart); listRequest.setKey(Auth.devKey()); listRequest.setRegionCode(mRegionCode); listRequest.setFields(mFields); categoryListResponse = listRequest.execute(); result.addAll(categoryListResponse.getItems()); response = categoryListResponse; } catch (UserRecoverableAuthIOException e) { handleResultsException(e); } catch (Exception e) { handleResultsException(e); } return itemsToMap(result); } private List<YouTubeData> itemsToMap(List<VideoCategory> itemList) { List<YouTubeData> result = new ArrayList<YouTubeData>(); // convert the list into hash maps of video info for (VideoCategory category : itemList) { YouTubeData map = new YouTubeData(); map.mChannel = category.getSnippet().getChannelId(); map.mTitle = category.getSnippet().getTitle(); result.add(map); } return result; } } // ======================================================== // SubscriptionListResults public class SubscriptionListResults extends BaseListResults { private boolean channelOnly; public SubscriptionListResults(boolean channelOnly) { super(); this.channelOnly = channelOnly; mPart = "snippet"; mFields = String.format("items(snippet/title, snippet/resourceId, snippet/description, %s), nextPageToken", thumbnailField()); if (channelOnly) mFields = String.format("items(snippet/resourceId), nextPageToken"); } protected List<YouTubeData> itemsForNextToken(String token, long maxResults) { List<Subscription> result = new ArrayList<Subscription>(); try { YouTube.Subscriptions.List listRequest = youTube().subscriptions().list(mPart); listRequest.setMine(true); listRequest.setFields(mFields); listRequest.setMaxResults(maxResults); listRequest.setKey(Auth.devKey()); listRequest.setPageToken(token); SubscriptionListResponse subscriptionListResponse = listRequest.execute(); response = subscriptionListResponse; result.addAll(subscriptionListResponse.getItems()); } catch (UserRecoverableAuthIOException e) { handleResultsException(e); } catch (Exception e) { handleResultsException(e); } return itemsToMap(result); } private List<YouTubeData> itemsToMap(List<Subscription> subscriptionsList) { List<YouTubeData> result = new ArrayList<YouTubeData>(); // convert the list into hash maps of video info for (Subscription subscription : subscriptionsList) { YouTubeData map = new YouTubeData(); if (channelOnly) { map.mChannel = subscription.getSnippet().getResourceId().getChannelId(); } else { map.mTitle = subscription.getSnippet().getTitle(); map.mChannel = subscription.getSnippet().getResourceId().getChannelId(); map.mDescription = Utils.condenseWhiteSpace(subscription.getSnippet().getDescription()); map.mThumbnail = thumbnailURL(subscription.getSnippet().getThumbnails()); } result.add(map); } return result; } } // ======================================================== // ChannelPlaylistsResults public class ChannelPlaylistsResults extends BaseListResults { private String mChannelID; public ChannelPlaylistsResults(String channelID, boolean addRelated) { super(); mChannelID = channelID; mPart = "id"; mFields = String.format("items(id), nextPageToken"); } protected List<YouTubeData> itemsForNextToken(String token, long maxResults) { List<Playlist> result = new ArrayList<Playlist>(); try { YouTube.Playlists.List listRequest = youTube().playlists().list(mPart); // if channel null, assume the users channel if (mChannelID == null) listRequest.setMine(true); else listRequest.setChannelId(mChannelID); listRequest.setFields(mFields); listRequest.setMaxResults(maxResults); listRequest.setKey(Auth.devKey()); listRequest.setPageToken(token); PlaylistListResponse subscriptionListResponse = listRequest.execute(); response = subscriptionListResponse; result.addAll(subscriptionListResponse.getItems()); } catch (UserRecoverableAuthIOException e) { handleResultsException(e); } catch (Exception e) { handleResultsException(e); } return itemsToMap(result); } private List<YouTubeData> itemsToMap(List<Playlist> playlists) { List<YouTubeData> result = new ArrayList<YouTubeData>(); // convert the list into hash maps of video info for (Playlist playlist : playlists) { YouTubeData map = new YouTubeData(); map.mPlaylist = playlist.getId(); result.add(map); } return result; } } // ======================================================== // PlaylistInfoListResults public class PlaylistInfoListResults extends BaseListResults { List<String> mPlaylistIds; public PlaylistInfoListResults(List<String> playlistIds) { mPlaylistIds = playlistIds; if (mPlaylistIds.size() > mYouTubeMaxResultsLimit) { DUtils.log("VideoInfoListResults can only handle 50 videos at a time."); mPlaylistIds = mPlaylistIds.subList(0, mYouTubeMaxResultsLimit); } mPart = "id, snippet, contentDetails"; mFields = String.format("items(id, contentDetails/itemCount, snippet/title, snippet/description, snippet/publishedAt, %s)", thumbnailField()); } protected List<YouTubeData> itemsForNextToken(String tokenNotUsed, long maxResultsNotUsed) { List<Playlist> result = new ArrayList<Playlist>(); try { YouTube.Playlists.List listRequest = youTube().playlists().list(mPart); listRequest.setFields(mFields); listRequest.setKey(Auth.devKey()); listRequest.setId(TextUtils.join(",", mPlaylistIds)); PlaylistListResponse subscriptionListResponse = listRequest.execute(); response = subscriptionListResponse; result.addAll(subscriptionListResponse.getItems()); } catch (UserRecoverableAuthIOException e) { handleResultsException(e); } catch (Exception e) { handleResultsException(e); } return itemsToMap(result); } private List<YouTubeData> itemsToMap(List<Playlist> playlists) { List<YouTubeData> result = new ArrayList<YouTubeData>(); // convert the list into hash maps of video info for (Playlist playlist : playlists) { YouTubeData map = new YouTubeData(); map.mPlaylist = playlist.getId(); map.mTitle = playlist.getSnippet().getTitle(); map.mItemCount = playlist.getContentDetails().getItemCount(); map.mDescription = Utils.condenseWhiteSpace(playlist.getSnippet().getDescription()); map.mThumbnail = thumbnailURL(playlist.getSnippet().getThumbnails()); map.mPublishedDate = playlist.getSnippet().getPublishedAt().getValue(); result.add(map); } return result; } } // ======================================================== // BaseListResults abstract public class BaseListResults { protected Object response; protected String mPart; protected String mFields; public BaseListResults() { super(); } // subclasses must implement abstract protected List<YouTubeData> itemsForNextToken(String token, long maxResults); public List<YouTubeData> getItems(long maxResults) { return getNext(maxResults); } // we need all items at once if we reverse sort, otherwise the top items in the list will jump // down as more data is loaded and look annoying. YouTube API doesn't support sorting, so we must do this crap public List<YouTubeData> getAllItems(int maxResults) { List<YouTubeData> result = new ArrayList<YouTubeData>(); long maxToRequest = maxResults; while (true) { List<YouTubeData> items = getItems(maxToRequest); if (items.size() == 0) break; else { result.addAll(items); // break out if we reached the max requested if (maxResults != 0) { if (result.size() >= maxResults) { // could truncate results, but not that concerned about exact size break; } else { maxToRequest = maxResults - result.size(); } } } } return result; } private List<YouTubeData> getNext(long maxResults) { List<YouTubeData> result = new ArrayList<YouTubeData>(); if (maxResults <= 0 || maxResults > mYouTubeMaxResultsLimit) maxResults = mYouTubeMaxResultsLimit; // youTube limit String token = nextToken(); if (token != null) { List<YouTubeData> newItems = itemsForNextToken(token, maxResults); if (newItems != null) { result.addAll(newItems); } } else { // no more tokens, we are done done(); } return result; } private String nextToken() { String result = null; if (response == null) result = ""; // first time else { // is there a better way of doing this? if (response instanceof SearchListResponse) { result = ((SearchListResponse) response).getNextPageToken(); } else if (response instanceof PlaylistItemListResponse) { result = ((PlaylistItemListResponse) response).getNextPageToken(); } else if (response instanceof SubscriptionListResponse) { result = ((SubscriptionListResponse) response).getNextPageToken(); } else if (response instanceof VideoListResponse) { result = ((VideoListResponse) response).getNextPageToken(); } else if (response instanceof PlaylistListResponse) { result = ((PlaylistListResponse) response).getNextPageToken(); } else { doHandleExceptionMessage("nextToken bug!"); } } return result; } private void done() { response = null; // avoid trying to get nextToken or possibly retriggering an exception } protected void handleResultsException(Exception e) { // must call done otherwise we get an endless loop as it continues to retry since it thinks there are still items to fetch done(); handleException(e); } } }