Search in sources :

Example 1 with SgMovieFlags

use of com.battlelancer.seriesguide.model.SgMovieFlags in project SeriesGuide by UweTrottmann.

the class TraktMovieSync method syncLists.

/**
 * Updates the local movie database against trakt movie watchlist, collection and watched
 * movies. Adds or updates movies in the database. Movies not in any list or not watched must be
 * removed afterwards.
 *
 * <p> When syncing the first time, will upload any local movies missing from trakt collection
 * or watchlist or are not watched on Trakt instead of removing them locally.
 *
 * <p> Performs <b>synchronous network access</b>, make sure to run this on a background
 * thread.
 */
boolean syncLists(LastActivityMore activity) {
    if (activity.collected_at == null) {
        Timber.e("syncLists: null collected_at");
        return false;
    }
    if (activity.watchlisted_at == null) {
        Timber.e("syncLists: null watchlisted_at");
        return false;
    }
    if (activity.watched_at == null) {
        Timber.e("syncLists: null watched_at");
        return false;
    }
    final boolean merging = !TraktSettings.hasMergedMovies(context);
    if (!merging && !TraktSettings.isMovieListsChanged(context, activity.collected_at, activity.watchlisted_at, activity.watched_at)) {
        Timber.d("syncLists: no changes");
        return true;
    }
    if (!TraktCredentials.get(context).hasCredentials()) {
        return false;
    }
    // download trakt state
    Set<Integer> collection = downloadCollection();
    if (collection == null) {
        return false;
    }
    Set<Integer> watchlist = downloadWatchlist();
    if (watchlist == null) {
        return false;
    }
    Map<Integer, Integer> watchedWithPlays = downloadWatched();
    if (watchedWithPlays == null) {
        return false;
    }
    // Loop through local movies to build updates.
    List<SgMovieFlags> localMovies;
    try {
        localMovies = SgRoomDatabase.getInstance(context).movieHelper().getMovieFlags();
    } catch (Exception e) {
        Errors.logAndReport("syncLists: query local movies", e);
        return false;
    }
    // only when merging
    Set<Integer> toCollectOnTrakt = new HashSet<>();
    // only when merging
    Set<Integer> toWatchlistOnTrakt = new HashSet<>();
    // only when merging
    Set<Integer> toSetWatchedOnTrakt = new HashSet<>();
    ArrayList<ContentProviderOperation> batch = new ArrayList<>();
    for (SgMovieFlags localMovie : localMovies) {
        // Is local movie in trakt collection, watchlist or watched?
        int tmdbId = localMovie.getTmdbId();
        boolean inCollectionOnTrakt = collection.remove(tmdbId);
        boolean inWatchlistOnTrakt = watchlist.remove(tmdbId);
        Integer plays = watchedWithPlays.remove(tmdbId);
        boolean isWatchedOnTrakt = plays != null;
        if (merging) {
            if (localMovie.getInCollection() && !inCollectionOnTrakt) {
                toCollectOnTrakt.add(tmdbId);
            }
            if (localMovie.getInWatchlist() && !inWatchlistOnTrakt) {
                toWatchlistOnTrakt.add(tmdbId);
            }
            if (localMovie.getWatched() && !isWatchedOnTrakt) {
                toSetWatchedOnTrakt.add(tmdbId);
            }
            // in later sync step.
            if (inCollectionOnTrakt || inWatchlistOnTrakt || isWatchedOnTrakt) {
                ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(Movies.buildMovieUri(tmdbId));
                boolean changed = false;
                if (!localMovie.getInCollection() && inCollectionOnTrakt) {
                    builder.withValue(Movies.IN_COLLECTION, true);
                    changed = true;
                }
                if (!localMovie.getInWatchlist() && inWatchlistOnTrakt) {
                    builder.withValue(Movies.IN_WATCHLIST, true);
                    changed = true;
                }
                if (!localMovie.getWatched() && isWatchedOnTrakt) {
                    builder.withValue(Movies.WATCHED, true);
                    builder.withValue(Movies.PLAYS, plays >= 1 ? plays : 1);
                    changed = true;
                }
                if (changed) {
                    batch.add(builder.build());
                }
            }
        } else {
            // Performance: only add op if any flag differs or if watched and plays have changed.
            if (localMovie.getInCollection() != inCollectionOnTrakt || localMovie.getInWatchlist() != inWatchlistOnTrakt || localMovie.getWatched() != isWatchedOnTrakt || (isWatchedOnTrakt && plays >= 1 && localMovie.getPlays() != plays)) {
                // Mirror Trakt collection, watchlist, watched flag and plays.
                // Note: unneeded (not watched or in any list) movies
                // are removed in a later sync step.
                ContentProviderOperation.Builder op = ContentProviderOperation.newUpdate(Movies.buildMovieUri(tmdbId)).withValue(Movies.IN_COLLECTION, inCollectionOnTrakt).withValue(Movies.IN_WATCHLIST, inWatchlistOnTrakt).withValue(Movies.WATCHED, isWatchedOnTrakt);
                int playsValue;
                if (isWatchedOnTrakt) {
                    playsValue = plays >= 1 ? plays : 1;
                } else {
                    playsValue = 0;
                }
                op.withValue(Movies.PLAYS, playsValue);
                batch.add(op.build());
            }
        }
    }
    // apply updates to existing movies
    try {
        DBUtils.applyInSmallBatches(context, batch);
        Timber.d("syncLists: updated %s", batch.size());
    } catch (OperationApplicationException e) {
        Timber.e(e, "syncLists: database updates failed");
        return false;
    }
    // release for gc
    batch.clear();
    // merge on first run
    if (merging) {
        // Upload movies not in Trakt collection, watchlist or watched history.
        if (uploadFlagsNotOnTrakt(toCollectOnTrakt, toWatchlistOnTrakt, toSetWatchedOnTrakt)) {
            // set merge successful
            PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(TraktSettings.KEY_HAS_MERGED_MOVIES, true).apply();
        } else {
            return false;
        }
    }
    // add movies from trakt missing locally
    // all local movies were removed from trakt collection, watchlist, and watched list
    // so they only contain movies missing locally
    boolean addingSuccessful = movieTools.addMovies(collection, watchlist, watchedWithPlays);
    if (addingSuccessful) {
        // store last activity timestamps
        TraktSettings.storeLastMoviesChangedAt(context, activity.collected_at, activity.watchlisted_at, activity.watched_at);
        // if movies were added, ensure ratings for them are downloaded next
        if (collection.size() > 0 || watchlist.size() > 0 || watchedWithPlays.size() > 0) {
            TraktSettings.resetMoviesLastRatedAt(context);
        }
    }
    return addingSuccessful;
}
Also used : ContentProviderOperation(android.content.ContentProviderOperation) ArrayList(java.util.ArrayList) OperationApplicationException(android.content.OperationApplicationException) SgMovieFlags(com.battlelancer.seriesguide.model.SgMovieFlags) OperationApplicationException(android.content.OperationApplicationException) HashSet(java.util.HashSet)

