Changed library sync to include limits when getting media info from media center

This commit is contained in:
Synced Synapse 2015-01-18 12:31:55 +00:00
parent 850e9809e2
commit 56ef1a9497
4 changed files with 403 additions and 180 deletions

View File

@ -22,6 +22,7 @@ import com.syncedsynapse.kore2.jsonrpc.ApiException;
import com.syncedsynapse.kore2.jsonrpc.ApiMethod;
import com.syncedsynapse.kore2.jsonrpc.type.AudioType;
import com.syncedsynapse.kore2.jsonrpc.type.LibraryType;
import com.syncedsynapse.kore2.jsonrpc.type.ListType;
import java.util.ArrayList;
import java.util.List;
@ -102,6 +103,23 @@ public class AudioLibrary {
addParameterToRequest("properties", properties);
}
/**
* Retrieve all artists with limits
*
* @param limits Limits to retrieve. See {@link ListType.Limits}
* @param albumartistsonly Whether or not to include artists only appearing in
* compilations. If the parameter is not passed or is passed as
* null the GUI setting will be used
* @param properties Properties to retrieve. See {@link AudioType.FieldsArtists} for a
* list of accepted values
*/
public GetArtists(ListType.Limits limits, boolean albumartistsonly, String... properties) {
super();
addParameterToRequest("limits", limits);
addParameterToRequest("albumartistsonly", albumartistsonly);
addParameterToRequest("properties", properties);
}
@Override
public String getMethodName() {
return METHOD_NAME;
@ -135,7 +153,7 @@ public class AudioLibrary {
private final static String LIST_NODE = "albums";
/**
* Retrieve all albums from specified artist or genre
* Retrieve all albums
*
* @param properties Properties to retrieve. See {@link AudioType.FieldsAlbum} for a
* list of accepted values
@ -145,6 +163,19 @@ public class AudioLibrary {
addParameterToRequest("properties", properties);
}
/**
* Retrieve all albums with limits
*
* @param limits Limits to retrieve. See {@link ListType.Limits}
* @param properties Properties to retrieve. See {@link AudioType.FieldsAlbum} for a
* list of accepted values
*/
public GetAlbums(ListType.Limits limits, String... properties) {
super();
addParameterToRequest("limits", limits);
addParameterToRequest("properties", properties);
}
@Override
public String getMethodName() {
return METHOD_NAME;
@ -219,7 +250,7 @@ public class AudioLibrary {
private final static String LIST_NODE = "songs";
/**
* Retrieve all songs from specified album, artist or genre
* Retrieve all songs
*
* @param properties Properties to retrieve. See {@link AudioType.FieldsSong} for a
* list of accepted values
@ -229,6 +260,19 @@ public class AudioLibrary {
addParameterToRequest("properties", properties);
}
/**
* Retrieve all songs with limits
*
* @param limits Limits to retrieve. See {@link ListType.Limits}
* @param properties Properties to retrieve. See {@link AudioType.FieldsSong} for a
* list of accepted values
*/
public GetSongs(ListType.Limits limits, String... properties) {
super();
addParameterToRequest("limits", limits);
addParameterToRequest("properties", properties);
}
@Override
public String getMethodName() {
return METHOD_NAME;

View File

@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.syncedsynapse.kore2.jsonrpc.ApiException;
import com.syncedsynapse.kore2.jsonrpc.ApiMethod;
import com.syncedsynapse.kore2.jsonrpc.type.ListType;
import com.syncedsynapse.kore2.jsonrpc.type.VideoType;
import java.util.ArrayList;
@ -87,7 +88,8 @@ public class VideoLibrary {
private final static String LIST_NODE = "movies";
/**
* Retrieve all movies
* Retrieve all movies, without limits
* Caution, this can break in large libraries
*
* @param properties Properties to retrieve. See {@link VideoType.FieldsMovie} for a list of
* accepted values
@ -97,6 +99,19 @@ public class VideoLibrary {
addParameterToRequest("properties", properties);
}
/**
* Retrieve all movies, with limits
*
* @param limits Limits to retrieve. See {@link ListType.Limits}
* @param properties Properties to retrieve. See {@link VideoType.FieldsMovie} for a list of
* accepted values
*/
public GetMovies(ListType.Limits limits, String... properties) {
super();
addParameterToRequest("properties", properties);
addParameterToRequest("limits", limits);
}
@Override
public String getMethodName() {
return METHOD_NAME;
@ -201,6 +216,19 @@ public class VideoLibrary {
addParameterToRequest("properties", properties);
}
/**
* Retrieve all tv shows, with limits
*
* @param limits Limits to retrieve. See {@link ListType.Limits}
* @param properties Properties to retrieve. See {@link VideoType.FieldsMovie} for a list of
* accepted values
*/
public GetTVShows(ListType.Limits limits, String... properties) {
super();
addParameterToRequest("properties", properties);
addParameterToRequest("limits", limits);
}
@Override
public String getMethodName() {
return METHOD_NAME;

View File

@ -16,6 +16,8 @@
package com.syncedsynapse.kore2.jsonrpc.type;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.syncedsynapse.kore2.utils.JsonUtils;
import java.util.List;
@ -310,6 +312,33 @@ public class ListType {
}
}
/**
* List.Limits
*/
public static class Limits
implements ApiParameter {
public static final String START = "start";
public static final String END = "end";
protected static final ObjectMapper objectMapper = new ObjectMapper();
public final int start;
public final int end;
public Limits(int start, int end) {
this.start = start;
this.end = end;
}
public JsonNode toJsonNode() {
final ObjectNode node = objectMapper.createObjectNode();
node.put(START, start);
node.put(END, end);
return node;
}
}
/**
* Enums for List.Fields.All
*/

View File

@ -35,6 +35,7 @@ import com.syncedsynapse.kore2.jsonrpc.event.MediaSyncEvent;
import com.syncedsynapse.kore2.jsonrpc.method.*;
import com.syncedsynapse.kore2.jsonrpc.type.AudioType;
import com.syncedsynapse.kore2.jsonrpc.type.LibraryType;
import com.syncedsynapse.kore2.jsonrpc.type.ListType;
import com.syncedsynapse.kore2.jsonrpc.type.VideoType;
import com.syncedsynapse.kore2.provider.MediaContract;
import com.syncedsynapse.kore2.utils.LogUtils;
@ -53,6 +54,12 @@ import de.greenrobot.event.EventBus;
public class LibrarySyncService extends Service {
public static final String TAG = LogUtils.makeLogTag(LibrarySyncService.class);
private static final int LIMIT_SYNC_MOVIES = 300;
private static final int LIMIT_SYNC_TVSHOWS = 300;
private static final int LIMIT_SYNC_ARTISTS = 300;
private static final int LIMIT_SYNC_ALBUMS = 300;
private static final int LIMIT_SYNC_SONGS = 600;
/**
* Possible requests to sync
*/
@ -362,7 +369,6 @@ public class LibrarySyncService extends Service {
return syncExtras;
}
/** {@inheritDoc} */
public void sync(final SyncOrchestrator orchestrator,
final HostConnection hostConnection,
@ -391,21 +397,7 @@ public class LibrarySyncService extends Service {
};
if (movieId == -1) {
// Delete and sync all movies
VideoLibrary.GetMovies action = new VideoLibrary.GetMovies(properties);
action.execute(hostConnection, new ApiCallback<List<VideoType.DetailsMovie>>() {
@Override
public void onSucess(List<VideoType.DetailsMovie> result) {
deleteMovies(contentResolver, hostId, -1);
insertMovies(orchestrator, contentResolver, result);
}
@Override
public void onError(int errorCode, String description) {
// Ok, something bad happend, just quit
orchestrator.syncItemFailed(errorCode, description);
}
}, callbackHandler);
syncAllMovies(orchestrator, hostConnection, callbackHandler, contentResolver, properties, 0);
} else {
// Sync a specific movie
VideoLibrary.GetMovieDetails action =
@ -417,6 +409,7 @@ public class LibrarySyncService extends Service {
List<VideoType.DetailsMovie> movies = new ArrayList<VideoType.DetailsMovie>(1);
movies.add(result);
insertMovies(orchestrator, contentResolver, movies);
orchestrator.syncItemFinished();
}
@Override
@ -428,6 +421,60 @@ public class LibrarySyncService extends Service {
}
}
/**
* Syncs all the movies, calling itself recursively
* Uses the {@link VideoLibrary.GetMovies} version with limits to make sure
* that Kodi doesn't blow up, and calls itself recursively until all the
* movies are returned
*/
private void syncAllMovies(final SyncOrchestrator orchestrator,
final HostConnection hostConnection,
final Handler callbackHandler,
final ContentResolver contentResolver,
final String properties[],
final int startIdx) {
// Call GetMovies with the current limits set
ListType.Limits limits = new ListType.Limits(startIdx, startIdx + LIMIT_SYNC_MOVIES);
VideoLibrary.GetMovies action = new VideoLibrary.GetMovies(limits, properties);
action.execute(hostConnection, new ApiCallback<List<VideoType.DetailsMovie>>() {
@Override
public void onSucess(List<VideoType.DetailsMovie> result) {
if (startIdx == 0) {
// First call, delete movies from DB
deleteMovies(contentResolver, hostId, -1);
}
if (result.size() > 0) {
insertMovies(orchestrator, contentResolver, result);
}
LogUtils.LOGD(TAG, "syncAllMovies, movies gotten: " + result.size());
if (result.size() == LIMIT_SYNC_MOVIES) {
// Max limit returned, there may be some more movies
// 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
// (hopefully this works)
result = null;
syncAllMovies(orchestrator, hostConnection, callbackHandler, contentResolver,
properties, startIdx + LIMIT_SYNC_MOVIES);
} else {
// Less than the limit was returned so we can finish
// (if it returned more there's a bug in Kodi but it
// shouldn't be a problem as they got inserted in the DB)
orchestrator.syncItemFinished();
}
}
@Override
public void onError(int errorCode, String description) {
// Ok, something bad happend, just quit
orchestrator.syncItemFailed(errorCode, description);
}
}, callbackHandler);
}
/**
* Deletes one or all movies from the database (pass -1 on movieId to delete all)
*/
private void deleteMovies(final ContentResolver contentResolver,
int hostId, int movieId) {
if (movieId == -1) {
@ -446,6 +493,9 @@ public class LibrarySyncService extends Service {
}
}
/**
* Inserts the given movies in the database
*/
private void insertMovies(final SyncOrchestrator orchestrator,
final ContentResolver contentResolver,
final List<VideoType.DetailsMovie> movies) {
@ -475,8 +525,6 @@ public class LibrarySyncService extends Service {
// Insert the cast list for this movie
contentResolver.bulkInsert(MediaContract.MovieCast.CONTENT_URI, movieCastValuesBatch);
orchestrator.syncItemFinished();
}
}
@ -526,45 +574,30 @@ public class LibrarySyncService extends Service {
return syncExtras;
}
private final static String getTVShowsProperties[] = {
VideoType.FieldsTVShow.TITLE, VideoType.FieldsTVShow.GENRE,
//VideoType.FieldsTVShow.YEAR,
VideoType.FieldsTVShow.RATING, VideoType.FieldsTVShow.PLOT,
VideoType.FieldsTVShow.STUDIO, VideoType.FieldsTVShow.MPAA,
VideoType.FieldsTVShow.CAST, VideoType.FieldsTVShow.PLAYCOUNT,
VideoType.FieldsTVShow.EPISODE, VideoType.FieldsTVShow.IMDBNUMBER,
VideoType.FieldsTVShow.PREMIERED,
//VideoType.FieldsTVShow.VOTES, VideoType.FieldsTVShow.LASTPLAYED,
VideoType.FieldsTVShow.FANART, VideoType.FieldsTVShow.THUMBNAIL,
VideoType.FieldsTVShow.FILE,
//VideoType.FieldsTVShow.ORIGINALTITLE, VideoType.FieldsTVShow.SORTTITLE,
// VideoType.FieldsTVShow.EPISODEGUIDE, VideoType.FieldsTVShow.SEASON,
VideoType.FieldsTVShow.WATCHEDEPISODES, VideoType.FieldsTVShow.DATEADDED,
//VideoType.FieldsTVShow.TAG, VideoType.FieldsTVShow.ART
};
/** {@inheritDoc} */
public void sync(final SyncOrchestrator orchestrator,
final HostConnection hostConnection,
final Handler callbackHandler,
final ContentResolver contentResolver) {
String getTVShowsProperties[] = {
VideoType.FieldsTVShow.TITLE, VideoType.FieldsTVShow.GENRE,
//VideoType.FieldsTVShow.YEAR,
VideoType.FieldsTVShow.RATING, VideoType.FieldsTVShow.PLOT,
VideoType.FieldsTVShow.STUDIO, VideoType.FieldsTVShow.MPAA,
VideoType.FieldsTVShow.CAST, VideoType.FieldsTVShow.PLAYCOUNT,
VideoType.FieldsTVShow.EPISODE, VideoType.FieldsTVShow.IMDBNUMBER,
VideoType.FieldsTVShow.PREMIERED,
//VideoType.FieldsTVShow.VOTES, VideoType.FieldsTVShow.LASTPLAYED,
VideoType.FieldsTVShow.FANART, VideoType.FieldsTVShow.THUMBNAIL,
VideoType.FieldsTVShow.FILE,
//VideoType.FieldsTVShow.ORIGINALTITLE, VideoType.FieldsTVShow.SORTTITLE,
// VideoType.FieldsTVShow.EPISODEGUIDE, VideoType.FieldsTVShow.SEASON,
VideoType.FieldsTVShow.WATCHEDEPISODES, VideoType.FieldsTVShow.DATEADDED,
//VideoType.FieldsTVShow.TAG, VideoType.FieldsTVShow.ART
};
if (tvshowId == -1) {
// Sync all tvshows
VideoLibrary.GetTVShows action = new VideoLibrary.GetTVShows(getTVShowsProperties);
action.execute(hostConnection, new ApiCallback<List<VideoType.DetailsTVShow>>() {
@Override
public void onSucess(List<VideoType.DetailsTVShow> result) {
deleteTVShows(contentResolver, hostId, -1);
insertTVShowsAndGetDetails(orchestrator, hostConnection, callbackHandler,
contentResolver, result);
}
@Override
public void onError(int errorCode, String description) {
// Ok, something bad happend, just quit
orchestrator.syncItemFailed(errorCode, description);
}
}, callbackHandler);
syncAllTVShows(orchestrator, hostConnection, callbackHandler, contentResolver,
0, new ArrayList<VideoType.DetailsTVShow>());
} else {
VideoLibrary.GetTVShowDetails action =
new VideoLibrary.GetTVShowDetails(tvshowId, getTVShowsProperties);
@ -577,6 +610,7 @@ public class LibrarySyncService extends Service {
tvShows.add(result);
insertTVShowsAndGetDetails(orchestrator, hostConnection, callbackHandler,
contentResolver, tvShows);
// insertTVShows calls syncItemFinished
}
@Override
@ -588,6 +622,47 @@ public class LibrarySyncService extends Service {
}
}
/**
* Syncs all the TV shows, calling itself recursively
* Uses the {@link VideoLibrary.GetTVShows} version with limits to make sure
* that Kodi doesn't blow up, and calls itself recursively until all the
* shows are returned
*/
private void syncAllTVShows(final SyncOrchestrator orchestrator,
final HostConnection hostConnection,
final Handler callbackHandler,
final ContentResolver contentResolver,
final int startIdx,
final List<VideoType.DetailsTVShow> allResults) {
// Call GetTVShows with the current limits set
ListType.Limits limits = new ListType.Limits(startIdx, startIdx + LIMIT_SYNC_TVSHOWS);
VideoLibrary.GetTVShows action = new VideoLibrary.GetTVShows(limits, getTVShowsProperties);
action.execute(hostConnection, new ApiCallback<List<VideoType.DetailsTVShow>>() {
@Override
public void onSucess(List<VideoType.DetailsTVShow> result) {
allResults.addAll(result);
if (result.size() == LIMIT_SYNC_TVSHOWS) {
// Max limit returned, there may be some more movies
LogUtils.LOGD(TAG, "syncAllTVShows: More tv shows on media center, recursing.");
syncAllTVShows(orchestrator, hostConnection, callbackHandler, contentResolver,
startIdx + LIMIT_SYNC_TVSHOWS, allResults);
} else {
// Ok, we have all the shows, insert them
LogUtils.LOGD(TAG, "syncAllTVShows: Got all tv shows");
deleteTVShows(contentResolver, hostId, -1);
insertTVShowsAndGetDetails(orchestrator, hostConnection, callbackHandler,
contentResolver, allResults);
}
}
@Override
public void onError(int errorCode, String description) {
// Ok, something bad happend, just quit
orchestrator.syncItemFailed(errorCode, description);
}
}, callbackHandler);
}
private void deleteTVShows(final ContentResolver contentResolver,
int hostId, int tvshowId) {
if (tvshowId == -1) {
@ -833,37 +908,61 @@ public class LibrarySyncService extends Service {
final HostConnection hostConnection,
final Handler callbackHandler,
final ContentResolver contentResolver) {
String getArtistsProperties[] = {
// AudioType.FieldsArtists.INSTRUMENT, AudioType.FieldsArtists.STYLE,
// AudioType.FieldsArtists.MOOD, AudioType.FieldsArtists.BORN,
// AudioType.FieldsArtists.FORMED,
AudioType.FieldsArtists.DESCRIPTION,
AudioType.FieldsArtists.GENRE,
// AudioType.FieldsArtists.DIED,
// AudioType.FieldsArtists.DISBANDED, AudioType.FieldsArtists.YEARSACTIVE,
//AudioType.FieldsArtists.MUSICBRAINZARTISTID,
AudioType.FieldsArtists.FANART,
AudioType.FieldsArtists.THUMBNAIL
};
chainCallSyncArtists(orchestrator, hostConnection, callbackHandler, contentResolver,
0, new ArrayList<AudioType.DetailsArtist>());
}
private final static String getArtistsProperties[] = {
// AudioType.FieldsArtists.INSTRUMENT, AudioType.FieldsArtists.STYLE,
// AudioType.FieldsArtists.MOOD, AudioType.FieldsArtists.BORN,
// AudioType.FieldsArtists.FORMED,
AudioType.FieldsArtists.DESCRIPTION,
AudioType.FieldsArtists.GENRE,
// AudioType.FieldsArtists.DIED,
// AudioType.FieldsArtists.DISBANDED, AudioType.FieldsArtists.YEARSACTIVE,
//AudioType.FieldsArtists.MUSICBRAINZARTISTID,
AudioType.FieldsArtists.FANART,
AudioType.FieldsArtists.THUMBNAIL
};
/**
* Gets all artists recursively and forwards the call to Genres
* Genres->Albums->Songs
*/
public void chainCallSyncArtists(final SyncOrchestrator orchestrator,
final HostConnection hostConnection,
final Handler callbackHandler,
final ContentResolver contentResolver,
final int startIdx,
final List<AudioType.DetailsArtist> allResults) {
// Artists->Genres->Albums->Songs
// Only gets album artists (first parameter)
AudioLibrary.GetArtists action = new AudioLibrary.GetArtists(true, getArtistsProperties);
ListType.Limits limits = new ListType.Limits(startIdx, startIdx + LIMIT_SYNC_ARTISTS);
AudioLibrary.GetArtists action = new AudioLibrary.GetArtists(limits, true, getArtistsProperties);
action.execute(hostConnection, new ApiCallback<List<AudioType.DetailsArtist>>() {
@Override
public void onSucess(List<AudioType.DetailsArtist> result) {
// First delete all music info
deleteMusicInfo(contentResolver, hostId);
allResults.addAll(result);
if (result.size() == LIMIT_SYNC_ARTISTS) {
// Max limit returned, there may be some more
LogUtils.LOGD(TAG, "chainCallSyncArtists: More results on media center, recursing.");
chainCallSyncArtists(orchestrator, hostConnection, callbackHandler, contentResolver,
startIdx + LIMIT_SYNC_ARTISTS, allResults);
} else {
// Ok, we have all the shows, insert them
LogUtils.LOGD(TAG, "chainCallSyncArtists: Got all results, continuing");
ContentValues artistValuesBatch[] = new ContentValues[result.size()];
for (int i = 0; i < result.size(); i++) {
AudioType.DetailsArtist artist = result.get(i);
artistValuesBatch[i] = SyncUtils.contentValuesFromArtist(hostId, artist);
// First delete all music info
deleteMusicInfo(contentResolver, hostId);
ContentValues artistValuesBatch[] = new ContentValues[allResults.size()];
for (int i = 0; i < allResults.size(); i++) {
AudioType.DetailsArtist artist = allResults.get(i);
artistValuesBatch[i] = SyncUtils.contentValuesFromArtist(hostId, artist);
}
// Insert the artists and continue the syncing
contentResolver.bulkInsert(MediaContract.Artists.CONTENT_URI, artistValuesBatch);
chainCallSyncGenres(orchestrator, hostConnection, callbackHandler, contentResolver);
}
// Insert the artists and continue the syncing
contentResolver.bulkInsert(MediaContract.Artists.CONTENT_URI, artistValuesBatch);
chainCallSyncGenres(orchestrator, hostConnection, callbackHandler, contentResolver);
}
@Override
@ -893,6 +992,9 @@ public class LibrarySyncService extends Service {
}
private final static String getGenresProperties[] = {
LibraryType.FieldsGenre.TITLE, LibraryType.FieldsGenre.THUMBNAIL
};
/**
* Syncs Audio genres and forwards calls to sync albums:
* Genres->Albums->Songs
@ -901,10 +1003,6 @@ public class LibrarySyncService extends Service {
final HostConnection hostConnection,
final Handler callbackHandler,
final ContentResolver contentResolver) {
String getGenresProperties[] = {
LibraryType.FieldsGenre.TITLE, LibraryType.FieldsGenre.THUMBNAIL
};
// Genres->Albums->Songs
AudioLibrary.GetGenres action = new AudioLibrary.GetGenres(getGenresProperties);
action.execute(hostConnection, new ApiCallback<List<LibraryType.DetailsGenre>>() {
@ -920,7 +1018,8 @@ public class LibrarySyncService extends Service {
// Insert the genres
contentResolver.bulkInsert(MediaContract.AudioGenres.CONTENT_URI, genresValuesBatch);
chainCallSyncAlbums(orchestrator, hostConnection, callbackHandler, contentResolver);
chainCallSyncAlbums(orchestrator, hostConnection, callbackHandler, contentResolver,
0, new ArrayList<AudioType.DetailsAlbum>());
}
@Override
@ -931,89 +1030,100 @@ public class LibrarySyncService extends Service {
}, callbackHandler);
}
private static final String getAlbumsProperties[] = {
AudioType.FieldsAlbum.TITLE, AudioType.FieldsAlbum.DESCRIPTION,
AudioType.FieldsAlbum.ARTIST, AudioType.FieldsAlbum.GENRE,
//AudioType.FieldsAlbum.THEME, AudioType.FieldsAlbum.MOOD,
//AudioType.FieldsAlbum.STYLE, AudioType.FieldsAlbum.TYPE,
AudioType.FieldsAlbum.ALBUMLABEL, AudioType.FieldsAlbum.RATING,
AudioType.FieldsAlbum.YEAR,
//AudioType.FieldsAlbum.MUSICBRAINZALBUMID,
//AudioType.FieldsAlbum.MUSICBRAINZALBUMARTISTID,
AudioType.FieldsAlbum.FANART, AudioType.FieldsAlbum.THUMBNAIL,
AudioType.FieldsAlbum.PLAYCOUNT, AudioType.FieldsAlbum.GENREID,
AudioType.FieldsAlbum.ARTISTID, AudioType.FieldsAlbum.DISPLAYARTIST
};
/**
* Syncs Albums and forwards calls to sync songs:
* Syncs Albums recursively and forwards calls to sync songs:
* Albums->Songs
*/
private void chainCallSyncAlbums(final SyncOrchestrator orchestrator,
final HostConnection hostConnection,
final Handler callbackHandler,
final ContentResolver contentResolver) {
String getAlbumsProperties[] = {
AudioType.FieldsAlbum.TITLE, AudioType.FieldsAlbum.DESCRIPTION,
AudioType.FieldsAlbum.ARTIST, AudioType.FieldsAlbum.GENRE,
//AudioType.FieldsAlbum.THEME, AudioType.FieldsAlbum.MOOD,
//AudioType.FieldsAlbum.STYLE, AudioType.FieldsAlbum.TYPE,
AudioType.FieldsAlbum.ALBUMLABEL, AudioType.FieldsAlbum.RATING,
AudioType.FieldsAlbum.YEAR,
//AudioType.FieldsAlbum.MUSICBRAINZALBUMID,
//AudioType.FieldsAlbum.MUSICBRAINZALBUMARTISTID,
AudioType.FieldsAlbum.FANART, AudioType.FieldsAlbum.THUMBNAIL,
AudioType.FieldsAlbum.PLAYCOUNT, AudioType.FieldsAlbum.GENREID,
AudioType.FieldsAlbum.ARTISTID, AudioType.FieldsAlbum.DISPLAYARTIST
};
final ContentResolver contentResolver,
final int startIdx,
final List<AudioType.DetailsAlbum> allResults) {
final long albumSyncStartTime = System.currentTimeMillis();
// Albums->Songs
AudioLibrary.GetAlbums action = new AudioLibrary.GetAlbums(getAlbumsProperties);
ListType.Limits limits = new ListType.Limits(startIdx, startIdx + LIMIT_SYNC_ALBUMS);
AudioLibrary.GetAlbums action = new AudioLibrary.GetAlbums(limits, getAlbumsProperties);
action.execute(hostConnection, new ApiCallback<List<AudioType.DetailsAlbum>>() {
@Override
public void onSucess(List<AudioType.DetailsAlbum> result) {
ContentValues albumValuesBatch[] = new ContentValues[result.size()];
allResults.addAll(result);
if (result.size() == LIMIT_SYNC_ALBUMS) {
// Max limit returned, there may be some more
LogUtils.LOGD(TAG, "chainCallSyncAlbums: More results on media center, recursing.");
chainCallSyncAlbums(orchestrator, hostConnection, callbackHandler, contentResolver,
startIdx + LIMIT_SYNC_ALBUMS, allResults);
} else {
// Ok, we have all the shows, insert them
LogUtils.LOGD(TAG, "chainCallSyncAlbums: Got all results, continuing");
int artistsCount = 0;
int genresCount = 0;
for (int i = 0; i < result.size(); i++) {
AudioType.DetailsAlbum album = result.get(i);
albumValuesBatch[i] = SyncUtils.contentValuesFromAlbum(hostId, album);
ContentValues albumValuesBatch[] = new ContentValues[allResults.size()];
int artistsCount = 0;
int genresCount = 0;
for (int i = 0; i < allResults.size(); i++) {
AudioType.DetailsAlbum album = allResults.get(i);
albumValuesBatch[i] = SyncUtils.contentValuesFromAlbum(hostId, album);
artistsCount += album.artistid.size();
genresCount += album.genreid.size();
}
LogUtils.LOGD(TAG, "Finished parsing albums in: " +
(System.currentTimeMillis() - albumSyncStartTime));
// Insert the albums
contentResolver.bulkInsert(MediaContract.Albums.CONTENT_URI, albumValuesBatch);
LogUtils.LOGD(TAG, "Finished inserting albums in: " +
(System.currentTimeMillis() - albumSyncStartTime));
// Iterate on each album, collect the artists and the genres and insert them
ContentValues albumArtistsValuesBatch[] = new ContentValues[artistsCount];
ContentValues albumGenresValuesBatch[] = new ContentValues[genresCount];
int artistCount = 0, genreCount = 0;
for (AudioType.DetailsAlbum album : result) {
for (int artistId : album.artistid) {
albumArtistsValuesBatch[artistCount] = new ContentValues();
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.HOST_ID, hostId);
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.ALBUMID, album.albumid);
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.ARTISTID, artistId);
artistCount++;
artistsCount += album.artistid.size();
genresCount += album.genreid.size();
}
for (int genreId : album.genreid) {
albumGenresValuesBatch[genreCount] = new ContentValues();
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.HOST_ID, hostId);
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.ALBUMID, album.albumid);
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.GENREID, genreId);
genreCount++;
LogUtils.LOGD(TAG, "Finished parsing albums in: " +
(System.currentTimeMillis() - albumSyncStartTime));
// Insert the albums
contentResolver.bulkInsert(MediaContract.Albums.CONTENT_URI, albumValuesBatch);
LogUtils.LOGD(TAG, "Finished inserting albums in: " +
(System.currentTimeMillis() - albumSyncStartTime));
// Iterate on each album, collect the artists and the genres and insert them
ContentValues albumArtistsValuesBatch[] = new ContentValues[artistsCount];
ContentValues albumGenresValuesBatch[] = new ContentValues[genresCount];
int artistCount = 0, genreCount = 0;
for (AudioType.DetailsAlbum album : allResults) {
for (int artistId : album.artistid) {
albumArtistsValuesBatch[artistCount] = new ContentValues();
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.HOST_ID, hostId);
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.ALBUMID, album.albumid);
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.ARTISTID, artistId);
artistCount++;
}
for (int genreId : album.genreid) {
albumGenresValuesBatch[genreCount] = new ContentValues();
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.HOST_ID, hostId);
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.ALBUMID, album.albumid);
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.GENREID, genreId);
genreCount++;
}
}
LogUtils.LOGD(TAG, "Finished parsing artists and genres in: " +
(System.currentTimeMillis() - albumSyncStartTime));
contentResolver.bulkInsert(MediaContract.AlbumArtists.CONTENT_URI, albumArtistsValuesBatch);
contentResolver.bulkInsert(MediaContract.AlbumGenres.CONTENT_URI, albumGenresValuesBatch);
LogUtils.LOGD(TAG, "Finished inserting artists and genres in: " +
(System.currentTimeMillis() - albumSyncStartTime));
chainCallSyncSongs(orchestrator, hostConnection, callbackHandler, contentResolver,
0, new ArrayList<AudioType.DetailsSong>());
}
LogUtils.LOGD(TAG, "Finished parsing artists and genres in: " +
(System.currentTimeMillis() - albumSyncStartTime));
contentResolver.bulkInsert(MediaContract.AlbumArtists.CONTENT_URI, albumArtistsValuesBatch);
contentResolver.bulkInsert(MediaContract.AlbumGenres.CONTENT_URI, albumGenresValuesBatch);
LogUtils.LOGD(TAG, "Finished inserting artists and genres in: " +
(System.currentTimeMillis() - albumSyncStartTime));
// TODO: Continue to sync songs?
chainCallSyncSongs(orchestrator, hostConnection, callbackHandler, contentResolver);
}
@Override
@ -1024,50 +1134,62 @@ public class LibrarySyncService extends Service {
}, callbackHandler);
}
private static final String getSongsProperties[] = {
AudioType.FieldsSong.TITLE,
//AudioType.FieldsSong.ARTIST, AudioType.FieldsSong.ALBUMARTIST, AudioType.FieldsSong.GENRE,
//AudioType.FieldsSong.YEAR, AudioType.FieldsSong.RATING,
//AudioType.FieldsSong.ALBUM,
AudioType.FieldsSong.TRACK, AudioType.FieldsSong.DURATION,
//AudioType.FieldsSong.COMMENT, AudioType.FieldsSong.LYRICS,
//AudioType.FieldsSong.MUSICBRAINZTRACKID,
//AudioType.FieldsSong.MUSICBRAINZARTISTID,
//AudioType.FieldsSong.MUSICBRAINZALBUMID,
//AudioType.FieldsSong.MUSICBRAINZALBUMARTISTID,
//AudioType.FieldsSong.PLAYCOUNT, AudioType.FieldsSong.FANART,
AudioType.FieldsSong.THUMBNAIL, AudioType.FieldsSong.FILE,
AudioType.FieldsSong.ALBUMID,
//AudioType.FieldsSong.LASTPLAYED, AudioType.FieldsSong.DISC,
//AudioType.FieldsSong.GENREID, AudioType.FieldsSong.ARTISTID,
//AudioType.FieldsSong.DISPLAYARTIST, AudioType.FieldsSong.ALBUMARTISTID
};
/**
* Syncs songs and stops
*/
private void chainCallSyncSongs(final SyncOrchestrator orchestrator,
final HostConnection hostConnection,
final Handler callbackHandler,
final ContentResolver contentResolver) {
String getSongsProperties[] = {
AudioType.FieldsSong.TITLE,
//AudioType.FieldsSong.ARTIST, AudioType.FieldsSong.ALBUMARTIST, AudioType.FieldsSong.GENRE,
//AudioType.FieldsSong.YEAR, AudioType.FieldsSong.RATING,
//AudioType.FieldsSong.ALBUM,
AudioType.FieldsSong.TRACK, AudioType.FieldsSong.DURATION,
//AudioType.FieldsSong.COMMENT, AudioType.FieldsSong.LYRICS,
//AudioType.FieldsSong.MUSICBRAINZTRACKID,
//AudioType.FieldsSong.MUSICBRAINZARTISTID,
//AudioType.FieldsSong.MUSICBRAINZALBUMID,
//AudioType.FieldsSong.MUSICBRAINZALBUMARTISTID,
//AudioType.FieldsSong.PLAYCOUNT, AudioType.FieldsSong.FANART,
AudioType.FieldsSong.THUMBNAIL, AudioType.FieldsSong.FILE,
AudioType.FieldsSong.ALBUMID,
//AudioType.FieldsSong.LASTPLAYED, AudioType.FieldsSong.DISC,
//AudioType.FieldsSong.GENREID, AudioType.FieldsSong.ARTISTID,
//AudioType.FieldsSong.DISPLAYARTIST, AudioType.FieldsSong.ALBUMARTISTID
};
final ContentResolver contentResolver,
final int startIdx,
final List<AudioType.DetailsSong> allResults) {
// Songs
AudioLibrary.GetSongs action = new AudioLibrary.GetSongs(getSongsProperties);
ListType.Limits limits = new ListType.Limits(startIdx, startIdx + LIMIT_SYNC_SONGS);
AudioLibrary.GetSongs action = new AudioLibrary.GetSongs(limits, getSongsProperties);
action.execute(hostConnection, new ApiCallback<List<AudioType.DetailsSong>>() {
@Override
public void onSucess(List<AudioType.DetailsSong> result) {
LogUtils.LOGD(TAG, "GetSongs result size: " + result.size());
ContentValues songValuesBatch[] = new ContentValues[result.size()];
allResults.addAll(result);
if (result.size() == LIMIT_SYNC_SONGS) {
// Max limit returned, there may be some more
LogUtils.LOGD(TAG, "chainCallSyncSongs: More results on media center, recursing.");
chainCallSyncSongs(orchestrator, hostConnection, callbackHandler, contentResolver,
startIdx + LIMIT_SYNC_SONGS, allResults);
} else {
// Ok, we have all the songs, insert them
LogUtils.LOGD(TAG, "chainCallSyncSongs: Got all results, continuing");
for (int i = 0; i < result.size(); i++) {
AudioType.DetailsSong song = result.get(i);
songValuesBatch[i] = SyncUtils.contentValuesFromSong(hostId, song);
ContentValues songValuesBatch[] = new ContentValues[allResults.size()];
for (int i = 0; i < allResults.size(); i++) {
AudioType.DetailsSong song = allResults.get(i);
songValuesBatch[i] = SyncUtils.contentValuesFromSong(hostId, song);
}
// Insert the songs
contentResolver.bulkInsert(MediaContract.Songs.CONTENT_URI, songValuesBatch);
orchestrator.syncItemFinished();
}
// Insert the songs
contentResolver.bulkInsert(MediaContract.Songs.CONTENT_URI, songValuesBatch);
orchestrator.syncItemFinished();
}
@Override