Search in sources :

Example 6 with Sync

use of com.uwetrottmann.trakt5.services.Sync in project SeriesGuide by UweTrottmann.

the class TraktRatingsSync method downloadForEpisodes.

/**
 * Downloads trakt episode ratings and applies the latest ones to the database.
 *
 * <p> To apply all ratings, set {@link TraktSettings#KEY_LAST_EPISODES_RATED_AT} to 0.
 */
public boolean downloadForEpisodes(@Nullable OffsetDateTime ratedAt) {
    if (ratedAt == null) {
        Timber.e("downloadForEpisodes: null rated_at");
        return false;
    }
    long lastRatedAt = TraktSettings.getLastEpisodesRatedAt(context);
    if (!TimeTools.isAfterMillis(ratedAt, lastRatedAt)) {
        // not initial sync, no ratings have changed
        Timber.d("downloadForEpisodes: no changes since %tF %tT", lastRatedAt, lastRatedAt);
        return true;
    }
    if (!TraktCredentials.get(context).hasCredentials()) {
        return false;
    }
    // download rated episodes
    List<RatedEpisode> ratedEpisodes;
    try {
        Response<List<RatedEpisode>> response = traktSync.ratingsEpisodes(RatingsFilter.ALL, null, null, null).execute();
        if (response.isSuccessful()) {
            ratedEpisodes = response.body();
        } else {
            if (SgTrakt.isUnauthorized(context, response)) {
                return false;
            }
            Errors.logAndReport("get episode ratings", response);
            return false;
        }
    } catch (Exception e) {
        Errors.logAndReport("get episode ratings", e);
        return false;
    }
    if (ratedEpisodes == null) {
        Timber.e("downloadForEpisodes: null response");
        return false;
    }
    if (ratedEpisodes.isEmpty()) {
        Timber.d("downloadForEpisodes: no ratings on trakt");
        return true;
    }
    // trakt last activity rated_at timestamp is set after the rating timestamp
    // so include ratings that are a little older
    long ratedAtThreshold = lastRatedAt - 5 * DateUtils.MINUTE_IN_MILLIS;
    Map<Integer, Integer> tmdbIdsToRatings = new HashMap<>();
    for (RatedEpisode episode : ratedEpisodes) {
        if (episode.rating == null || episode.episode == null || episode.episode.ids == null || episode.episode.ids.tmdb == null) {
            // skip, can't handle
            continue;
        }
        if (episode.rated_at != null && TimeTools.isBeforeMillis(episode.rated_at, ratedAtThreshold)) {
            // no need to apply older ratings again
            break;
        }
        // if an episode does not exist, this update will do nothing
        tmdbIdsToRatings.put(episode.episode.ids.tmdb, episode.rating.value);
    }
    // apply database updates
    SgRoomDatabase.getInstance(context).sgEpisode2Helper().updateUserRatings(tmdbIdsToRatings);
    // save last rated instant
    long ratedAtTime = ratedAt.toInstant().toEpochMilli();
    PreferenceManager.getDefaultSharedPreferences(context).edit().putLong(TraktSettings.KEY_LAST_EPISODES_RATED_AT, ratedAtTime).apply();
    Timber.d("downloadForEpisodes: success, last rated_at %tF %tT", ratedAtTime, ratedAtTime);
    return true;
}
Also used : RatedEpisode(com.uwetrottmann.trakt5.entities.RatedEpisode) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) List(java.util.List) OperationApplicationException(android.content.OperationApplicationException)

Example 7 with Sync

use of com.uwetrottmann.trakt5.services.Sync in project SeriesGuide by UweTrottmann.

the class TraktRatingsSync method downloadForShows.

/**
 * Downloads trakt show ratings and applies the latest ones to the database.
 *
 * <p> To apply all ratings, set {@link TraktSettings#KEY_LAST_SHOWS_RATED_AT} to 0.
 */
