Search in sources :

Example 1 with Episodes

use of com.uwetrottmann.seriesguide.backend.episodes.Episodes in project SeriesGuide by UweTrottmann.

the class HexagonEpisodeSync method downloadFlagsByTmdbId.

private DownloadFlagsResult downloadFlagsByTmdbId(long showId, int showTmdbId) {
    List<SgCloudEpisode> episodes;
    boolean onFirstPage = true;
    boolean hasMoreEpisodes = true;
    String cursor = null;
    Long lastWatchedMs = null;
    while (hasMoreEpisodes) {
        // abort if connection is lost
        if (!AndroidUtils.isNetworkConnected(context)) {
            Timber.e("downloadFlags: no network connection");
            return DownloadFlagsResult.FAILED;
        }
        try {
            // get service each time to check if auth was removed
            Episodes episodesService = hexagonTools.getEpisodesService();
            if (episodesService == null) {
                return DownloadFlagsResult.FAILED;
            }
            // build request
            Episodes.GetSgEpisodes request = episodesService.getSgEpisodes().setShowTmdbId(// use default server limit
            showTmdbId);
            if (!TextUtils.isEmpty(cursor)) {
                request.setCursor(cursor);
            }
            // execute request
            SgCloudEpisodeList response = request.execute();
            if (response == null) {
                // If empty should send status 200 and empty list, so no body is a failure.
                return DownloadFlagsResult.FAILED;
            }
            episodes = response.getEpisodes();
            // check for more items
            if (response.getCursor() != null) {
                cursor = response.getCursor();
            } else {
                hasMoreEpisodes = false;
            }
        } catch (IOException | IllegalArgumentException e) {
            // Note: JSON parser may throw IllegalArgumentException.
            Errors.logAndReportHexagon("get episodes of show", e);
            return DownloadFlagsResult.FAILED;
        }
        if (episodes == null || episodes.size() == 0) {
            if (onFirstPage) {
                // If there is no data by TMDB ID at all, try again using TVDB ID.
                return DownloadFlagsResult.NO_DATA;
            } else {
                // no more updates to apply
                break;
            }
        }
        onFirstPage = false;
        // build batch of episode flag updates
        ArrayList<SgEpisode2UpdateByNumber> batch = new ArrayList<>();
        for (SgCloudEpisode episode : episodes) {
            Pair<SgEpisode2UpdateByNumber, Long> update = buildSgEpisodeUpdate(episode.getWatchedFlag(), episode.getPlays(), episode.getIsInCollection(), episode.getUpdatedAt(), episode.getEpisodeNumber(), episode.getSeasonNumber(), showId, lastWatchedMs);
            if (update != null) {
                batch.add(update.first);
                lastWatchedMs = update.second;
            }
        }
        // execute database update
        SgRoomDatabase.getInstance(context).sgEpisode2Helper().updateWatchedAndCollectedByNumber(batch);
    }
    return new DownloadFlagsResult(true, false, lastWatchedMs);
}
Also used : SgCloudEpisode(com.uwetrottmann.seriesguide.backend.episodes.model.SgCloudEpisode) SgCloudEpisodeList(com.uwetrottmann.seriesguide.backend.episodes.model.SgCloudEpisodeList) ArrayList(java.util.ArrayList) IOException(java.io.IOException) SgEpisode2UpdateByNumber(com.battlelancer.seriesguide.provider.SgEpisode2UpdateByNumber) Episodes(com.uwetrottmann.seriesguide.backend.episodes.Episodes)

Example 2 with Episodes

use of com.uwetrottmann.seriesguide.backend.episodes.Episodes in project SeriesGuide by UweTrottmann.

the class HexagonEpisodeSync method uploadFlags.

/**
 * Uploads all watched, skipped including plays or collected episodes of this show to Hexagon.
 *
 * @return Whether the upload was successful.
 */
