From f6d5c780e59687509fd0d96c3a31e5ca69697fba Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Thu, 14 Jan 2016 19:52:54 +0100 Subject: [PATCH] Auto Download: Exponential backoff when file 404s --- .../danoeh/antennapod/core/feed/FeedItem.java | 44 +++++++++++++++---- .../service/download/DownloadService.java | 3 +- .../antennapod/core/storage/DBWriter.java | 27 +++++++++++- .../antennapod/core/storage/PodDBAdapter.java | 2 +- 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java index c54cc1d5b..00b32de5f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java @@ -11,6 +11,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.asynctask.ImageResource; import de.danoeh.antennapod.core.storage.DBReader; @@ -75,7 +76,13 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr private List chapters; private FeedImage image; - private boolean autoDownload = true; + /* + * 0: auto download disabled + * 1: auto download enabled + * > 1: auto download enabled, (approx.) timestamp of the last failed attempt + * where last digit denotes the number of failed attempts + */ + private long autoDownload = 0; /** * Any tags assigned to this item @@ -93,7 +100,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr * */ public FeedItem(long id, String title, String link, Date pubDate, String paymentLink, long feedId, FlattrStatus flattrStatus, boolean hasChapters, FeedImage image, int state, - String itemIdentifier, boolean autoDownload) { + String itemIdentifier, long autoDownload) { this.id = id; this.title = title; this.link = link; @@ -162,7 +169,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr FlattrStatus flattrStatus = new FlattrStatus(cursor.getLong(indexFlattrStatus)); int state = cursor.getInt(indexRead); String itemIdentifier = cursor.getString(indexItemIdentifier); - boolean autoDownload = cursor.getInt(indexAutoDownload) > 0; + long autoDownload = cursor.getLong(indexAutoDownload); FeedItem item = new FeedItem(id, title, link, pubDate, paymentLink, feedId, flattrStatus, hasChapters, null, state, itemIdentifier, autoDownload); @@ -449,18 +456,37 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr } public void setAutoDownload(boolean autoDownload) { - this.autoDownload = autoDownload; + this.autoDownload = autoDownload ? 1 : 0; } public boolean getAutoDownload() { - return this.autoDownload; + return this.autoDownload > 0; + } + + public int getFailedAutoDownloadAttempts() { + if (autoDownload <= 1) { + return 0; + } + int failedAttempts = (int)(autoDownload % 10); + if (failedAttempts == 0) { + failedAttempts = 10; + } + return failedAttempts; } public boolean isAutoDownloadable() { - return this.hasMedia() && - false == this.getMedia().isPlaying() && - false == this.getMedia().isDownloaded() && - this.getAutoDownload(); + if (media == null || media.isPlaying() || media.isDownloaded() || autoDownload == 0) { + return false; + } + if (autoDownload == 1) { + return true; + } + int failedAttempts = getFailedAutoDownloadAttempts(); + double magicValue = 1.767; // 1.767^(10[=#maxNumAttempts]-1) = 168 hours / 7 days + int millisecondsInHour = 3600000; + long waitingTime = (long) (Math.pow(magicValue, failedAttempts - 1) * millisecondsInHour); + long grace = TimeUnit.MINUTES.toMillis(5); + return System.currentTimeMillis() > (autoDownload + waitingTime - grace); } /** diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java index bb7ff29d4..c3afff276 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java @@ -206,8 +206,7 @@ public class DownloadService extends Service { FeedItem item = media.getItem(); if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR && Integer.valueOf(status.getReasonDetailed()) == HttpURLConnection.HTTP_NOT_FOUND) { - item.setAutoDownload(false); // for event bus - DBWriter.setFeedItemAutoDownload(item, false); + DBWriter.saveFeedItemAutoDownloadFailed(item).get(); } // to make lists reload the failed item, we fake an item update EventBus.getDefault().post(FeedItemEvent.updated(item)); diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java index f74064cfc..d1d6bd750 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java @@ -977,11 +977,33 @@ public class DBWriter { * Sets the 'auto_download'-attribute of specific FeedItem. * * @param feedItem FeedItem. + * @param autoDownload true enables auto download, false disables it */ public static Future setFeedItemAutoDownload(final FeedItem feedItem, final boolean autoDownload) { - Log.d(TAG, "FeedItem[id=" + feedItem.getId() + "] SET auto_download " + autoDownload); return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setFeedItemAutoDownload(feedItem, autoDownload ? 1 : 0); + adapter.close(); + EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); + }); + } + + public static Future saveFeedItemAutoDownloadFailed(final FeedItem feedItem) { + return dbExec.submit(() -> { + int failedAttempts = feedItem.getFailedAutoDownloadAttempts() + 1; + Log.d(TAG, "failedAttempts: " + failedAttempts); + long autoDownload; + if(!feedItem.getAutoDownload() || failedAttempts >= 10) { + autoDownload = 0; // giving up, disable auto download + feedItem.setAutoDownload(false); + } else { + long now = System.currentTimeMillis(); + autoDownload = (now / 10) * 10 + failedAttempts; + Log.d(TAG, "now: " + now); + Log.d(TAG, "autoDownload: " + autoDownload); + } final PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); adapter.setFeedItemAutoDownload(feedItem, autoDownload); @@ -992,7 +1014,8 @@ public class DBWriter { /** * Sets the 'auto_download'-attribute of specific FeedItem. - * @param feed This feed's episodes will be processed. + * + * @param feed This feed's episodes will be processed. * @param autoDownload If true, auto download will be enabled for the feed's episodes. Else, */ public static Future setFeedsItemsAutoDownload(final Feed feed, diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 629b73668..915ca14c7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -794,7 +794,7 @@ public class PodDBAdapter { return status.getId(); } - public void setFeedItemAutoDownload(FeedItem feedItem, boolean autoDownload) { + public void setFeedItemAutoDownload(FeedItem feedItem, long autoDownload) { ContentValues values = new ContentValues(); values.put(KEY_AUTO_DOWNLOAD, autoDownload); db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?",