public boolean downloadForShows(@Nullable OffsetDateTime ratedAt) {
    if (ratedAt == null) {
        Timber.e("downloadForShows: null rated_at");
        return false;
    }
    long lastRatedAt = TraktSettings.getLastShowsRatedAt(context);
    if (!TimeTools.isAfterMillis(ratedAt, lastRatedAt)) {
        // not initial sync, no ratings have changed
        Timber.d("downloadForShows: no changes since %tF %tT", lastRatedAt, lastRatedAt);
        return true;
    }
    if (!TraktCredentials.get(context).hasCredentials()) {
        return false;
    }
    // download rated shows
    List<RatedShow> ratedShows;
    try {
        Response<List<RatedShow>> response = traktSync.ratingsShows(RatingsFilter.ALL, null, null, null).execute();
        if (response.isSuccessful()) {
            ratedShows = response.body();
        } else {
            if (SgTrakt.isUnauthorized(context, response)) {
                return false;
            }
            Errors.logAndReport("get show ratings", response);
            return false;
        }
    } catch (Exception e) {
        Errors.logAndReport("get show ratings", e);
        return false;
    }
    if (ratedShows == null) {
        Timber.e("downloadForShows: null response");
        return false;
    }
    if (ratedShows.isEmpty()) {
        Timber.d("downloadForShows: no ratings on trakt");
        return true;
    }
    // trakt last activity rated_at timestamp is set after the rating timestamp
    // so include ratings that are a little older
    long ratedAtThreshold = lastRatedAt - 5 * DateUtils.MINUTE_IN_MILLIS;
    // go through ratings, latest first (trakt sends in that order)
    Map<Integer, Integer> tmdbIdsToRatings = new HashMap<>();
    for (RatedShow show : ratedShows) {
        Rating rating = show.rating;
        if (rating == null || show.show == null || show.show.ids == null) {
            continue;
        }
        Integer showTmdbId = show.show.ids.tmdb;
        if (showTmdbId == null) {
            continue;
        }
        if (show.rated_at != null && TimeTools.isBeforeMillis(show.rated_at, ratedAtThreshold)) {
            // no need to apply older ratings again
            break;
        }
        // if a show does not exist, this update will do nothing
        tmdbIdsToRatings.put(showTmdbId, rating.value);
    }
    // apply database updates
    SgRoomDatabase.getInstance(context).sgShow2Helper().updateUserRatings(tmdbIdsToRatings);
    // save last rated instant
    long ratedAtTime = ratedAt.toInstant().toEpochMilli();
    PreferenceManager.getDefaultSharedPreferences(context).edit().putLong(TraktSettings.KEY_LAST_SHOWS_RATED_AT, ratedAtTime).apply();
    Timber.d("downloadForShows: success, last rated_at %tF %tT", ratedAtTime, ratedAtTime);
    return true;
}
Also used : RatedShow(com.uwetrottmann.trakt5.entities.RatedShow) HashMap(java.util.HashMap) Rating(com.uwetrottmann.trakt5.enums.Rating) ArrayList(java.util.ArrayList) List(java.util.List) OperationApplicationException(android.content.OperationApplicationException)

Example 8 with Sync

use of com.uwetrottmann.trakt5.services.Sync in project SeriesGuide by UweTrottmann.

the class TraktRatingsSync method downloadForMovies.

/**
 * Downloads trakt movie ratings and applies the latest ones to the database.
 *
 * <p> To apply all ratings, set {@link TraktSettings#KEY_LAST_MOVIES_RATED_AT} to 0.
 */