boolean uploadFlags(long showId, int showTmdbId) {
    // query for watched, skipped or collected episodes
    List<SgEpisode2ForSync> episodesForSync = SgRoomDatabase.getInstance(context).sgEpisode2Helper().getEpisodesForHexagonSync(showId);
    if (episodesForSync.isEmpty()) {
        Timber.d("uploadFlags: uploading none for show %d", showId);
        return true;
    } else {
        // Issues with some requests failing at Cloud due to
        // EOFException: Unexpected end of ZLIB input stream
        // Using info log to report sizes that are uploaded to determine
        // if MAX_BATCH_SIZE is actually too large.
        // https://github.com/UweTrottmann/SeriesGuide/issues/781
        Timber.i("uploadFlags: uploading %d for show %d", episodesForSync.size(), showId);
    }
    // build list of episodes to upload
    List<SgCloudEpisode> episodes = new ArrayList<>();
    int count = episodesForSync.size();
    for (int i = 0; i < count; i++) {
        SgEpisode2ForSync episodeForSync = episodesForSync.get(i);
        SgCloudEpisode episode = new SgCloudEpisode();
        episode.setSeasonNumber(episodeForSync.getSeason());
        episode.setEpisodeNumber(episodeForSync.getNumber());
        int watchedFlag = episodeForSync.getWatched();
        if (!EpisodeTools.isUnwatched(watchedFlag)) {
            // Skipped or watched.
            episode.setWatchedFlag(watchedFlag);
            episode.setPlays(episodeForSync.getPlays());
        }
        if (episodeForSync.getCollected()) {
            episode.setIsInCollection(true);
        }
        episodes.add(episode);
        // upload a batch
        boolean isLast = i + 1 == count;
        if (episodes.size() == MAX_BATCH_SIZE || isLast) {
            SgCloudEpisodeList episodeList = new SgCloudEpisodeList();
            episodeList.setEpisodes(episodes);
            episodeList.setShowTmdbId(showTmdbId);
            try {
                // get service each time to check if auth was removed
                Episodes episodesService = hexagonTools.getEpisodesService();
                if (episodesService == null) {
                    return false;
                }
                episodesService.saveSgEpisodes(episodeList).execute();
            } catch (IOException e) {
                // abort
                Errors.logAndReportHexagon("save episodes of show", e);
                return false;
            }
            // clear array
            episodes = new ArrayList<>();
        }
    }
    return true;
}
Also used : SgCloudEpisode(com.uwetrottmann.seriesguide.backend.episodes.model.SgCloudEpisode) SgEpisode2ForSync(com.battlelancer.seriesguide.provider.SgEpisode2ForSync) SgCloudEpisodeList(com.uwetrottmann.seriesguide.backend.episodes.model.SgCloudEpisodeList) ArrayList(java.util.ArrayList) Episodes(com.uwetrottmann.seriesguide.backend.episodes.Episodes) IOException(java.io.IOException)

Example 3 with Episodes

use of com.uwetrottmann.seriesguide.backend.episodes.Episodes in project SeriesGuide by UweTrottmann.

the class HexagonEpisodeSync method downloadChangedFlags.

/**
 * Downloads all episodes changed since the last time this was called and applies changes to
 * the database.
 */
