Search in sources :

Example 1 with Ratings

use of com.uwetrottmann.trakt5.entities.Ratings in project SeriesGuide by UweTrottmann.

the class TraktTools method downloadShowRatings.

/**
     * 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 UpdateResult downloadShowRatings(@Nullable DateTime ratedAt) {
    if (ratedAt == null) {
        Timber.e("downloadShowRatings: null rated_at");
        return UpdateResult.INCOMPLETE;
    }
    long lastRatedAt = TraktSettings.getLastShowsRatedAt(context);
    if (!ratedAt.isAfter(lastRatedAt)) {
        // not initial sync, no ratings have changed
        Timber.d("downloadShowRatings: no changes since %tF %tT", lastRatedAt, lastRatedAt);
        return UpdateResult.SUCCESS;
    }
    if (!TraktCredentials.get(context).hasCredentials()) {
        return UpdateResult.INCOMPLETE;
    }
    // download rated shows
    List<RatedShow> ratedShows;
    try {
        Response<List<RatedShow>> response = traktSync.get().ratingsShows(RatingsFilter.ALL, Extended.DEFAULT_MIN).execute();
        if (response.isSuccessful()) {
            ratedShows = response.body();
        } else {
            if (SgTrakt.isUnauthorized(context, response)) {
                return UpdateResult.INCOMPLETE;
            }
            SgTrakt.trackFailedRequest(context, "get show ratings", response);
            return UpdateResult.INCOMPLETE;
        }
    } catch (IOException e) {
        SgTrakt.trackFailedRequest(context, "get show ratings", e);
        return UpdateResult.INCOMPLETE;
    }
    if (ratedShows == null) {
        Timber.e("downloadShowRatings: null response");
        return UpdateResult.INCOMPLETE;
    }
    if (ratedShows.isEmpty()) {
        Timber.d("downloadShowRatings: no ratings on trakt");
        return UpdateResult.SUCCESS;
    }
    // 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 (RatedShow show : ratedShows) {
        if (show.rating == null || show.show == null || show.show.ids == null || show.show.ids.tvdb == null) {
            // skip, can't handle
            continue;
        }
        if (show.rated_at != null && show.rated_at.isBefore(ratedAtThreshold)) {
            // no need to apply older ratings again
            break;
        }
        // if a show does not exist, this update will do nothing
        ContentProviderOperation op = ContentProviderOperation.newUpdate(SeriesGuideContract.Shows.buildShowUri(show.show.ids.tvdb)).withValue(SeriesGuideContract.Shows.RATING_USER, show.rating.value).build();
        batch.add(op);
    }
    // apply database updates
    try {
        DBUtils.applyInSmallBatches(context, batch);
    } catch (OperationApplicationException e) {
        Timber.e(e, "downloadShowRatings: database update failed");
        return UpdateResult.INCOMPLETE;
    }
    // save last rated instant
    PreferenceManager.getDefaultSharedPreferences(context).edit().putLong(TraktSettings.KEY_LAST_SHOWS_RATED_AT, ratedAt.getMillis()).commit();
    Timber.d("downloadShowRatings: success, last rated_at %tF %tT", ratedAt.getMillis(), ratedAt.getMillis());
    return UpdateResult.SUCCESS;
}
Also used : ContentProviderOperation(android.content.ContentProviderOperation) RatedShow(com.uwetrottmann.trakt5.entities.RatedShow) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) IOException(java.io.IOException) OperationApplicationException(android.content.OperationApplicationException)

Example 2 with Ratings

use of com.uwetrottmann.trakt5.entities.Ratings in project SeriesGuide by UweTrottmann.

the class TraktRatingsTask method doInBackground.

@Override
protected Void doInBackground(Void... params) {
    long ratingId = createUniqueId(showTvdbId, episodeTvdbId);
    // avoid saving ratings too frequently
    // (network requests are cached, but also avoiding database writes)
    long currentTimeMillis = System.currentTimeMillis();
    synchronized (sCache) {
        Long lastUpdateMillis = sCache.get(ratingId);
        // if the ratings were just updated, do nothing
        if (lastUpdateMillis != null && lastUpdateMillis > currentTimeMillis - MAXIMUM_AGE) {
            Timber.d("Just loaded rating for %s, skip.", ratingId);
            return null;
        }
    }
    if (isCancelled() || !AndroidUtils.isNetworkConnected(context)) {
        return null;
    }
    // look up show trakt id
    Integer showTraktId = ShowTools.getShowTraktId(context, showTvdbId);
    if (showTraktId == null) {
        Timber.d("Show %s has no trakt id, skip.", showTvdbId);
        return null;
    }
    String showTraktIdString = String.valueOf(showTraktId);
    boolean isShowNotEpisode = episodeTvdbId == 0;
    Ratings ratings;
    if (isShowNotEpisode) {
        ratings = SgTrakt.executeCall(context, traktShows.get().ratings(showTraktIdString), "get show rating");
    } else {
        ratings = SgTrakt.executeCall(context, traktEpisodes.get().ratings(showTraktIdString, season, episode), "get episode rating");
    }
    if (ratings != null && ratings.rating != null && ratings.votes != null) {
        if (isShowNotEpisode) {
            saveShowRating(ratings);
        } else {
            saveEpisodeRating(ratings);
        }
    }
    // cache download time to avoid saving ratings too frequently
    synchronized (sCache) {
        sCache.put(ratingId, currentTimeMillis);
    }
    return null;
}
Also used : Ratings(com.uwetrottmann.trakt5.entities.Ratings)

Example 3 with Ratings

use of com.uwetrottmann.trakt5.entities.Ratings in project SeriesGuide by UweTrottmann.

the class AddShowTask method doInBackground.

@Override
protected Void doInBackground(Void... params) {
    Timber.d("Starting to add shows...");
    SearchResult firstShow = addQueue.peek();
    if (firstShow == null) {
        Timber.d("Finished. Queue was empty.");
        return null;
    }
    if (!AndroidUtils.isNetworkConnected(context)) {
        Timber.d("Finished. No internet connection.");
        publishProgress(RESULT_OFFLINE, firstShow.getTmdbId(), firstShow.getTitle());
        return null;
    }
    if (isCancelled()) {
        Timber.d("Finished. Cancelled.");
        return null;
    }
    // if not connected to Hexagon, get episodes from trakt
    Map<Integer, BaseShow> traktCollection = null;
    Map<Integer, BaseShow> traktWatched = null;
    if (!HexagonSettings.isEnabled(context) && TraktCredentials.get(context).hasCredentials()) {
        Timber.d("Getting watched and collected episodes from trakt.");
        // get collection
        Map<Integer, BaseShow> traktShows = getTraktShows(true);
        if (traktShows == null) {
            // can not get collected state from trakt, give up.
            return null;
        }
        traktCollection = traktShows;
        // get watched
        traktShows = getTraktShows(false);
        if (traktShows == null) {
            // can not get watched state from trakt, give up.
            return null;
        }
        traktWatched = traktShows;
    }
    HexagonEpisodeSync hexagonEpisodeSync = new HexagonEpisodeSync(context, SgApp.getServicesComponent(context).hexagonTools());
    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;
        }
        SearchResult nextShow = addQueue.removeFirst();
        // set values required for progress update
        String currentShowName = nextShow.getTitle();
        int currentShowTmdbId = nextShow.getTmdbId();
        if (currentShowTmdbId <= 0) {
            // Invalid ID, should never have been passed, report.
            // Background: Hexagon gets requests with ID 0.
            IllegalStateException invalidIdException = new IllegalStateException("Show id invalid: " + currentShowTmdbId + ", silentMode=" + isSilentMode + ", merging=" + isMergingShows);
            Errors.logAndReport("Add show", invalidIdException);
            continue;
        }
        if (!AndroidUtils.isNetworkConnected(context)) {
            Timber.d("Finished. No connection.");
            publishProgress(RESULT_OFFLINE, currentShowTmdbId, currentShowName);
            failedMergingShows = true;
            break;
        }
        ShowResult addResult = SgApp.getServicesComponent(context).showTools().addShow(nextShow.getTmdbId(), nextShow.getLanguage(), traktCollection, traktWatched, hexagonEpisodeSync);
        if (addResult == ShowResult.SUCCESS) {
            result = PROGRESS_SUCCESS;
            addedAtLeastOneShow = true;
        } else if (addResult == ShowResult.IN_DATABASE) {
            result = PROGRESS_EXISTS;
        } else {
            Timber.e("Adding show failed: %s", addResult);
            // not because it does not (longer) exist.
            if (isMergingShows && addResult != ShowResult.DOES_NOT_EXIST) {
                failedMergingShows = true;
            }
            switch(addResult) {
                case DOES_NOT_EXIST:
                    result = PROGRESS_ERROR_TVDB_NOT_EXISTS;
                    break;
                case TMDB_ERROR:
                    result = PROGRESS_ERROR_TVDB;
                    break;
                case TRAKT_ERROR:
                    result = PROGRESS_ERROR_TRAKT;
                    break;
                case HEXAGON_ERROR:
                    result = PROGRESS_ERROR_HEXAGON;
                    break;
                case DATABASE_ERROR:
                    result = PROGRESS_ERROR_DATA;
                    break;
                default:
                    result = PROGRESS_ERROR;
                    break;
            }
        }
        publishProgress(result, currentShowTmdbId, currentShowName);
        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(context, true);
    }
    if (addedAtLeastOneShow) {
        // make sure the next sync will download all ratings
        PreferenceManager.getDefaultSharedPreferences(context).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.");
        SeriesGuideDatabase.rebuildFtsTable(context);
    }
    Timber.d("Finished adding shows.");
    return null;
}
Also used : BaseShow(com.uwetrottmann.trakt5.entities.BaseShow) HexagonEpisodeSync(com.battlelancer.seriesguide.sync.HexagonEpisodeSync) ShowResult(com.battlelancer.seriesguide.ui.shows.ShowTools2.ShowResult) SuppressLint(android.annotation.SuppressLint)

Example 4 with Ratings

use of com.uwetrottmann.trakt5.entities.Ratings 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 5 with Ratings

use of com.uwetrottmann.trakt5.entities.Ratings 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)

Aggregations

OperationApplicationException (android.content.OperationApplicationException)6 ArrayList (java.util.ArrayList)6 List (java.util.List)6 ContentProviderOperation (android.content.ContentProviderOperation)4 Ratings (com.uwetrottmann.trakt5.entities.Ratings)3 IOException (java.io.IOException)3 LinkedList (java.util.LinkedList)3 Movie (com.uwetrottmann.tmdb2.entities.Movie)2 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 HashMap (java.util.HashMap)2 SuppressLint (android.annotation.SuppressLint)1 Intent (android.content.Intent)1 Cursor (android.database.Cursor)1 Bitmap (android.graphics.Bitmap)1 NestedScrollView (android.support.v4.widget.NestedScrollView)1 Palette (android.support.v7.graphics.Palette)1