Implemented recursion fix for movies and tv shows (#283)

This applies the fix for issue #219 Incomplete libraries for movies and
TV shows.
For music items this was already fixed in PR #236
See commit 7330f85241
This commit is contained in:
Martijn Brekhof 2016-09-26 19:31:22 +02:00 committed by Synced Synapse
parent 080b5809f3
commit dadabd09c5
8 changed files with 53 additions and 52 deletions

View File

@ -23,6 +23,7 @@ import android.content.Context;
import org.xbmc.kore.host.HostInfo; import org.xbmc.kore.host.HostInfo;
import org.xbmc.kore.host.HostManager; import org.xbmc.kore.host.HostManager;
import org.xbmc.kore.jsonrpc.ApiException; import org.xbmc.kore.jsonrpc.ApiException;
import org.xbmc.kore.jsonrpc.ApiList;
import org.xbmc.kore.jsonrpc.method.AudioLibrary; import org.xbmc.kore.jsonrpc.method.AudioLibrary;
import org.xbmc.kore.jsonrpc.method.VideoLibrary; import org.xbmc.kore.jsonrpc.method.VideoLibrary;
import org.xbmc.kore.jsonrpc.type.AudioType; import org.xbmc.kore.jsonrpc.type.AudioType;
@ -68,15 +69,15 @@ public class Database {
private static void insertMovies(Context context, int hostId) throws ApiException, IOException { private static void insertMovies(Context context, int hostId) throws ApiException, IOException {
VideoLibrary.GetMovies getMovies = new VideoLibrary.GetMovies(); VideoLibrary.GetMovies getMovies = new VideoLibrary.GetMovies();
String result = Utils.readFile(context, "Video.Details.Movie.json"); String result = Utils.readFile(context, "Video.Details.Movie.json");
ArrayList<VideoType.DetailsMovie> movieList = (ArrayList) getMovies.resultFromJson(result); ApiList<VideoType.DetailsMovie> movieList = getMovies.resultFromJson(result);
ContentValues movieValuesBatch[] = new ContentValues[movieList.size()]; ContentValues movieValuesBatch[] = new ContentValues[movieList.items.size()];
int castCount = 0; int castCount = 0;
// Iterate on each movie // Iterate on each movie
for (int i = 0; i < movieList.size(); i++) { for (int i = 0; i < movieList.items.size(); i++) {
VideoType.DetailsMovie movie = movieList.get(i); VideoType.DetailsMovie movie = movieList.items.get(i);
movieValuesBatch[i] = SyncUtils.contentValuesFromMovie(hostId, movie); movieValuesBatch[i] = SyncUtils.contentValuesFromMovie(hostId, movie);
castCount += movie.cast.size(); castCount += movie.cast.size();
} }
@ -86,7 +87,7 @@ public class Database {
ContentValues movieCastValuesBatch[] = new ContentValues[castCount]; ContentValues movieCastValuesBatch[] = new ContentValues[castCount];
int count = 0; int count = 0;
// Iterate on each movie/cast // Iterate on each movie/cast
for (VideoType.DetailsMovie movie : movieList) { for (VideoType.DetailsMovie movie : movieList.items) {
for (VideoType.Cast cast : movie.cast) { for (VideoType.Cast cast : movie.cast) {
movieCastValuesBatch[count] = SyncUtils.contentValuesFromCast(hostId, cast); movieCastValuesBatch[count] = SyncUtils.contentValuesFromCast(hostId, cast);
movieCastValuesBatch[count].put(MediaContract.MovieCastColumns.MOVIEID, movie.movieid); movieCastValuesBatch[count].put(MediaContract.MovieCastColumns.MOVIEID, movie.movieid);

View File

@ -18,13 +18,9 @@ package org.xbmc.kore.testhelpers;
import android.database.Cursor; import android.database.Cursor;
import org.xbmc.kore.ui.SongsListFragment;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class TestUtils { public class TestUtils {

View File

@ -19,18 +19,6 @@ package org.xbmc.kore.tests.mediaprovider;
import android.database.Cursor; import android.database.Cursor;
import org.xbmc.kore.provider.MediaContract; import org.xbmc.kore.provider.MediaContract;
import org.xbmc.kore.provider.MediaDatabase;
import org.xbmc.kore.provider.MediaProvider;
import org.xbmc.kore.ui.AlbumListFragment;
import org.xbmc.kore.ui.ArtistListFragment;
import org.xbmc.kore.ui.ArtistOverviewFragment;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;

View File

@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import org.xbmc.kore.jsonrpc.ApiException; import org.xbmc.kore.jsonrpc.ApiException;
import org.xbmc.kore.jsonrpc.ApiList;
import org.xbmc.kore.jsonrpc.ApiMethod; import org.xbmc.kore.jsonrpc.ApiMethod;
import org.xbmc.kore.jsonrpc.type.ListType; import org.xbmc.kore.jsonrpc.type.ListType;
import org.xbmc.kore.jsonrpc.type.VideoType; import org.xbmc.kore.jsonrpc.type.VideoType;
@ -82,7 +83,7 @@ public class VideoLibrary {
/** /**
* Retrieve all movies * Retrieve all movies
*/ */
public static class GetMovies extends ApiMethod<List<VideoType.DetailsMovie>> { public static class GetMovies extends ApiMethod<ApiList<VideoType.DetailsMovie>> {
public final static String METHOD_NAME = "VideoLibrary.GetMovies"; public final static String METHOD_NAME = "VideoLibrary.GetMovies";
private final static String LIST_NODE = "movies"; private final static String LIST_NODE = "movies";
@ -118,13 +119,15 @@ public class VideoLibrary {
} }
@Override @Override
public List<VideoType.DetailsMovie> resultFromJson(ObjectNode jsonObject) public ApiList<VideoType.DetailsMovie> resultFromJson(ObjectNode jsonObject)
throws ApiException { throws ApiException {
ListType.LimitsReturned limits = new ListType.LimitsReturned(jsonObject);
JsonNode resultNode = jsonObject.get(RESULT_NODE); JsonNode resultNode = jsonObject.get(RESULT_NODE);
ArrayNode items = resultNode.has(LIST_NODE) ? ArrayNode items = resultNode.has(LIST_NODE) ?
(ArrayNode)resultNode.get(LIST_NODE) : null; (ArrayNode)resultNode.get(LIST_NODE) : null;
if (items == null) { if (items == null) {
return new ArrayList<VideoType.DetailsMovie>(0); return new ApiList<>(new ArrayList<VideoType.DetailsMovie>(0), limits);
} }
ArrayList<VideoType.DetailsMovie> result = new ArrayList<VideoType.DetailsMovie>(items.size()); ArrayList<VideoType.DetailsMovie> result = new ArrayList<VideoType.DetailsMovie>(items.size());
@ -132,7 +135,7 @@ public class VideoLibrary {
result.add(new VideoType.DetailsMovie(item)); result.add(new VideoType.DetailsMovie(item));
} }
return result; return new ApiList<>(result, limits);
} }
} }
@ -200,7 +203,7 @@ public class VideoLibrary {
/** /**
* Retrieve all TV Shows * Retrieve all TV Shows
*/ */
public static class GetTVShows extends ApiMethod<List<VideoType.DetailsTVShow>> { public static class GetTVShows extends ApiMethod<ApiList<VideoType.DetailsTVShow>> {
public final static String METHOD_NAME = "VideoLibrary.GetTVShows"; public final static String METHOD_NAME = "VideoLibrary.GetTVShows";
private final static String LIST_NODE = "tvshows"; private final static String LIST_NODE = "tvshows";
@ -235,21 +238,22 @@ public class VideoLibrary {
} }
@Override @Override
public List<VideoType.DetailsTVShow> resultFromJson(ObjectNode jsonObject) public ApiList<VideoType.DetailsTVShow> resultFromJson(ObjectNode jsonObject)
throws ApiException { throws ApiException {
ListType.LimitsReturned limits = new ListType.LimitsReturned(jsonObject);
JsonNode resultNode = jsonObject.get(RESULT_NODE); JsonNode resultNode = jsonObject.get(RESULT_NODE);
ArrayNode items = resultNode.has(LIST_NODE) ? ArrayNode items = resultNode.has(LIST_NODE) ?
(ArrayNode)resultNode.get(LIST_NODE) : null; (ArrayNode)resultNode.get(LIST_NODE) : null;
if (items == null) { if (items == null) {
return new ArrayList<VideoType.DetailsTVShow>(0); return new ApiList<>(new ArrayList<VideoType.DetailsTVShow>(0), limits);
} }
ArrayList<VideoType.DetailsTVShow> result = new ArrayList<VideoType.DetailsTVShow>(items.size()); ArrayList<VideoType.DetailsTVShow> result = new ArrayList<>(items.size());
for (JsonNode item : items) { for (JsonNode item : items) {
result.add(new VideoType.DetailsTVShow(item)); result.add(new VideoType.DetailsTVShow(item));
} }
return result; return new ApiList<>(result, limits);
} }
} }

View File

@ -22,6 +22,7 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import org.xbmc.kore.jsonrpc.ApiCallback; import org.xbmc.kore.jsonrpc.ApiCallback;
import org.xbmc.kore.jsonrpc.ApiList;
import org.xbmc.kore.jsonrpc.HostConnection; import org.xbmc.kore.jsonrpc.HostConnection;
import org.xbmc.kore.jsonrpc.method.VideoLibrary; import org.xbmc.kore.jsonrpc.method.VideoLibrary;
import org.xbmc.kore.jsonrpc.type.ListType; import org.xbmc.kore.jsonrpc.type.ListType;
@ -146,19 +147,24 @@ public class SyncMovies extends SyncItem {
// Call GetMovies with the current limits set // Call GetMovies with the current limits set
ListType.Limits limits = new ListType.Limits(startIdx, startIdx + LIMIT_SYNC_MOVIES); ListType.Limits limits = new ListType.Limits(startIdx, startIdx + LIMIT_SYNC_MOVIES);
VideoLibrary.GetMovies action = new VideoLibrary.GetMovies(limits, properties); VideoLibrary.GetMovies action = new VideoLibrary.GetMovies(limits, properties);
action.execute(hostConnection, new ApiCallback<List<VideoType.DetailsMovie>>() { action.execute(hostConnection, new ApiCallback<ApiList<VideoType.DetailsMovie>>() {
@Override @Override
public void onSuccess(List<VideoType.DetailsMovie> result) { public void onSuccess(ApiList<VideoType.DetailsMovie> result) {
ListType.LimitsReturned limitsReturned = null;
if (result != null) {
limitsReturned = result.limits;
}
if (startIdx == 0) { if (startIdx == 0) {
// First call, delete movies from DB // First call, delete movies from DB
deleteMovies(contentResolver, hostId, -1); deleteMovies(contentResolver, hostId, -1);
} }
if (!result.isEmpty()) { if (!result.items.isEmpty()) {
insertMovies(orchestrator, contentResolver, result); insertMovies(orchestrator, contentResolver, result.items);
} }
LogUtils.LOGD(TAG, "syncAllMovies, movies gotten: " + result.size()); LogUtils.LOGD(TAG, "syncAllMovies, movies gotten: " + result.items.size());
if (result.size() == LIMIT_SYNC_MOVIES) { if (SyncUtils.moreItemsAvailable(limitsReturned)) {
// Max limit returned, there may be some more movies // Max limit returned, there may be some more movies
// As we're going to recurse, these result objects can add up, so // As we're going to recurse, these result objects can add up, so
// let's help the GC and indicate that we don't need this memory // let's help the GC and indicate that we don't need this memory
@ -176,7 +182,7 @@ public class SyncMovies extends SyncItem {
@Override @Override
public void onError(int errorCode, String description) { public void onError(int errorCode, String description) {
// Ok, something bad happend, just quit // Ok, something bad happened, just quit
orchestrator.syncItemFailed(errorCode, description); orchestrator.syncItemFailed(errorCode, description);
} }
}, callbackHandler); }, callbackHandler);

View File

@ -118,7 +118,7 @@ public class SyncMusic extends SyncItem {
insertArtists(items, contentResolver); insertArtists(items, contentResolver);
if (moreItemsAvailable(limitsReturned)) { if (SyncUtils.moreItemsAvailable(limitsReturned)) {
LogUtils.LOGD(TAG, "chainCallSyncArtists: More results on media center, recursing."); LogUtils.LOGD(TAG, "chainCallSyncArtists: More results on media center, recursing.");
result = null; // Help the GC? result = null; // Help the GC?
chainCallSyncArtists(orchestrator, hostConnection, callbackHandler, contentResolver, chainCallSyncArtists(orchestrator, hostConnection, callbackHandler, contentResolver,
@ -235,7 +235,7 @@ public class SyncMusic extends SyncItem {
LogUtils.LOGD(TAG, "Finished inserting artists and genres in: " + LogUtils.LOGD(TAG, "Finished inserting artists and genres in: " +
(System.currentTimeMillis() - albumSyncStartTime)); (System.currentTimeMillis() - albumSyncStartTime));
if (moreItemsAvailable(limitsReturned)) { if (SyncUtils.moreItemsAvailable(limitsReturned)) {
LogUtils.LOGD(TAG, "chainCallSyncAlbums: More results on media center, recursing."); LogUtils.LOGD(TAG, "chainCallSyncAlbums: More results on media center, recursing.");
result = null; // Help the GC? result = null; // Help the GC?
chainCallSyncAlbums(orchestrator, hostConnection, callbackHandler, contentResolver, chainCallSyncAlbums(orchestrator, hostConnection, callbackHandler, contentResolver,
@ -302,7 +302,7 @@ public class SyncMusic extends SyncItem {
// Save partial results to DB // Save partial results to DB
insertSongsItems(items, contentResolver); insertSongsItems(items, contentResolver);
if (moreItemsAvailable(limitsReturned)) { if (SyncUtils.moreItemsAvailable(limitsReturned)) {
LogUtils.LOGD(TAG, "chainCallSyncSongs: More results on media center, recursing."); LogUtils.LOGD(TAG, "chainCallSyncSongs: More results on media center, recursing.");
result = null; // Help the GC? result = null; // Help the GC?
chainCallSyncSongs(orchestrator, hostConnection, callbackHandler, contentResolver, chainCallSyncSongs(orchestrator, hostConnection, callbackHandler, contentResolver,
@ -407,12 +407,4 @@ public class SyncMusic extends SyncItem {
contentResolver.bulkInsert(MediaContract.SongArtists.CONTENT_URI, songArtistsValuesBatch); contentResolver.bulkInsert(MediaContract.SongArtists.CONTENT_URI, songArtistsValuesBatch);
} }
private boolean moreItemsAvailable(ListType.LimitsReturned limitsReturned) {
boolean moreItemsAvailable = false;
if (limitsReturned != null) {
moreItemsAvailable = ( limitsReturned.total - limitsReturned.end ) > 0;
}
return moreItemsAvailable;
}
} }

View File

@ -23,6 +23,7 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import org.xbmc.kore.jsonrpc.ApiCallback; import org.xbmc.kore.jsonrpc.ApiCallback;
import org.xbmc.kore.jsonrpc.ApiList;
import org.xbmc.kore.jsonrpc.HostConnection; import org.xbmc.kore.jsonrpc.HostConnection;
import org.xbmc.kore.jsonrpc.method.VideoLibrary; import org.xbmc.kore.jsonrpc.method.VideoLibrary;
import org.xbmc.kore.jsonrpc.type.ListType; import org.xbmc.kore.jsonrpc.type.ListType;
@ -143,11 +144,11 @@ public class SyncTVShows extends SyncItem {
// Call GetTVShows with the current limits set // Call GetTVShows with the current limits set
ListType.Limits limits = new ListType.Limits(startIdx, startIdx + LIMIT_SYNC_TVSHOWS); ListType.Limits limits = new ListType.Limits(startIdx, startIdx + LIMIT_SYNC_TVSHOWS);
VideoLibrary.GetTVShows action = new VideoLibrary.GetTVShows(limits, getTVShowsProperties); VideoLibrary.GetTVShows action = new VideoLibrary.GetTVShows(limits, getTVShowsProperties);
action.execute(hostConnection, new ApiCallback<List<VideoType.DetailsTVShow>>() { action.execute(hostConnection, new ApiCallback<ApiList<VideoType.DetailsTVShow>>() {
@Override @Override
public void onSuccess(List<VideoType.DetailsTVShow> result) { public void onSuccess(ApiList<VideoType.DetailsTVShow> result) {
allResults.addAll(result); allResults.addAll(result.items);
if (result.size() == LIMIT_SYNC_TVSHOWS) { if (SyncUtils.moreItemsAvailable(result.limits)) {
// Max limit returned, there may be some more movies // Max limit returned, there may be some more movies
LogUtils.LOGD(TAG, "syncAllTVShows: More tv shows on media center, recursing."); LogUtils.LOGD(TAG, "syncAllTVShows: More tv shows on media center, recursing.");
syncAllTVShows(orchestrator, hostConnection, callbackHandler, contentResolver, syncAllTVShows(orchestrator, hostConnection, callbackHandler, contentResolver,

View File

@ -23,6 +23,7 @@ import android.content.ServiceConnection;
import android.os.IBinder; import android.os.IBinder;
import org.xbmc.kore.host.HostInfo; import org.xbmc.kore.host.HostInfo;
import org.xbmc.kore.jsonrpc.type.ListType;
import org.xbmc.kore.jsonrpc.type.VideoType; import org.xbmc.kore.jsonrpc.type.VideoType;
import org.xbmc.kore.jsonrpc.type.AudioType; import org.xbmc.kore.jsonrpc.type.AudioType;
import org.xbmc.kore.jsonrpc.type.LibraryType; import org.xbmc.kore.jsonrpc.type.LibraryType;
@ -476,4 +477,16 @@ public class SyncUtils {
return false; return false;
} }
/**
* Checks if there are more items available according to the limits returned
* @param limitsReturned
* @return true if there are more items available, false otherwise
*/
public static boolean moreItemsAvailable(ListType.LimitsReturned limitsReturned) {
if (limitsReturned != null) {
return ( limitsReturned.total - limitsReturned.end ) > 0;
}
return false;
}
} }