public boolean downloadChangedFlags(@NonNull Map<Integer, Long> tmdbIdsToShowIds) {
    long currentTime = System.currentTimeMillis();
    SgRoomDatabase database = SgRoomDatabase.getInstance(context);
    DateTime lastSyncTime = new DateTime(HexagonSettings.getLastEpisodesSyncTime(context));
    Timber.d("downloadChangedFlags: since %s", lastSyncTime);
    List<SgCloudEpisode> episodes;
    String cursor = null;
    boolean hasMoreEpisodes = true;
    Map<Long, ShowLastWatchedInfo> showIdsToLastWatched = new HashMap<>();
    while (hasMoreEpisodes) {
        try {
            // get service each time to check if auth was removed
            Episodes episodesService = hexagonTools.getEpisodesService();
            if (episodesService == null) {
                return false;
            }
            Episodes.GetSgEpisodes request = episodesService.getSgEpisodes().setUpdatedSince(// use default server limit
            lastSyncTime);
            if (!TextUtils.isEmpty(cursor)) {
                request.setCursor(cursor);
            }
            SgCloudEpisodeList response = request.execute();
            if (response == null) {
                // we're done here
                Timber.d("downloadChangedFlags: response was null, done here");
                break;
            }
            episodes = response.getEpisodes();
            // check for more items
            if (response.getCursor() != null) {
                cursor = response.getCursor();
            } else {
                hasMoreEpisodes = false;
            }
        } catch (IOException | IllegalArgumentException e) {
            // Note: JSON parser may throw IllegalArgumentException.
            Errors.logAndReportHexagon("get updated episodes", e);
            return false;
        }
        if (episodes == null || episodes.size() == 0) {
            // nothing to do here
            break;
        }
        // build batch of episode flag updates
        ArrayList<SgEpisode2UpdateByNumber> batch = new ArrayList<>();
        for (SgCloudEpisode episode : episodes) {
            Integer showTmdbId = episode.getShowTmdbId();
            Long showId = tmdbIdsToShowIds.get(showTmdbId);
            if (showId == null) {
                // ignore, show not added on this device
                continue;
            }
            Integer watchedFlag = episode.getWatchedFlag();
            Integer playsOrNull = null;
            if (watchedFlag != null) {
                if (watchedFlag == EpisodeFlags.WATCHED) {
                    // Note: plays may be null for legacy data. Protect against invalid data.
                    if (episode.getPlays() != null && episode.getPlays() >= 1) {
                        playsOrNull = episode.getPlays();
                    } else {
                        playsOrNull = 1;
                    }
                } else {
                    // Skipped or not watched.
                    playsOrNull = 0;
                }
                // record the latest last watched time and episode ID for a show
                if (!EpisodeTools.isUnwatched(watchedFlag)) {
                    ShowLastWatchedInfo lastWatchedInfo = showIdsToLastWatched.get(showId);
                    // episodes returned in reverse chrono order, so just get the first time
                    if (lastWatchedInfo == null && episode.getUpdatedAt() != null) {
                        long updatedAtMs = episode.getUpdatedAt().getValue();
                        showIdsToLastWatched.put(showId, new ShowLastWatchedInfo(updatedAtMs, episode.getSeasonNumber(), episode.getEpisodeNumber()));
                    }
                }
            }
            batch.add(new SgEpisode2UpdateByNumber(showId, episode.getEpisodeNumber(), episode.getSeasonNumber(), watchedFlag, playsOrNull, episode.getIsInCollection()));
        }
        // execute database update
        database.sgEpisode2Helper().updateWatchedAndCollectedByNumber(batch);
    }
    if (!showIdsToLastWatched.isEmpty()) {
        // Note: it is possible that this overwrites a more recently watched episode,
        // however, the next sync should contain this episode and restore it.
        database.sgShow2Helper().updateLastWatchedMsIfLaterAndLastWatchedEpisodeId(showIdsToLastWatched, database.sgEpisode2Helper());
    }
    // store new last sync time
    PreferenceManager.getDefaultSharedPreferences(context).edit().putLong(HexagonSettings.KEY_LAST_SYNC_EPISODES, currentTime).apply();
    return true;
}
Also used : SgCloudEpisode(com.uwetrottmann.seriesguide.backend.episodes.model.SgCloudEpisode) SgRoomDatabase(com.battlelancer.seriesguide.provider.SgRoomDatabase) HashMap(java.util.HashMap) SgCloudEpisodeList(com.uwetrottmann.seriesguide.backend.episodes.model.SgCloudEpisodeList) ArrayList(java.util.ArrayList) IOException(java.io.IOException) DateTime(com.google.api.client.util.DateTime) SgEpisode2UpdateByNumber(com.battlelancer.seriesguide.provider.SgEpisode2UpdateByNumber) Episodes(com.uwetrottmann.seriesguide.backend.episodes.Episodes)

Example 4 with Episodes

use of com.uwetrottmann.seriesguide.backend.episodes.Episodes in project SeriesGuide by UweTrottmann.

the class HexagonEpisodeSync method downloadFlagsByTvdbId.