public boolean downloadForMovies(OffsetDateTime ratedAt) {
    if (ratedAt == null) {
        Timber.e("downloadForMovies: null rated_at");
        return false;
    }
    long lastRatedAt = TraktSettings.getLastMoviesRatedAt(context);
    if (!TimeTools.isAfterMillis(ratedAt, lastRatedAt)) {
        // not initial sync, no ratings have changed
        Timber.d("downloadForMovies: no changes since %tF %tT", lastRatedAt, lastRatedAt);
        return true;
    }
    if (!TraktCredentials.get(context).hasCredentials()) {
        return false;
    }
    // download rated shows
    List<RatedMovie> ratedMovies;
    try {
        Response<List<RatedMovie>> response = traktSync.ratingsMovies(RatingsFilter.ALL, null, null, null).execute();
        if (response.isSuccessful()) {
            ratedMovies = response.body();
        } else {
            if (SgTrakt.isUnauthorized(context, response)) {
                return false;
            }
            Errors.logAndReport("get movie ratings", response);
            return false;
        }
    } catch (Exception e) {
        Errors.logAndReport("get movie ratings", e);
        return false;
    }
    if (ratedMovies == null) {
        Timber.e("downloadForMovies: null response");
        return false;
    }
    if (ratedMovies.isEmpty()) {
        Timber.d("downloadForMovies: no ratings on trakt");
        return true;
    }
    // trakt last activity rated_at timestamp is set after the rating timestamp
    // so include ratings that are a little older
    long ratedAtThreshold = lastRatedAt - 5 * DateUtils.MINUTE_IN_MILLIS;
    // go through ratings, latest first (trakt sends in that order)
    ArrayList<ContentProviderOperation> batch = new ArrayList<>();
    for (RatedMovie movie : ratedMovies) {
        if (movie.rating == null || movie.movie == null || movie.movie.ids == null || movie.movie.ids.tmdb == null) {
            // skip, can't handle
            continue;
        }
        if (movie.rated_at != null && TimeTools.isBeforeMillis(movie.rated_at, ratedAtThreshold)) {
            // no need to apply older ratings again
            break;
        }
        // if a movie does not exist, this update will do nothing
        ContentProviderOperation op = ContentProviderOperation.newUpdate(SeriesGuideContract.Movies.buildMovieUri(movie.movie.ids.tmdb)).withValue(SeriesGuideContract.Movies.RATING_USER, movie.rating.value).build();
        batch.add(op);
    }
    // apply database updates
    try {
        DBUtils.applyInSmallBatches(context, batch);
    } catch (OperationApplicationException e) {
        Timber.e(e, "downloadForMovies: database update failed");
        return false;
    }
    // save last rated instant
    long ratedAtTime = ratedAt.toInstant().toEpochMilli();
    PreferenceManager.getDefaultSharedPreferences(context).edit().putLong(TraktSettings.KEY_LAST_MOVIES_RATED_AT, ratedAtTime).apply();
    Timber.d("downloadForMovies: success, last rated_at %tF %tT", ratedAtTime, ratedAtTime);
    return true;
}
Also used : ContentProviderOperation(android.content.ContentProviderOperation) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) RatedMovie(com.uwetrottmann.trakt5.entities.RatedMovie) OperationApplicationException(android.content.OperationApplicationException) OperationApplicationException(android.content.OperationApplicationException)

Example 9 with Sync

use of com.uwetrottmann.trakt5.services.Sync in project SeriesGuide by UweTrottmann.

the class SgSyncAdapter method performTraktSync.

