summaryrefslogtreecommitdiff
path: root/core/src/main/java/de
diff options
context:
space:
mode:
authorH. Lehmann <ByteHamster@users.noreply.github.com>2019-05-28 17:44:12 +0200
committerGitHub <noreply@github.com>2019-05-28 17:44:12 +0200
commitcb3b3ac5785651cac5161b777c7f611a03038dc8 (patch)
tree822f825c9ba3ff56fd57caf10379082cde986ec2 /core/src/main/java/de
parent83a6d70387e8df95e04f198ef99f992aef674413 (diff)
parent0a1a54d28d1824e3652f6dc968c8282a8ec4b6a0 (diff)
downloadAntennaPod-cb3b3ac5785651cac5161b777c7f611a03038dc8.zip
Merge pull request #3174 from skitt/spread-smart-shuffle
Smart shuffle: spread episodes evenly
Diffstat (limited to 'core/src/main/java/de')
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java62
1 files changed, 36 insertions, 26 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java
index 5c827dfe9..8680b2d2e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java
@@ -104,13 +104,10 @@ public class QueueSorter {
* prefer a more balanced ordering that avoids having to listen to clusters of consecutive
* episodes from the same feed. This is what "Smart Shuffle" tries to accomplish.
*
- * The Smart Shuffle algorithm involves choosing episodes (in round-robin fashion) from a
- * collection of individual, pubdate-sorted lists that each contain only items from a specific
- * feed.
- *
- * Of course, clusters of consecutive episodes <i>at the end of the queue</i> may be
- * unavoidable. This seems unlikely to be an issue for most users who presumably maintain
- * large queues with new episodes continuously being added.
+ * The Smart Shuffle algorithm involves spreading episodes from each feed out over the whole
+ * queue. To do this, we calculate the number of episodes in each feed, then a common multiple
+ * (not the smallest); each episode is then spread out, and we sort the resulting list of
+ * episodes by "spread out factor" and feed name.
*
* For example, given a queue containing three episodes each from three different feeds
* (A, B, and C), a simple pubdate sort might result in a queue that looks like the following:
@@ -152,8 +149,17 @@ public class QueueSorter {
? (f1, f2) -> f1.getPubDate().compareTo(f2.getPubDate())
: (f1, f2) -> f2.getPubDate().compareTo(f1.getPubDate());
- for (Long id : map.keySet()) {
- Collections.sort(map.get(id), itemComparator);
+ // Calculate the spread
+
+ long spread = 0;
+ for (Map.Entry<Long, List<FeedItem>> mapEntry : map.entrySet()) {
+ List<FeedItem> feedItems = mapEntry.getValue();
+ Collections.sort(feedItems, itemComparator);
+ if (spread == 0) {
+ spread = feedItems.size();
+ } else if (feedItems.size() % spread != 0){
+ spread *= feedItems.size();
+ }
}
// Create a list of the individual FeedItems lists, and sort it by feed title (ascending).
@@ -161,25 +167,29 @@ public class QueueSorter {
List<List<FeedItem>> feeds = new ArrayList<>(map.values());
Collections.sort(feeds,
- // (we use a desc sort here, since we're iterating back-to-front below)
- (f1, f2) -> f2.get(0).getFeed().getTitle().compareTo(f1.get(0).getFeed().getTitle()));
-
- // Cycle through the (sorted) feed lists in a round-robin fashion, removing the first item
- // and adding it back into to the original queue
-
- while (!feeds.isEmpty()) {
- // Iterate across the (sorted) list of feeds, removing the first item in each, and
- // appending it to the queue. Note that we're iterating back-to-front here, since we
- // will be deleting feed lists as they become empty.
- for (int i = feeds.size() - 1; i >= 0; --i) {
- List<FeedItem> items = feeds.get(i);
- queue.add(items.remove(0));
- // Removed the last item in this particular feed? Then remove this feed from the
- // list of feeds.
- if (items.isEmpty()) {
- feeds.remove(i);
+ (f1, f2) -> f1.get(0).getFeed().getTitle().compareTo(f2.get(0).getFeed().getTitle()));
+
+ // Spread each episode out
+ Map<Long, List<FeedItem>> spreadItems = new HashMap<>();
+ for (List<FeedItem> feedItems : feeds) {
+ long thisSpread = spread / feedItems.size();
+ // Starting from 0 ensures we front-load, so the queue starts with one episode from
+ // each feed in the queue
+ long itemSpread = 0;
+ for (FeedItem feedItem : feedItems) {
+ if (!spreadItems.containsKey(itemSpread)) {
+ spreadItems.put(itemSpread, new ArrayList<>());
}
+ spreadItems.get(itemSpread).add(feedItem);
+ itemSpread += thisSpread;
}
}
+
+ // Go through the spread items and add them to the queue
+ List<Long> spreads = new ArrayList<>(spreadItems.keySet());
+ Collections.sort(spreads);
+ for (long itemSpread : spreads) {
+ queue.addAll(spreadItems.get(itemSpread));
+ }
}
}