Example 2 with SgMovieFlags

use of com.battlelancer.seriesguide.model.SgMovieFlags in project SeriesGuide by UweTrottmann.

the class MovieTools method removeFromList.

/**
 * Removes the movie from the given list.
 *
 * <p>If it would not be on any list afterwards, deletes the movie from the local database.
 *
 * @return If the database operation was successful.
 */
public static boolean removeFromList(Context context, int movieTmdbId, Lists listToRemoveFrom) {
    SgMovieFlags movieFlags = SgRoomDatabase.getInstance(context).movieHelper().getMovieFlags(movieTmdbId);
    if (movieFlags == null) {
        // query failed
        return false;
    }
    boolean removeMovie = false;
    if (listToRemoveFrom == Lists.COLLECTION) {
        removeMovie = !movieFlags.getInWatchlist() && !movieFlags.getWatched();
    } else if (listToRemoveFrom == Lists.WATCHLIST) {
        removeMovie = !movieFlags.getInCollection() && !movieFlags.getWatched();
    } else if (listToRemoveFrom == Lists.WATCHED) {
        removeMovie = !movieFlags.getInCollection() && !movieFlags.getInWatchlist();
    }
    // if movie will not be in any list, remove it completely
    if (removeMovie) {
        return deleteMovie(context, movieTmdbId);
    } else {
        // otherwise, just update
        return updateMovie(context, movieTmdbId, listToRemoveFrom, false);
    }
}
Also used : SgMovieFlags(com.battlelancer.seriesguide.model.SgMovieFlags)

Aggregations

SgMovieFlags (com.battlelancer.seriesguide.model.SgMovieFlags)2 ContentProviderOperation (android.content.ContentProviderOperation)1 OperationApplicationException (android.content.OperationApplicationException)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1