Merge pull request #5644 from ByteHamster/refresh-local-feeds-in-downloadservice

Refresh local feeds in DownloadService
This commit is contained in:
ByteHamster 2022-01-06 15:48:05 +01:00 committed by GitHub
commit ba17dd53f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 58 deletions

View File

@ -8,8 +8,9 @@ import android.text.TextUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import de.danoeh.antennapod.model.feed.FeedFile; import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.core.util.URLChecker; import de.danoeh.antennapod.core.util.URLChecker;
import de.danoeh.antennapod.model.feed.FeedMedia;
public class DownloadRequest implements Parcelable { public class DownloadRequest implements Parcelable {
public static final String REQUEST_ARG_PAGE_NR = "page"; public static final String REQUEST_ARG_PAGE_NR = "page";
@ -273,12 +274,20 @@ public class DownloadRequest implements Parcelable {
private Bundle arguments = new Bundle(); private Bundle arguments = new Bundle();
private boolean initiatedByUser = true; private boolean initiatedByUser = true;
public Builder(@NonNull String destination, @NonNull FeedFile item) { public Builder(@NonNull String destination, @NonNull FeedMedia media) {
this.destination = destination; this.destination = destination;
this.source = URLChecker.prepareURL(item.getDownload_url()); this.source = URLChecker.prepareURL(media.getDownload_url());
this.title = item.getHumanReadableIdentifier(); this.title = media.getHumanReadableIdentifier();
this.feedfileId = item.getId(); this.feedfileId = media.getId();
this.feedfileType = item.getTypeAsInt(); this.feedfileType = media.getTypeAsInt();
}
public Builder(@NonNull String destination, @NonNull Feed feed) {
this.destination = destination;
this.source = feed.isLocalFeed() ? feed.getDownload_url() : URLChecker.prepareURL(feed.getDownload_url());
this.title = feed.getHumanReadableIdentifier();
this.feedfileId = feed.getId();
this.feedfileType = feed.getTypeAsInt();
} }
public void setInitiatedByUser(boolean initiatedByUser) { public void setInitiatedByUser(boolean initiatedByUser) {

View File

@ -14,13 +14,13 @@ import java.io.File;
* Creates download requests that can be sent to the DownloadService. * Creates download requests that can be sent to the DownloadService.
*/ */
public class DownloadRequestCreator { public class DownloadRequestCreator {
private static final String TAG = "DownloadRequester"; private static final String TAG = "DownloadRequestCreat";
private static final String FEED_DOWNLOADPATH = "cache/"; private static final String FEED_DOWNLOADPATH = "cache/";
private static final String MEDIA_DOWNLOADPATH = "media/"; private static final String MEDIA_DOWNLOADPATH = "media/";
public static DownloadRequest.Builder create(Feed feed) { public static DownloadRequest.Builder create(Feed feed) {
File dest = new File(getFeedfilePath(), getFeedfileName(feed)); File dest = new File(getFeedfilePath(), getFeedfileName(feed));
if (!isFilenameAvailable(dest.toString())) { if (!isFilenameAvailable(dest.toString()) && !feed.isLocalFeed()) {
dest = findUnusedFile(dest); dest = findUnusedFile(dest);
} }
Log.d(TAG, "Requesting download of url " + feed.getDownload_url()); Log.d(TAG, "Requesting download of url " + feed.getDownload_url());

View File

@ -20,6 +20,7 @@ import androidx.core.app.ServiceCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
@ -274,6 +275,10 @@ public class DownloadService extends Service {
DBTasks.autodownloadUndownloadedItems(getApplicationContext()); DBTasks.autodownloadUndownloadedItems(getApplicationContext());
} }
/**
* This method MUST NOT, in any case, throw an exception.
* Otherwise, it hangs up the refresh thread pool.
*/
private void performDownload(Downloader downloader) { private void performDownload(Downloader downloader) {
try { try {
downloader.call(); downloader.call();
@ -295,6 +300,24 @@ public class DownloadService extends Service {
}); });
} }
/**
* This method MUST NOT, in any case, throw an exception.
* Otherwise, it hangs up the refresh thread pool.
*/
private void performLocalFeedRefresh(Downloader downloader, DownloadRequest request) {
try {
Feed feed = DBReader.getFeed(request.getFeedfileId());
LocalFeedUpdater.updateFeed(feed, DownloadService.this);
} catch (Exception e) {
e.printStackTrace();
}
downloadEnqueueExecutor.submit(() -> {
downloads.remove(downloader);
stopServiceIfEverythingDone();
});
}
private void handleSuccessfulDownload(Downloader downloader) { private void handleSuccessfulDownload(Downloader downloader) {
DownloadRequest request = downloader.getDownloadRequest(); DownloadRequest request = downloader.getDownloadRequest();
DownloadStatus status = downloader.getResult(); DownloadStatus status = downloader.getResult();
@ -479,7 +502,7 @@ public class DownloadService extends Service {
boolean initiatedByUser = intent.getBooleanExtra(EXTRA_INITIATED_BY_USER, false); boolean initiatedByUser = intent.getBooleanExtra(EXTRA_INITIATED_BY_USER, false);
List<Feed> feeds = DBReader.getFeedList(); List<Feed> feeds = DBReader.getFeedList();
for (Feed feed : feeds) { for (Feed feed : feeds) {
if (feed.getPreferences().getKeepUpdated() && !feed.isLocalFeed()) { if (feed.getPreferences().getKeepUpdated()) {
DownloadRequest.Builder builder = DownloadRequestCreator.create(feed); DownloadRequest.Builder builder = DownloadRequestCreator.create(feed);
builder.setInitiatedByUser(initiatedByUser); builder.setInitiatedByUser(initiatedByUser);
addNewRequest(builder.build()); addNewRequest(builder.build());
@ -494,6 +517,12 @@ public class DownloadService extends Service {
Log.d(TAG, "Skipped enqueueing request. Already running."); Log.d(TAG, "Skipped enqueueing request. Already running.");
return; return;
} }
Log.d(TAG, "Add new request: " + request.getSource());
if (request.getSource().startsWith(Feed.PREFIX_LOCAL_FOLDER)) {
Downloader downloader = new LocalFeedStubDownloader(request);
downloads.add(downloader);
downloadHandleExecutor.submit(() -> performLocalFeedRefresh(downloader, request));
} else {
writeFileUrl(request); writeFileUrl(request);
Downloader downloader = downloaderFactory.create(request); Downloader downloader = downloaderFactory.create(request);
if (downloader != null) { if (downloader != null) {
@ -501,6 +530,7 @@ public class DownloadService extends Service {
downloadHandleExecutor.submit(() -> performDownload(downloader)); downloadHandleExecutor.submit(() -> performDownload(downloader));
} }
} }
}
@VisibleForTesting @VisibleForTesting
public static DownloaderFactory getDownloaderFactory() { public static DownloaderFactory getDownloaderFactory() {

View File

@ -0,0 +1,17 @@
package de.danoeh.antennapod.core.service.download;
import androidx.annotation.NonNull;
/**
* This does not actually download, but it keeps track of a local feed's refresh state.
*/
public class LocalFeedStubDownloader extends Downloader {
public LocalFeedStubDownloader(@NonNull DownloadRequest request) {
super(request);
}
@Override
protected void download() {
}
}

View File

@ -31,7 +31,6 @@ import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.event.FeedItemEvent; import de.danoeh.antennapod.event.FeedItemEvent;
import de.danoeh.antennapod.event.FeedListUpdateEvent; import de.danoeh.antennapod.event.FeedListUpdateEvent;
import de.danoeh.antennapod.event.MessageEvent; import de.danoeh.antennapod.event.MessageEvent;
import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.storage.mapper.FeedCursorMapper; import de.danoeh.antennapod.core.storage.mapper.FeedCursorMapper;
@ -114,14 +113,6 @@ public final class DBTasks {
* @param initiatedByUser a boolean indicating if the refresh was triggered by user action. * @param initiatedByUser a boolean indicating if the refresh was triggered by user action.
*/ */
public static void refreshAllFeeds(final Context context, boolean initiatedByUser) { public static void refreshAllFeeds(final Context context, boolean initiatedByUser) {
new Thread(() -> {
List<Feed> feeds = DBReader.getFeedList();
for (Feed feed : feeds) {
if (feed.isLocalFeed() && feed.getPreferences().getKeepUpdated()) {
LocalFeedUpdater.updateFeed(feed, context);
}
}
}).start();
DownloadService.refreshAllFeeds(context, initiatedByUser); DownloadService.refreshAllFeeds(context, initiatedByUser);
SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE); SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
@ -169,16 +160,12 @@ public final class DBTasks {
} }
private static void forceRefreshFeed(Context context, Feed feed, boolean loadAllPages, boolean initiatedByUser) { private static void forceRefreshFeed(Context context, Feed feed, boolean loadAllPages, boolean initiatedByUser) {
if (feed.isLocalFeed()) {
new Thread(() -> LocalFeedUpdater.updateFeed(feed, context)).start();
} else {
DownloadRequest.Builder builder = DownloadRequestCreator.create(feed); DownloadRequest.Builder builder = DownloadRequestCreator.create(feed);
builder.setInitiatedByUser(initiatedByUser); builder.setInitiatedByUser(initiatedByUser);
builder.setForce(true); builder.setForce(true);
builder.loadAllPages(loadAllPages); builder.loadAllPages(loadAllPages);
DownloadService.download(context, false, builder.build()); DownloadService.download(context, false, builder.build());
} }
}
/** /**
* Notifies the database about a missing FeedMedia file. This method will correct the FeedMedia object's * Notifies the database about a missing FeedMedia file. This method will correct the FeedMedia object's

View File

@ -3,14 +3,13 @@ package de.danoeh.antennapod.core.service.download;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcel; import android.os.Parcel;
import de.danoeh.antennapod.model.feed.FeedMedia;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import java.util.ArrayList; import java.util.ArrayList;
import de.danoeh.antennapod.model.feed.FeedFile;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
@ -40,7 +39,7 @@ public class DownloadRequestTest {
String destStr = "file://location/media.mp3"; String destStr = "file://location/media.mp3";
String username = "testUser"; String username = "testUser";
String password = "testPassword"; String password = "testPassword";
FeedFile item = createFeedItem(1); FeedMedia item = createFeedItem(1);
DownloadRequest request1 = new DownloadRequest.Builder(destStr, item) DownloadRequest request1 = new DownloadRequest.Builder(destStr, item)
.deleteOnFailure(true) .deleteOnFailure(true)
.withAuthentication(username, password) .withAuthentication(username, password)
@ -68,12 +67,12 @@ public class DownloadRequestTest {
ArrayList<DownloadRequest> toParcel; ArrayList<DownloadRequest> toParcel;
{ // test DownloadRequests to parcel { // test DownloadRequests to parcel
String destStr = "file://location/media.mp3"; String destStr = "file://location/media.mp3";
FeedFile item1 = createFeedItem(1); FeedMedia item1 = createFeedItem(1);
DownloadRequest request1 = new DownloadRequest.Builder(destStr, item1) DownloadRequest request1 = new DownloadRequest.Builder(destStr, item1)
.withAuthentication(username1, password1) .withAuthentication(username1, password1)
.build(); .build();
FeedFile item2 = createFeedItem(2); FeedMedia item2 = createFeedItem(2);
DownloadRequest request2 = new DownloadRequest.Builder(destStr, item2) DownloadRequest request2 = new DownloadRequest.Builder(destStr, item2)
.withAuthentication(username2, password2) .withAuthentication(username2, password2)
.build(); .build();
@ -118,28 +117,8 @@ public class DownloadRequestTest {
return sb.toString(); return sb.toString();
} }
private FeedFile createFeedItem(final int id) { private FeedMedia createFeedItem(final int id) {
// Use mockito would be less verbose, but it'll take extra 1 second for this tiny test // Use mockito would be less verbose, but it'll take extra 1 second for this tiny test
return new FeedFile() { return new FeedMedia(id, null, 0, 0, 0, "", "", "http://example.com/episode" + id, false, null, 0, 0);
@Override
public long getId() {
return id;
}
@Override
public String getDownload_url() {
return "http://example.com/episode" + id;
}
@Override
public int getTypeAsInt() {
return 0;
}
@Override
public String getHumanReadableIdentifier() {
return "human-id-" + id;
}
};
} }
} }