private UpdateResult performTraktSync(HashSet<Integer> localShows, long currentTime) {
    if (!TraktCredentials.get(getContext()).hasCredentials()) {
        Timber.d("performTraktSync: no auth, skip");
        return UpdateResult.SUCCESS;
    }
    if (!AndroidUtils.isNetworkConnected(getContext())) {
        return UpdateResult.INCOMPLETE;
    }
    // get last activity timestamps
    TraktTools traktTools = app.getTraktTools();
    LastActivities lastActivity = traktTools.getLastActivity();
    if (lastActivity == null) {
        // trakt is likely offline or busy, try later
        Timber.e("performTraktSync: last activity download failed");
        return UpdateResult.INCOMPLETE;
    }
    if (!AndroidUtils.isNetworkConnected(getContext())) {
        return UpdateResult.INCOMPLETE;
    }
    if (localShows.size() == 0) {
        Timber.d("performTraktSync: no local shows, skip shows");
    } else {
        // download and upload episode watched and collected flags
        if (performTraktEpisodeSync(localShows, lastActivity.episodes, currentTime) != UpdateResult.SUCCESS) {
            return UpdateResult.INCOMPLETE;
        }
        if (!AndroidUtils.isNetworkConnected(getContext())) {
            return UpdateResult.INCOMPLETE;
        }
        // download show ratings
        if (traktTools.downloadShowRatings(lastActivity.shows.rated_at) != UpdateResult.SUCCESS) {
            return UpdateResult.INCOMPLETE;
        }
        if (!AndroidUtils.isNetworkConnected(getContext())) {
            return UpdateResult.INCOMPLETE;
        }
        // download episode ratings
        if (traktTools.downloadEpisodeRatings(lastActivity.episodes.rated_at) != UpdateResult.SUCCESS) {
            return UpdateResult.INCOMPLETE;
        }
        if (!AndroidUtils.isNetworkConnected(getContext())) {
            return UpdateResult.INCOMPLETE;
        }
    }
    // sync watchlist and collection with trakt
    if (app.getMovieTools().syncMovieListsWithTrakt(lastActivity.movies) != UpdateResult.SUCCESS) {
        return UpdateResult.INCOMPLETE;
    }
    if (!AndroidUtils.isNetworkConnected(getContext())) {
        return UpdateResult.INCOMPLETE;
    }
    // download watched movies
    if (traktTools.downloadWatchedMovies(lastActivity.movies.watched_at) != UpdateResult.SUCCESS) {
        return UpdateResult.INCOMPLETE;
    }
    // clean up any useless movies (not watched or not in any list)
    MovieTools.deleteUnusedMovies(getContext());
    if (!AndroidUtils.isNetworkConnected(getContext())) {
        return UpdateResult.INCOMPLETE;
    }
    // download movie ratings
    return traktTools.downloadMovieRatings(lastActivity.movies.rated_at);
}
Also used : TraktTools(com.battlelancer.seriesguide.util.TraktTools) LastActivities(com.uwetrottmann.trakt5.entities.LastActivities)

Example 10 with Sync

use of com.uwetrottmann.trakt5.services.Sync in project SeriesGuide by UweTrottmann.

the class AddShowTask method doInBackground.

