Search in sources :

Example 1 with UpdateResult

use of com.battlelancer.seriesguide.sync.SgSyncAdapter.UpdateResult in project SeriesGuide by UweTrottmann.

the class MovieTools method syncMovieListsWithTrakt.

/**
     * Updates the local movie database against trakt movie watchlist and collection. Adds, updates
     * and removes movies in the database.
     *
     * <p> When syncing the first time, will upload any local movies missing from trakt collection
     * or watchlist instead of removing them locally.
     *
     * <p> Performs <b>synchronous network access</b>, make sure to run this on a background
     * thread.
     */
@SuppressLint("ApplySharedPref")
public UpdateResult syncMovieListsWithTrakt(LastActivityMore activity) {
    if (activity.collected_at == null) {
        Timber.e("syncMoviesWithTrakt: null collected_at");
        return UpdateResult.INCOMPLETE;
    }
    if (activity.watchlisted_at == null) {
        Timber.e("syncMoviesWithTrakt: null watchlisted_at");
        return UpdateResult.INCOMPLETE;
    }
    if (!TraktCredentials.get(context).hasCredentials()) {
        return UpdateResult.INCOMPLETE;
    }
    final boolean merging = !TraktSettings.hasMergedMovies(context);
    if (!merging && !TraktSettings.isMovieListsChanged(context, activity.collected_at, activity.watchlisted_at)) {
        Timber.d("syncMoviesWithTrakt: no changes");
        return UpdateResult.SUCCESS;
    }
    // download collection
    Set<Integer> collection;
    try {
        Response<List<BaseMovie>> response = traktSync.get().collectionMovies(Extended.DEFAULT_MIN).execute();
        if (response.isSuccessful()) {
            collection = buildTmdbIdSet(response.body());
        } else {
            if (SgTrakt.isUnauthorized(context, response)) {
                return UpdateResult.INCOMPLETE;
            }
            SgTrakt.trackFailedRequest(context, "get movie collection", response);
            return UpdateResult.INCOMPLETE;
        }
    } catch (IOException e) {
        SgTrakt.trackFailedRequest(context, "get movie collection", e);
        return UpdateResult.INCOMPLETE;
    }
    if (collection == null) {
        Timber.e("syncMoviesWithTrakt: null collection response");
        return UpdateResult.INCOMPLETE;
    }
    // download watchlist
    Set<Integer> watchlist;
    try {
        Response<List<BaseMovie>> response = traktSync.get().watchlistMovies(Extended.DEFAULT_MIN).execute();
        if (response.isSuccessful()) {
            watchlist = buildTmdbIdSet(response.body());
        } else {
            if (SgTrakt.isUnauthorized(context, response)) {
                return UpdateResult.INCOMPLETE;
            }
            SgTrakt.trackFailedRequest(context, "get movie watchlist", response);
            return UpdateResult.INCOMPLETE;
        }
    } catch (IOException e) {
        SgTrakt.trackFailedRequest(context, "get movie watchlist", e);
        return UpdateResult.INCOMPLETE;
    }
    if (watchlist == null) {
        Timber.e("syncMoviesWithTrakt: null watchlist response");
        return UpdateResult.INCOMPLETE;
    }
    // build updates
    // loop through all local movies
    Set<Integer> moviesNotOnTraktCollection = new HashSet<>();
    Set<Integer> moviesNotOnTraktWatchlist = new HashSet<>();
    ArrayList<ContentProviderOperation> batch = new ArrayList<>();
    HashSet<Integer> localMovies = getMovieTmdbIdsAsSet(context);
    if (localMovies == null) {
        Timber.e("syncMoviesWithTrakt: querying local movies failed");
        return UpdateResult.INCOMPLETE;
    }
    for (Integer tmdbId : localMovies) {
        // is local movie in trakt collection or watchlist?
        boolean inCollection = collection.remove(tmdbId);
        boolean inWatchlist = watchlist.remove(tmdbId);
        if (merging) {
            // upload movie if missing from trakt collection or watchlist
            if (!inCollection) {
                moviesNotOnTraktCollection.add(tmdbId);
            }
            if (!inWatchlist) {
                moviesNotOnTraktWatchlist.add(tmdbId);
            }
            // add to local collection or watchlist, but do NOT remove
            if (inCollection || inWatchlist) {
                ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(SeriesGuideContract.Movies.buildMovieUri(tmdbId));
                if (inCollection) {
                    builder.withValue(SeriesGuideContract.Movies.IN_COLLECTION, true);
                }
                if (inWatchlist) {
                    builder.withValue(SeriesGuideContract.Movies.IN_WATCHLIST, true);
                }
                batch.add(builder.build());
            }
        } else {
            // mirror trakt collection and watchlist flag
            // will take care of removing unneeded (not watched or in any list) movies
            // in later sync step
            ContentProviderOperation op = ContentProviderOperation.newUpdate(SeriesGuideContract.Movies.buildMovieUri(tmdbId)).withValue(SeriesGuideContract.Movies.IN_COLLECTION, inCollection).withValue(SeriesGuideContract.Movies.IN_WATCHLIST, inWatchlist).build();
            batch.add(op);
        }
    }
    // apply collection and watchlist updates to existing movies
    try {
        DBUtils.applyInSmallBatches(context, batch);
        Timber.d("syncMoviesWithTrakt: updated %s", batch.size());
    } catch (OperationApplicationException e) {
        Timber.e(e, "syncMoviesWithTrakt: database updates failed");
        return UpdateResult.INCOMPLETE;
    }
    batch.clear();
    // merge on first run
    if (merging) {
        // upload movies not in trakt collection or watchlist
        if (toTrakt(moviesNotOnTraktCollection, moviesNotOnTraktWatchlist) != UpdateResult.SUCCESS) {
            return UpdateResult.INCOMPLETE;
        } else {
            // set merge successful
            PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(TraktSettings.KEY_HAS_MERGED_MOVIES, true).commit();
        }
    }
    // add movies from trakt missing locally
    // all local movies were removed from trakt collection and watchlist,
    // so they only contain movies missing locally
    UpdateResult result = addMovies(collection, watchlist);
    if (result == UpdateResult.SUCCESS) {
        // store last activity timestamps
        TraktSettings.storeLastMoviesChangedAt(context, activity.collected_at, activity.watchlisted_at);
        // ensure all movie ratings and watched flags are downloaded next
        if (collection.size() > 0 || watchlist.size() > 0) {
            TraktSettings.resetMoviesLastActivity(context);
        }
    }
    return result;
}
Also used : ContentProviderOperation(android.content.ContentProviderOperation) ArrayList(java.util.ArrayList) IOException(java.io.IOException) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) MovieList(com.uwetrottmann.seriesguide.backend.movies.model.MovieList) OperationApplicationException(android.content.OperationApplicationException) UpdateResult(com.battlelancer.seriesguide.sync.SgSyncAdapter.UpdateResult) HashSet(java.util.HashSet) SuppressLint(android.annotation.SuppressLint)

Aggregations

SuppressLint (android.annotation.SuppressLint)1 ContentProviderOperation (android.content.ContentProviderOperation)1 OperationApplicationException (android.content.OperationApplicationException)1 UpdateResult (com.battlelancer.seriesguide.sync.SgSyncAdapter.UpdateResult)1 MovieList (com.uwetrottmann.seriesguide.backend.movies.model.MovieList)1 IOException (java.io.IOException)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1