diff options
Diffstat (limited to 'core')
5 files changed, 191 insertions, 2 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java index 3d8d1b6bc..807348896 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java @@ -36,6 +36,7 @@ import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.feed.SubscriptionsFilter; import de.danoeh.antennapod.core.service.download.ProxyConfig; import de.danoeh.antennapod.core.storage.APCleanupAlgorithm; +import de.danoeh.antennapod.core.storage.ExceptFavoriteCleanupAlgorithm; import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm; import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm; import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm; @@ -137,6 +138,7 @@ public class UserPreferences { public static final String PREF_CAST_ENABLED = "prefCast"; //Used for enabling Chromecast support public static final int EPISODE_CLEANUP_QUEUE = -1; public static final int EPISODE_CLEANUP_NULL = -2; + public static final int EPISODE_CLEANUP_EXCEPT_FAVORITE = -3; public static final int EPISODE_CLEANUP_DEFAULT = 0; // Constants @@ -882,7 +884,9 @@ public class UserPreferences { return new APNullCleanupAlgorithm(); } int cleanupValue = getEpisodeCleanupValue(); - if (cleanupValue == EPISODE_CLEANUP_QUEUE) { + if (cleanupValue == EPISODE_CLEANUP_EXCEPT_FAVORITE) { + return new ExceptFavoriteCleanupAlgorithm(); + } else if (cleanupValue == EPISODE_CLEANUP_QUEUE) { return new APQueueCleanupAlgorithm(); } else if (cleanupValue == EPISODE_CLEANUP_NULL) { return new APNullCleanupAlgorithm(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/ExceptFavoriteCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/ExceptFavoriteCleanupAlgorithm.java new file mode 100644 index 000000000..0a495115f --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/ExceptFavoriteCleanupAlgorithm.java @@ -0,0 +1,93 @@ +package de.danoeh.antennapod.core.storage; + +import android.content.Context; +import android.util.Log; + +import androidx.annotation.NonNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.ExecutionException; + +import de.danoeh.antennapod.core.feed.FeedItem; + +/** + * A cleanup algorithm that removes any item that isn't a favorite but only if space is needed. + */ +public class ExceptFavoriteCleanupAlgorithm extends EpisodeCleanupAlgorithm { + + private static final String TAG = "ExceptFavCleanupAlgo"; + + /** + * The maximum number of episodes that could be cleaned up. + * + * @return the number of episodes that *could* be cleaned up, if needed + */ + public int getReclaimableItems() { + return getCandidates().size(); + } + + @Override + public int performCleanup(Context context, int numberOfEpisodesToDelete) { + List<FeedItem> candidates = getCandidates(); + List<FeedItem> delete; + + // in the absence of better data, we'll sort by item publication date + Collections.sort(candidates, (lhs, rhs) -> { + Date l = lhs.getPubDate(); + Date r = rhs.getPubDate(); + + if (l != null && r != null) { + return l.compareTo(r); + } else { + // No date - compare by id which should be always incremented + return Long.compare(lhs.getId(), rhs.getId()); + } + }); + + if (candidates.size() > numberOfEpisodesToDelete) { + delete = candidates.subList(0, numberOfEpisodesToDelete); + } else { + delete = candidates; + } + + for (FeedItem item : delete) { + try { + DBWriter.deleteFeedMediaOfItem(context, item.getMedia().getId()).get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } + + int counter = delete.size(); + + + Log.i(TAG, String.format(Locale.US, + "Auto-delete deleted %d episodes (%d requested)", counter, + numberOfEpisodesToDelete)); + + return counter; + } + + @NonNull + private List<FeedItem> getCandidates() { + List<FeedItem> candidates = new ArrayList<>(); + List<FeedItem> downloadedItems = DBReader.getDownloadedItems(); + for (FeedItem item : downloadedItems) { + if (item.hasMedia() + && item.getMedia().isDownloaded() + && !item.isTagged(FeedItem.TAG_FAVORITE)) { + candidates.add(item); + } + } + return candidates; + } + + @Override + public int getDefaultCleanupParameter() { + return getNumEpisodesToCleanup(0); + } +} diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml index 6492c1aa2..6b3a10f46 100644 --- a/core/src/main/res/values/arrays.xml +++ b/core/src/main/res/values/arrays.xml @@ -96,6 +96,7 @@ </string-array> <string-array name="episode_cleanup_entries"> + <item>@string/episode_cleanup_except_favorite_removal</item> <item>@string/episode_cleanup_queue_removal</item> <item>0</item> <item>1</item> @@ -133,6 +134,7 @@ </string-array> <string-array name="episode_cleanup_values"> + <item>-3</item> <item>-1</item> <item>0</item> <item>12</item> diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 0cd8bcd54..91ec75782 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -116,6 +116,7 @@ <string name="feed_auto_download_never">Never</string> <string name="send_label">Send…</string> <string name="episode_cleanup_never">Never</string> + <string name="episode_cleanup_except_favorite_removal">When not favorited</string> <string name="episode_cleanup_queue_removal">When not in queue</string> <string name="episode_cleanup_after_listening">After finishing</string> <plurals name="episode_cleanup_hours_after_listening"> @@ -387,7 +388,7 @@ <string name="preference_search_clear_history">Clear history</string> <string name="media_player">Media player</string> <string name="pref_episode_cleanup_title">Episode Cleanup</string> - <string name="pref_episode_cleanup_summary">Episodes that aren\'t in the queue and aren\'t favorites should be eligible for removal if Auto Download needs space for new episodes</string> + <string name="pref_episode_cleanup_summary">Episodes that should be eligible for removal if Auto Download needs space for new episodes</string> <string name="pref_pauseOnDisconnect_sum">Pause playback when headphones or bluetooth are disconnected</string> <string name="pref_unpauseOnHeadsetReconnect_sum">Resume playback when the headphones are reconnected</string> <string name="pref_unpauseOnBluetoothReconnect_sum">Resume playback when bluetooth reconnects</string> diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/ExceptFavoriteCleanupAlgorithmTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/ExceptFavoriteCleanupAlgorithmTest.java new file mode 100644 index 000000000..8c02391ca --- /dev/null +++ b/core/src/test/java/de/danoeh/antennapod/core/storage/ExceptFavoriteCleanupAlgorithmTest.java @@ -0,0 +1,89 @@ +package de.danoeh.antennapod.core.storage; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.preferences.UserPreferences; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Tests that the APFavoriteCleanupAlgorithm is working correctly. + */ +@RunWith(RobolectricTestRunner.class) +public class ExceptFavoriteCleanupAlgorithmTest extends DbCleanupTests { + private final int numberOfItems = EPISODE_CACHE_SIZE * 2; + + public ExceptFavoriteCleanupAlgorithmTest() { + setCleanupAlgorithm(UserPreferences.EPISODE_CLEANUP_EXCEPT_FAVORITE); + } + + @Test + public void testPerformAutoCleanupHandleUnplayed() throws IOException { + Feed feed = new Feed("url", null, "title"); + List<FeedItem> items = new ArrayList<>(); + feed.setItems(items); + List<File> files = new ArrayList<>(); + populateItems(numberOfItems, feed, items, files, FeedItem.UNPLAYED, false, false); + + DBTasks.performAutoCleanup(context); + for (int i = 0; i < files.size(); i++) { + if (i < EPISODE_CACHE_SIZE) { + assertTrue("Only enough items should be deleted", files.get(i).exists()); + } else { + assertFalse("Expected episode to be deleted", files.get(i).exists()); + } + } + } + + @Test + public void testPerformAutoCleanupDeletesQueued() throws IOException { + Feed feed = new Feed("url", null, "title"); + List<FeedItem> items = new ArrayList<>(); + feed.setItems(items); + List<File> files = new ArrayList<>(); + populateItems(numberOfItems, feed, items, files, FeedItem.UNPLAYED, true, false); + + DBTasks.performAutoCleanup(context); + for (int i = 0; i < files.size(); i++) { + if (i < EPISODE_CACHE_SIZE) { + assertTrue("Only enough items should be deleted", files.get(i).exists()); + } else { + assertFalse("Queued episodes should be deleted", files.get(i).exists()); + } + } + } + + @Test + public void testPerformAutoCleanupSavesFavorited() throws IOException { + Feed feed = new Feed("url", null, "title"); + List<FeedItem> items = new ArrayList<>(); + feed.setItems(items); + List<File> files = new ArrayList<>(); + populateItems(numberOfItems, feed, items, files, FeedItem.UNPLAYED, false, true); + + DBTasks.performAutoCleanup(context); + for (int i = 0; i < files.size(); i++) { + assertTrue("Favorite episodes should should not be deleted", files.get(i).exists()); + } + } + + @Override + public void testPerformAutoCleanupShouldNotDeleteBecauseInQueue() throws IOException { + // Yes it should + } + + @Override + public void testPerformAutoCleanupShouldNotDeleteBecauseInQueue_withFeedsWithNoMedia() throws IOException { + // Yes it should + } +} |