@Override
protected Void doInBackground(Void... params) {
    Timber.d("Starting to add shows...");
    // don't even get started
    if (addQueue.isEmpty()) {
        Timber.d("Finished. Queue was empty.");
        return null;
    }
    // set values required for progress update
    SearchResult nextShow = addQueue.peek();
    currentShowName = nextShow.title;
    currentShowTvdbId = nextShow.tvdbid;
    if (!AndroidUtils.isNetworkConnected(app)) {
        Timber.d("Finished. No internet connection.");
        publishProgress(RESULT_OFFLINE);
        return null;
    }
    if (isCancelled()) {
        Timber.d("Finished. Cancelled.");
        return null;
    }
    // if not connected to Hexagon, get episodes from trakt
    HashMap<Integer, BaseShow> traktCollection = null;
    HashMap<Integer, BaseShow> traktWatched = null;
    if (!HexagonSettings.isEnabled(app) && TraktCredentials.get(app).hasCredentials()) {
        Timber.d("Getting watched and collected episodes from trakt.");
        // get collection
        HashMap<Integer, BaseShow> traktShows = getTraktShows("get collection", true);
        if (traktShows == null) {
            // can not get collected state from trakt, give up.
            return null;
        }
        traktCollection = traktShows;
        // get watched
        traktShows = getTraktShows("get watched", false);
        if (traktShows == null) {
            // can not get watched state from trakt, give up.
            return null;
        }
        traktWatched = traktShows;
    }
    int result;
    boolean addedAtLeastOneShow = false;
    boolean failedMergingShows = false;
    while (!addQueue.isEmpty()) {
        Timber.d("Starting to add next show...");
        if (isCancelled()) {
            Timber.d("Finished. Cancelled.");
            // table yet
            return null;
        }
        nextShow = addQueue.removeFirst();
        // set values required for progress update
        currentShowName = nextShow.title;
        currentShowTvdbId = nextShow.tvdbid;
        if (!AndroidUtils.isNetworkConnected(app)) {
            Timber.d("Finished. No connection.");
            publishProgress(RESULT_OFFLINE);
            failedMergingShows = true;
            break;
        }
        try {
            boolean addedShow = TvdbTools.getInstance(app).addShow(nextShow.tvdbid, nextShow.language, traktCollection, traktWatched);
            result = addedShow ? PROGRESS_SUCCESS : PROGRESS_EXISTS;
            addedAtLeastOneShow = addedShow || // do not overwrite previous success
            addedAtLeastOneShow;
        } catch (TvdbException e) {
            // because it does not exist (any longer)
            if (!(isMergingShows && e.itemDoesNotExist())) {
                failedMergingShows = true;
            }
            if (e.service() == TvdbException.Service.TVDB) {
                if (e.itemDoesNotExist()) {
                    result = PROGRESS_ERROR_TVDB_NOT_EXISTS;
                } else {
                    result = PROGRESS_ERROR_TVDB;
                }
            } else if (e.service() == TvdbException.Service.HEXAGON) {
                result = PROGRESS_ERROR_HEXAGON;
            } else if (e.service() == TvdbException.Service.DATA) {
                result = PROGRESS_ERROR_DATA;
            } else {
                result = PROGRESS_ERROR;
            }
            Timber.e(e, "Adding show failed");
        }
        publishProgress(result);
        Timber.d("Finished adding show. (Result code: %s)", result);
    }
    isFinishedAddingShows = true;
    // when merging shows down from Hexagon, set success flag
    if (isMergingShows && !failedMergingShows) {
        HexagonSettings.setHasMergedShows(app, true);
    }
    if (addedAtLeastOneShow) {
        // make sure the next sync will download all ratings
        PreferenceManager.getDefaultSharedPreferences(app).edit().putLong(TraktSettings.KEY_LAST_SHOWS_RATED_AT, 0).putLong(TraktSettings.KEY_LAST_EPISODES_RATED_AT, 0).apply();
        // renew FTS3 table
        Timber.d("Renewing search table.");
        DBUtils.rebuildFtsTable(app);
    }
    Timber.d("Finished adding shows.");
    return null;
}
Also used : BaseShow(com.uwetrottmann.trakt5.entities.BaseShow) SearchResult(com.battlelancer.seriesguide.items.SearchResult) TvdbException(com.battlelancer.seriesguide.thetvdbapi.TvdbException)

Aggregations

OperationApplicationException (android.content.OperationApplicationException)8 ArrayList (java.util.ArrayList)8 List (java.util.List)7 ContentProviderOperation (android.content.ContentProviderOperation)6 IOException (java.io.IOException)4 LinkedList (java.util.LinkedList)4 BaseShow (com.uwetrottmann.trakt5.entities.BaseShow)2 LastActivities (com.uwetrottmann.trakt5.entities.LastActivities)2 RatedEpisode (com.uwetrottmann.trakt5.entities.RatedEpisode)2 RatedMovie (com.uwetrottmann.trakt5.entities.RatedMovie)2 RatedShow (com.uwetrottmann.trakt5.entities.RatedShow)2 SyncItems (com.uwetrottmann.trakt5.entities.SyncItems)2 SyncResponse (com.uwetrottmann.trakt5.entities.SyncResponse)2 Sync (com.uwetrottmann.trakt5.services.Sync)2 HashMap (java.util.HashMap)2 SuppressLint (android.annotation.SuppressLint)1 Cursor (android.database.Cursor)1 SearchResult (com.battlelancer.seriesguide.items.SearchResult)1 HexagonEpisodeSync (com.battlelancer.seriesguide.sync.HexagonEpisodeSync)1 TvdbException (com.battlelancer.seriesguide.thetvdbapi.TvdbException)1