private DownloadFlagsResult downloadFlagsByTvdbId(long showId, int showTvdbId) {
    List<Episode> episodes;
    boolean hasMoreEpisodes = true;
    String cursor = null;
    Long lastWatchedMs = null;
    while (hasMoreEpisodes) {
        // abort if connection is lost
        if (!AndroidUtils.isNetworkConnected(context)) {
            Timber.e("downloadFlags: no network connection");
            return DownloadFlagsResult.FAILED;
        }
        try {
            // get service each time to check if auth was removed
            Episodes episodesService = hexagonTools.getEpisodesService();
            if (episodesService == null) {
                return DownloadFlagsResult.FAILED;
            }
            // build request
            Episodes.Get request = episodesService.get().setShowTvdbId(// use default server limit
            showTvdbId);
            if (!TextUtils.isEmpty(cursor)) {
                request.setCursor(cursor);
            }
            // execute request
            EpisodeList response = request.execute();
            if (response == null) {
                // If empty should send status 200 and empty list, so no body is a failure.
                return DownloadFlagsResult.FAILED;
            }
            episodes = response.getEpisodes();
            // check for more items
            if (response.getCursor() != null) {
                cursor = response.getCursor();
            } else {
                hasMoreEpisodes = false;
            }
        } catch (IOException | IllegalArgumentException e) {
            // Note: JSON parser may throw IllegalArgumentException.
            Errors.logAndReportHexagon("get episodes of show", e);
            return DownloadFlagsResult.FAILED;
        }
        if (episodes == null || episodes.size() == 0) {
            // nothing to do here
            break;
        }
        // build batch of episode flag updates
        ArrayList<SgEpisode2UpdateByNumber> batch = new ArrayList<>();
        for (Episode episode : episodes) {
            Pair<SgEpisode2UpdateByNumber, Long> update = buildSgEpisodeUpdate(episode.getWatchedFlag(), episode.getPlays(), episode.getIsInCollection(), episode.getUpdatedAt(), episode.getEpisodeNumber(), episode.getSeasonNumber(), showId, lastWatchedMs);
            if (update != null) {
                batch.add(update.first);
                lastWatchedMs = update.second;
            }
        }
        // execute database update
        SgRoomDatabase.getInstance(context).sgEpisode2Helper().updateWatchedAndCollectedByNumber(batch);
    }
    return new DownloadFlagsResult(true, false, lastWatchedMs);
}
Also used : ArrayList(java.util.ArrayList) IOException(java.io.IOException) SgCloudEpisode(com.uwetrottmann.seriesguide.backend.episodes.model.SgCloudEpisode) Episode(com.uwetrottmann.seriesguide.backend.episodes.model.Episode) EpisodeList(com.uwetrottmann.seriesguide.backend.episodes.model.EpisodeList) SgCloudEpisodeList(com.uwetrottmann.seriesguide.backend.episodes.model.SgCloudEpisodeList) SgEpisode2UpdateByNumber(com.battlelancer.seriesguide.provider.SgEpisode2UpdateByNumber) Episodes(com.uwetrottmann.seriesguide.backend.episodes.Episodes)

Example 5 with Episodes

use of com.uwetrottmann.seriesguide.backend.episodes.Episodes in project SeriesGuide by UweTrottmann.

the class HexagonTools method getEpisodesService.

/**
     * Returns the instance for this hexagon service or null if not signed in.
     */
@Nullable
public synchronized Episodes getEpisodesService() {
    GoogleAccountCredential credential = getAccountCredential(true);
    if (credential.getSelectedAccount() == null) {
        return null;
    }
    if (episodesService == null) {
        Episodes.Builder builder = new Episodes.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential);
        episodesService = CloudEndpointUtils.updateBuilder(app, builder).build();
    }
    return episodesService;
}
Also used : GoogleAccountCredential(com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential) Episodes(com.uwetrottmann.seriesguide.backend.episodes.Episodes) Nullable(android.support.annotation.Nullable)

Aggregations

Episodes (com.uwetrottmann.seriesguide.backend.episodes.Episodes)5 SgCloudEpisode (com.uwetrottmann.seriesguide.backend.episodes.model.SgCloudEpisode)4 SgCloudEpisodeList (com.uwetrottmann.seriesguide.backend.episodes.model.SgCloudEpisodeList)4 IOException (java.io.IOException)4 ArrayList (java.util.ArrayList)4 SgEpisode2UpdateByNumber (com.battlelancer.seriesguide.provider.SgEpisode2UpdateByNumber)3 Nullable (android.support.annotation.Nullable)1 SgEpisode2ForSync (com.battlelancer.seriesguide.provider.SgEpisode2ForSync)1 SgRoomDatabase (com.battlelancer.seriesguide.provider.SgRoomDatabase)1 GoogleAccountCredential (com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential)1 DateTime (com.google.api.client.util.DateTime)1 Episode (com.uwetrottmann.seriesguide.backend.episodes.model.Episode)1 EpisodeList (com.uwetrottmann.seriesguide.backend.episodes.model.EpisodeList)1 HashMap (java.util.HashMap)1