Remove FeedComponent and FeedFile class (#6949)

We want to be more flexible in what we store for each type of item. Also rename misleading function (lastUpdate to lastModified)
This commit is contained in:
ByteHamster 2024-03-02 09:50:24 +01:00 committed by GitHub
parent fa9dd8cb5a
commit ee99ef934c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 225 additions and 334 deletions

View File

@ -7,7 +7,7 @@ import android.util.Log;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import de.danoeh.antennapod.model.feed.FeedFile; import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.storage.preferences.UserPreferences; import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequest; import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequest;
import de.danoeh.antennapod.model.download.DownloadResult; import de.danoeh.antennapod.model.download.DownloadResult;
@ -60,8 +60,8 @@ public class HttpDownloaderTest {
urlAuth = httpServer.getBaseUrl() + "/basic-auth/user/passwd"; urlAuth = httpServer.getBaseUrl() + "/basic-auth/user/passwd";
} }
private FeedFileImpl setupFeedFile(String downloadUrl, String title, boolean deleteExisting) { private Feed setupFeedFile(String downloadUrl, String title, boolean deleteExisting) {
FeedFileImpl feedfile = new FeedFileImpl(downloadUrl); Feed feedfile = new Feed(downloadUrl, "");
String fileUrl = new File(destDir, title).getAbsolutePath(); String fileUrl = new File(destDir, title).getAbsolutePath();
File file = new File(fileUrl); File file = new File(fileUrl);
if (deleteExisting) { if (deleteExisting) {
@ -77,8 +77,8 @@ public class HttpDownloaderTest {
private Downloader download(String url, String title, boolean expectedResult, boolean deleteExisting, private Downloader download(String url, String title, boolean expectedResult, boolean deleteExisting,
String username, String password) { String username, String password) {
FeedFile feedFile = setupFeedFile(url, title, deleteExisting); Feed feedFile = setupFeedFile(url, title, deleteExisting);
DownloadRequest request = new DownloadRequest(feedFile.getFile_url(), url, title, 0, feedFile.getTypeAsInt(), DownloadRequest request = new DownloadRequest(feedFile.getFile_url(), url, title, 0, Feed.FEEDFILETYPE_FEED,
username, password, null, false); username, password, null, false);
Downloader downloader = new HttpDownloader(request); Downloader downloader = new HttpDownloader(request);
downloader.call(); downloader.call();
@ -113,9 +113,9 @@ public class HttpDownloaderTest {
@Test @Test
public void testCancel() { public void testCancel() {
final String url = httpServer.getBaseUrl() + "/delay/3"; final String url = httpServer.getBaseUrl() + "/delay/3";
FeedFileImpl feedFile = setupFeedFile(url, "delay", true); Feed feedFile = setupFeedFile(url, "delay", true);
final Downloader downloader = new HttpDownloader(new DownloadRequest(feedFile.getFile_url(), url, "delay", 0, final Downloader downloader = new HttpDownloader(new DownloadRequest(feedFile.getFile_url(), url, "delay", 0,
feedFile.getTypeAsInt(), null, null, null, false)); Feed.FEEDFILETYPE_FEED, null, null, null, false));
Thread t = new Thread() { Thread t = new Thread() {
@Override @Override
public void run() { public void run() {
@ -159,28 +159,4 @@ public class HttpDownloaderTest {
Downloader downloader = download(urlAuth, "testAuthSuccess", false, true, "user", "Wrong passwd"); Downloader downloader = download(urlAuth, "testAuthSuccess", false, true, "user", "Wrong passwd");
assertEquals(DownloadError.ERROR_UNAUTHORIZED, downloader.getResult().getReason()); assertEquals(DownloadError.ERROR_UNAUTHORIZED, downloader.getResult().getReason());
} }
/* TODO: replace with smaller test file
public void testUrlWithSpaces() {
download("http://acedl.noxsolutions.com/ace/Don't Call Salman Rushdie Sneezy in Finland.mp3", "testUrlWithSpaces", true);
}
*/
private static class FeedFileImpl extends FeedFile {
public FeedFileImpl(String download_url) {
super(null, download_url, false);
}
@Override
public String getHumanReadableIdentifier() {
return download_url;
}
@Override
public int getTypeAsInt() {
return 0;
}
}
} }

View File

@ -242,8 +242,8 @@ public class LocalFeedUpdater {
} }
private static void reportError(Feed feed, String reasonDetailed) { private static void reportError(Feed feed, String reasonDetailed) {
DownloadResult status = new DownloadResult(feed, feed.getTitle(), DownloadResult status = new DownloadResult(feed.getTitle(), feed.getId(),
DownloadError.ERROR_IO_ERROR, false, reasonDetailed); Feed.FEEDFILETYPE_FEED, false, DownloadError.ERROR_IO_ERROR, reasonDetailed);
DBWriter.addDownloadStatus(status); DBWriter.addDownloadStatus(status);
DBWriter.setFeedLastUpdateFailed(feed.getId(), true); DBWriter.setFeedLastUpdateFailed(feed.getId(), true);
} }
@ -252,7 +252,8 @@ public class LocalFeedUpdater {
* Reports a successful download status. * Reports a successful download status.
*/ */
private static void reportSuccess(Feed feed) { private static void reportSuccess(Feed feed) {
DownloadResult status = new DownloadResult(feed, feed.getTitle(), DownloadError.SUCCESS, true, null); DownloadResult status = new DownloadResult(feed.getTitle(), feed.getId(),
Feed.FEEDFILETYPE_FEED, true, DownloadError.SUCCESS, null);
DBWriter.addDownloadStatus(status); DBWriter.addDownloadStatus(status);
DBWriter.setFeedLastUpdateFailed(feed.getId(), false); DBWriter.setFeedLastUpdateFailed(feed.getId(), false);
} }

View File

@ -142,8 +142,9 @@ public class FeedUpdateWorker extends Worker {
} }
} catch (Exception e) { } catch (Exception e) {
DBWriter.setFeedLastUpdateFailed(feed.getId(), true); DBWriter.setFeedLastUpdateFailed(feed.getId(), true);
DownloadResult status = new DownloadResult(feed, feed.getTitle(), DownloadResult status = new DownloadResult(feed.getTitle(),
DownloadError.ERROR_IO_ERROR, false, e.getMessage()); feed.getId(), Feed.FEEDFILETYPE_FEED, false,
DownloadError.ERROR_IO_ERROR, e.getMessage());
DBWriter.addDownloadStatus(status); DBWriter.addDownloadStatus(status);
} }
toUpdate.remove(0); toUpdate.remove(0);

View File

@ -31,7 +31,7 @@ public class DownloadRequestCreator {
return new DownloadRequest.Builder(dest.toString(), feed) return new DownloadRequest.Builder(dest.toString(), feed)
.withAuthentication(username, password) .withAuthentication(username, password)
.lastModified(feed.getLastUpdate()); .lastModified(feed.getLastModified());
} }
public static DownloadRequest.Builder create(FeedMedia media) { public static DownloadRequest.Builder create(FeedMedia media) {

View File

@ -87,12 +87,12 @@ public class FeedParserTask implements Callable<FeedHandlerResult> {
} }
if (successful) { if (successful) {
downloadResult = new DownloadResult(feed, feed.getHumanReadableIdentifier(), DownloadError.SUCCESS, downloadResult = new DownloadResult(feed.getHumanReadableIdentifier(), feed.getId(),
successful, reasonDetailed); Feed.FEEDFILETYPE_FEED, true, DownloadError.SUCCESS, reasonDetailed);
return result; return result;
} else { } else {
downloadResult = new DownloadResult(feed, feed.getHumanReadableIdentifier(), reason, downloadResult = new DownloadResult(feed.getHumanReadableIdentifier(), feed.getId(),
successful, reasonDetailed); Feed.FEEDFILETYPE_FEED, false, reason, reasonDetailed);
return null; return null;
} }
} }

View File

@ -95,8 +95,8 @@ public class MediaDownloadedHandler implements Runnable {
Log.e(TAG, "MediaHandlerThread was interrupted"); Log.e(TAG, "MediaHandlerThread was interrupted");
} catch (ExecutionException e) { } catch (ExecutionException e) {
Log.e(TAG, "ExecutionException in MediaHandlerThread: " + e.getMessage()); Log.e(TAG, "ExecutionException in MediaHandlerThread: " + e.getMessage());
updatedStatus = new DownloadResult(media, media.getEpisodeTitle(), updatedStatus = new DownloadResult(media.getEpisodeTitle(), media.getId(),
DownloadError.ERROR_DB_ACCESS_ERROR, false, e.getMessage()); FeedMedia.FEEDFILETYPE_FEEDMEDIA, false, DownloadError.ERROR_DB_ACCESS_ERROR, e.getMessage());
} }
if (item != null) { if (item != null) {

View File

@ -243,8 +243,9 @@ public final class DBTasks {
FeedItem possibleDuplicate = searchFeedItemGuessDuplicate(newFeed.getItems(), item); FeedItem possibleDuplicate = searchFeedItemGuessDuplicate(newFeed.getItems(), item);
if (!newFeed.isLocalFeed() && possibleDuplicate != null && item != possibleDuplicate) { if (!newFeed.isLocalFeed() && possibleDuplicate != null && item != possibleDuplicate) {
// Canonical episode is the first one returned (usually oldest) // Canonical episode is the first one returned (usually oldest)
DBWriter.addDownloadStatus(new DownloadResult(savedFeed, DBWriter.addDownloadStatus(new DownloadResult(item.getTitle(),
item.getTitle(), DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE, false, savedFeed.getId(), Feed.FEEDFILETYPE_FEED, false,
DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE,
"The podcast host appears to have added the same episode twice. " "The podcast host appears to have added the same episode twice. "
+ "AntennaPod still refreshed the feed and attempted to repair it." + "AntennaPod still refreshed the feed and attempted to repair it."
+ "\n\nOriginal episode:\n" + duplicateEpisodeDetails(item) + "\n\nOriginal episode:\n" + duplicateEpisodeDetails(item)
@ -258,8 +259,9 @@ public final class DBTasks {
oldItem = searchFeedItemGuessDuplicate(savedFeed.getItems(), item); oldItem = searchFeedItemGuessDuplicate(savedFeed.getItems(), item);
if (oldItem != null) { if (oldItem != null) {
Log.d(TAG, "Repaired duplicate: " + oldItem + ", " + item); Log.d(TAG, "Repaired duplicate: " + oldItem + ", " + item);
DBWriter.addDownloadStatus(new DownloadResult(savedFeed, DBWriter.addDownloadStatus(new DownloadResult(item.getTitle(),
item.getTitle(), DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE, false, savedFeed.getId(), Feed.FEEDFILETYPE_FEED, false,
DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE,
"The podcast host changed the ID of an existing episode instead of just " "The podcast host changed the ID of an existing episode instead of just "
+ "updating the episode itself. AntennaPod still refreshed the feed and " + "updating the episode itself. AntennaPod still refreshed the feed and "
+ "attempted to repair it." + "attempted to repair it."
@ -328,7 +330,7 @@ public final class DBTasks {
} }
// update attributes // update attributes
savedFeed.setLastUpdate(newFeed.getLastUpdate()); savedFeed.setLastModified(newFeed.getLastModified());
savedFeed.setType(newFeed.getType()); savedFeed.setType(newFeed.getType());
savedFeed.setLastUpdateFailed(false); savedFeed.setLastUpdateFailed(false);

View File

@ -423,7 +423,10 @@ public class DbReaderTest {
FeedItem item2 = DBReader.getFeedItem(item1.getId()); FeedItem item2 = DBReader.getFeedItem(item1.getId());
item2.setChapters(DBReader.loadChaptersOfFeedItem(item2)); item2.setChapters(DBReader.loadChaptersOfFeedItem(item2));
assertTrue(item2.hasChapters()); assertTrue(item2.hasChapters());
assertEquals(item1.getChapters(), item2.getChapters()); assertEquals(item1.getChapters().size(), item2.getChapters().size());
for (int i = 0; i < item1.getChapters().size(); i++) {
assertEquals(item1.getChapters().get(i).getId(), item2.getChapters().get(i).getId());
}
} }
@Test @Test

View File

@ -16,7 +16,6 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import de.danoeh.antennapod.model.feed.FeedComponent;
import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.model.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.FeedMother; import de.danoeh.antennapod.core.feed.FeedMother;
@ -145,7 +144,7 @@ public class ItemEnqueuePositionCalculatorTest {
Collections.unmodifiableList(Arrays.asList( Collections.unmodifiableList(Arrays.asList(
createFeedItem(11), createFeedItem(12), createFeedItem(13), createFeedItem(14))); createFeedItem(11), createFeedItem(12), createFeedItem(13), createFeedItem(14)));
static final List<Long> QUEUE_DEFAULT_IDS = static final List<Long> QUEUE_DEFAULT_IDS =
QUEUE_DEFAULT.stream().map(FeedComponent::getId).collect(Collectors.toList()); QUEUE_DEFAULT.stream().map(FeedItem::getId).collect(Collectors.toList());
static Playable getCurrentlyPlaying(long idCurrentlyPlaying) { static Playable getCurrentlyPlaying(long idCurrentlyPlaying) {

View File

@ -56,7 +56,7 @@ public class FeedCursorMapperTest {
assertEquals("feed file url", feed.getFile_url()); assertEquals("feed file url", feed.getFile_url());
assertEquals("feed download url", feed.getDownload_url()); assertEquals("feed download url", feed.getDownload_url());
assertTrue(feed.isDownloaded()); assertTrue(feed.isDownloaded());
assertEquals("feed last update", feed.getLastUpdate()); assertEquals("feed last update", feed.getLastModified());
assertEquals("feed type", feed.getType()); assertEquals("feed type", feed.getType());
assertEquals("feed identifier", feed.getFeedIdentifier()); assertEquals("feed identifier", feed.getFeedIdentifier());
assertTrue(feed.isPaged()); assertTrue(feed.isPaged());

View File

@ -4,8 +4,6 @@ import androidx.annotation.NonNull;
import java.util.Date; import java.util.Date;
import de.danoeh.antennapod.model.feed.FeedFile;
/** /**
* Contains status attributes for one download * Contains status attributes for one download
*/ */
@ -42,18 +40,13 @@ public class DownloadResult {
private boolean successful; private boolean successful;
private final Date completionDate; private final Date completionDate;
/** public DownloadResult(String title, long feedfileId, int feedfileType, boolean successful,
* Constructor for creating new completed downloads. DownloadError reason, String reasonDetailed) {
*/ this(0, title, feedfileId, feedfileType, successful, reason, new Date(), reasonDetailed);
public DownloadResult(@NonNull FeedFile feedfile, String title, DownloadError reason, boolean successful,
String reasonDetailed) {
this(0, title, feedfile.getId(), feedfile.getTypeAsInt(), successful, reason, new Date(),
reasonDetailed);
} }
public DownloadResult(long id, String title, long feedfileId, int feedfileType, boolean successful, public DownloadResult(long id, String title, long feedfileId, int feedfileType, boolean successful,
DownloadError reason, Date completionDate, DownloadError reason, Date completionDate, String reasonDetailed) {
String reasonDetailed) {
this.id = id; this.id = id;
this.title = title; this.title = title;
this.feedfileId = feedfileId; this.feedfileId = feedfileId;

View File

@ -1,6 +1,7 @@
package de.danoeh.antennapod.model.feed; package de.danoeh.antennapod.model.feed;
public class Chapter extends FeedComponent { public class Chapter {
private long id;
/** Defines starting point in milliseconds. */ /** Defines starting point in milliseconds. */
private long start; private long start;
private String title; private String title;
@ -61,13 +62,16 @@ public class Chapter extends FeedComponent {
this.chapterId = chapterId; this.chapterId = chapterId;
} }
@Override
public String getHumanReadableIdentifier() {
return title;
}
@Override @Override
public String toString() { public String toString() {
return "ID3Chapter [title=" + getTitle() + ", start=" + getStart() + ", url=" + getLink() + "]"; return "ID3Chapter [title=" + getTitle() + ", start=" + getStart() + ", url=" + getLink() + "]";
} }
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
} }

View File

@ -3,6 +3,7 @@ package de.danoeh.antennapod.model.feed;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -13,7 +14,7 @@ import java.util.List;
* *
* @author daniel * @author daniel
*/ */
public class Feed extends FeedFile { public class Feed {
public static final int FEEDFILETYPE_FEED = 0; public static final int FEEDFILETYPE_FEED = 0;
public static final String TYPE_RSS2 = "rss"; public static final String TYPE_RSS2 = "rss";
@ -21,6 +22,10 @@ public class Feed extends FeedFile {
public static final String PREFIX_LOCAL_FOLDER = "antennapod_local:"; public static final String PREFIX_LOCAL_FOLDER = "antennapod_local:";
public static final String PREFIX_GENERATIVE_COVER = "antennapod_generative_cover:"; public static final String PREFIX_GENERATIVE_COVER = "antennapod_generative_cover:";
private long id;
private String localFileUrl;
private String downloadUrl;
private boolean downloaded;
/** /**
* title as defined by the feed. * title as defined by the feed.
*/ */
@ -51,7 +56,7 @@ public class Feed extends FeedFile {
/** /**
* String that identifies the last update (adopted from Last-Modified or ETag header). * String that identifies the last update (adopted from Last-Modified or ETag header).
*/ */
private String lastUpdate; private String lastModified;
private ArrayList<FeedFunding> fundingList; private ArrayList<FeedFunding> fundingList;
/** /**
@ -102,16 +107,18 @@ public class Feed extends FeedFile {
/** /**
* This constructor is used for restoring a feed from the database. * This constructor is used for restoring a feed from the database.
*/ */
public Feed(long id, String lastUpdate, String title, String customTitle, String link, public Feed(long id, String lastModified, String title, String customTitle, String link,
String description, String paymentLinks, String author, String language, String description, String paymentLinks, String author, String language,
String type, String feedIdentifier, String imageUrl, String fileUrl, String type, String feedIdentifier, String imageUrl, String fileUrl,
String downloadUrl, boolean downloaded, boolean paged, String nextPageLink, String downloadUrl, boolean downloaded, boolean paged, String nextPageLink,
String filter, @Nullable SortOrder sortOrder, boolean lastUpdateFailed) { String filter, @Nullable SortOrder sortOrder, boolean lastUpdateFailed) {
super(fileUrl, downloadUrl, downloaded); this.localFileUrl = fileUrl;
this.downloadUrl = downloadUrl;
this.downloaded = downloaded;
this.id = id; this.id = id;
this.feedTitle = title; this.feedTitle = title;
this.customTitle = customTitle; this.customTitle = customTitle;
this.lastUpdate = lastUpdate; this.lastModified = lastModified;
this.link = link; this.link = link;
this.description = description; this.description = description;
this.fundingList = FeedFunding.extractPaymentLinks(paymentLinks); this.fundingList = FeedFunding.extractPaymentLinks(paymentLinks);
@ -135,11 +142,11 @@ public class Feed extends FeedFile {
/** /**
* This constructor is used for test purposes. * This constructor is used for test purposes.
*/ */
public Feed(long id, String lastUpdate, String title, String link, String description, String paymentLink, public Feed(long id, String lastModified, String title, String link, String description, String paymentLink,
String author, String language, String type, String feedIdentifier, String imageUrl, String fileUrl, String author, String language, String type, String feedIdentifier, String imageUrl, String fileUrl,
String downloadUrl, boolean downloaded) { String downloadUrl, boolean downloaded) {
this(id, lastUpdate, title, null, link, description, paymentLink, author, language, type, feedIdentifier, imageUrl, this(id, lastModified, title, null, link, description, paymentLink, author, language, type, feedIdentifier,
fileUrl, downloadUrl, downloaded, false, null, null, null, false); imageUrl, fileUrl, downloadUrl, downloaded, false, null, null, null, false);
} }
/** /**
@ -153,17 +160,19 @@ public class Feed extends FeedFile {
* This constructor is used for requesting a feed download (it must not be used for anything else!). It should NOT be * This constructor is used for requesting a feed download (it must not be used for anything else!). It should NOT be
* used if the title of the feed is already known. * used if the title of the feed is already known.
*/ */
public Feed(String url, String lastUpdate) { public Feed(String url, String lastModified) {
super(null, url, false); this.localFileUrl = null;
this.lastUpdate = lastUpdate; this.downloadUrl = url;
this.downloaded = false;
this.lastModified = lastModified;
} }
/** /**
* This constructor is used for requesting a feed download (it must not be used for anything else!). It should be * This constructor is used for requesting a feed download (it must not be used for anything else!). It should be
* used if the title of the feed is already known. * used if the title of the feed is already known.
*/ */
public Feed(String url, String lastUpdate, String title) { public Feed(String url, String lastModified, String title) {
this(url, lastUpdate); this(url, lastModified);
this.feedTitle = title; this.feedTitle = title;
} }
@ -171,8 +180,8 @@ public class Feed extends FeedFile {
* This constructor is used for requesting a feed download (it must not be used for anything else!). It should be * This constructor is used for requesting a feed download (it must not be used for anything else!). It should be
* used if the title of the feed is already known. * used if the title of the feed is already known.
*/ */
public Feed(String url, String lastUpdate, String title, String username, String password) { public Feed(String url, String lastModified, String title, String username, String password) {
this(url, lastUpdate, title); this(url, lastModified, title);
preferences = new FeedPreferences(0, true, FeedPreferences.AutoDeleteAction.GLOBAL, VolumeAdaptionSetting.OFF, preferences = new FeedPreferences(0, true, FeedPreferences.AutoDeleteAction.GLOBAL, VolumeAdaptionSetting.OFF,
FeedPreferences.NewEpisodesAction.GLOBAL, username, password); FeedPreferences.NewEpisodesAction.GLOBAL, username, password);
} }
@ -194,8 +203,8 @@ public class Feed extends FeedFile {
public String getIdentifyingValue() { public String getIdentifyingValue() {
if (feedIdentifier != null && !feedIdentifier.isEmpty()) { if (feedIdentifier != null && !feedIdentifier.isEmpty()) {
return feedIdentifier; return feedIdentifier;
} else if (download_url != null && !download_url.isEmpty()) { } else if (downloadUrl != null && !downloadUrl.isEmpty()) {
return download_url; return downloadUrl;
} else if (feedTitle != null && !feedTitle.isEmpty()) { } else if (feedTitle != null && !feedTitle.isEmpty()) {
return feedTitle; return feedTitle;
} else { } else {
@ -203,14 +212,13 @@ public class Feed extends FeedFile {
} }
} }
@Override
public String getHumanReadableIdentifier() { public String getHumanReadableIdentifier() {
if (!TextUtils.isEmpty(customTitle)) { if (!TextUtils.isEmpty(customTitle)) {
return customTitle; return customTitle;
} else if (!TextUtils.isEmpty(feedTitle)) { } else if (!TextUtils.isEmpty(feedTitle)) {
return feedTitle; return feedTitle;
} else { } else {
return download_url; return downloadUrl;
} }
} }
@ -249,8 +257,15 @@ public class Feed extends FeedFile {
} }
} }
/**
* Compare's this FeedFile's attribute values with another FeedFile's
* attribute values. This method will only compare attributes which were
* read from the feed.
*
* @return true if attribute values are different, false otherwise
*/
public boolean compareWithOther(Feed other) { public boolean compareWithOther(Feed other) {
if (super.compareWithOther(other)) { if (!StringUtils.equals(downloadUrl, other.downloadUrl)) {
return true; return true;
} }
if (other.imageUrl != null) { if (other.imageUrl != null) {
@ -313,11 +328,6 @@ public class Feed extends FeedFile {
return mostRecentItem; return mostRecentItem;
} }
@Override
public int getTypeAsInt() {
return FEEDFILETYPE_FEED;
}
public String getTitle() { public String getTitle() {
return !TextUtils.isEmpty(customTitle) ? customTitle : feedTitle; return !TextUtils.isEmpty(customTitle) ? customTitle : feedTitle;
} }
@ -375,12 +385,12 @@ public class Feed extends FeedFile {
this.items = list; this.items = list;
} }
public String getLastUpdate() { public String getLastModified() {
return lastUpdate; return lastModified;
} }
public void setLastUpdate(String lastModified) { public void setLastModified(String lastModified) {
this.lastUpdate = lastModified; this.lastModified = lastModified;
} }
public String getFeedIdentifier() { public String getFeedIdentifier() {
@ -434,14 +444,44 @@ public class Feed extends FeedFile {
return preferences; return preferences;
} }
@Override
public void setId(long id) { public void setId(long id) {
super.setId(id); this.id = id;
if (preferences != null) { if (preferences != null) {
preferences.setFeedID(id); preferences.setFeedID(id);
} }
} }
public long getId() {
return id;
}
public String getFile_url() {
return localFileUrl;
}
public void setFile_url(String fileUrl) {
this.localFileUrl = fileUrl;
if (fileUrl == null) {
downloaded = false;
}
}
public String getDownload_url() {
return downloadUrl;
}
public void setDownload_url(String downloadUrl) {
this.downloadUrl = downloadUrl;
}
public boolean isDownloaded() {
return downloaded;
}
public void setDownloaded(boolean downloaded) {
this.downloaded = downloaded;
}
public int getPageNr() { public int getPageNr() {
return pageNr; return pageNr;
} }
@ -499,6 +539,6 @@ public class Feed extends FeedFile {
} }
public boolean isLocalFeed() { public boolean isLocalFeed() {
return download_url.startsWith(PREFIX_LOCAL_FOLDER); return downloadUrl.startsWith(PREFIX_LOCAL_FOLDER);
} }
} }

View File

@ -1,65 +0,0 @@
package de.danoeh.antennapod.model.feed;
/**
* Represents every possible component of a feed
*
* @author daniel
*/
public abstract class FeedComponent {
long id;
FeedComponent() {
super();
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
/**
* Update this FeedComponent's attributes with the attributes from another
* FeedComponent. This method should only update attributes which where read from
* the feed.
*/
void updateFromOther(FeedComponent other) {
}
/**
* Compare's this FeedComponent's attribute values with another FeedComponent's
* attribute values. This method will only compare attributes which were
* read from the feed.
*
* @return true if attribute values are different, false otherwise
*/
boolean compareWithOther(FeedComponent other) {
return false;
}
/**
* Should return a non-null, human-readable String so that the item can be
* identified by the user. Can be title, download-url, etc.
*/
public abstract String getHumanReadableIdentifier();
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FeedComponent)) return false;
FeedComponent that = (FeedComponent) o;
return id == that.id;
}
@Override
public int hashCode() {
return (int) (id ^ (id >>> 32));
}
}

View File

@ -1,107 +0,0 @@
package de.danoeh.antennapod.model.feed;
import android.text.TextUtils;
import java.io.File;
/**
* Represents a component of a Feed that has to be downloaded
*/
public abstract class FeedFile extends FeedComponent {
String file_url;
protected String download_url;
boolean downloaded;
/**
* Creates a new FeedFile object.
*
* @param file_url The location of the FeedFile. If this is null, the downloaded-attribute
* will automatically be set to false.
* @param download_url The location where the FeedFile can be downloaded.
* @param downloaded true if the FeedFile has been downloaded, false otherwise. This parameter
* will automatically be interpreted as false if the file_url is null.
*/
public FeedFile(String file_url, String download_url, boolean downloaded) {
super();
this.file_url = file_url;
this.download_url = download_url;
this.downloaded = (file_url != null) && downloaded;
}
public FeedFile() {
this(null, null, false);
}
public abstract int getTypeAsInt();
/**
* Update this FeedFile's attributes with the attributes from another
* FeedFile. This method should only update attributes which where read from
* the feed.
*/
void updateFromOther(FeedFile other) {
super.updateFromOther(other);
this.download_url = other.download_url;
}
/**
* Compare's this FeedFile's attribute values with another FeedFile's
* attribute values. This method will only compare attributes which were
* read from the feed.
*
* @return true if attribute values are different, false otherwise
*/
boolean compareWithOther(FeedFile other) {
if (super.compareWithOther(other)) {
return true;
}
if (!TextUtils.equals(download_url, other.download_url)) {
return true;
}
return false;
}
/**
* Returns true if the file exists at file_url.
*/
public boolean fileExists() {
if (file_url == null) {
return false;
} else {
File f = new File(file_url);
return f.exists();
}
}
public String getFile_url() {
return file_url;
}
/**
* Changes the file_url of this FeedFile. Setting this value to
* null will also set the downloaded-attribute to false.
*/
public void setFile_url(String file_url) {
this.file_url = file_url;
if (file_url == null) {
downloaded = false;
}
}
public String getDownload_url() {
return download_url;
}
public void setDownload_url(String download_url) {
this.download_url = download_url;
}
public boolean isDownloaded() {
return downloaded;
}
public void setDownloaded(boolean downloaded) {
this.downloaded = downloaded;
}
}

View File

@ -17,13 +17,14 @@ import java.util.Set;
* *
* @author daniel * @author daniel
*/ */
public class FeedItem extends FeedComponent implements Serializable { public class FeedItem implements Serializable {
/** tag that indicates this item is in the queue */ /** tag that indicates this item is in the queue */
public static final String TAG_QUEUE = "Queue"; public static final String TAG_QUEUE = "Queue";
/** tag that indicates this item is in favorites */ /** tag that indicates this item is in favorites */
public static final String TAG_FAVORITE = "Favorite"; public static final String TAG_FAVORITE = "Favorite";
private long id;
/** /**
* The id/guid that can be found in the rss/atom feed. Might not be set. * The id/guid that can be found in the rss/atom feed. Might not be set.
*/ */
@ -125,7 +126,6 @@ public class FeedItem extends FeedComponent implements Serializable {
} }
public void updateFromOther(FeedItem other) { public void updateFromOther(FeedItem other) {
super.updateFromOther(other);
if (other.imageUrl != null) { if (other.imageUrl != null) {
this.imageUrl = other.imageUrl; this.imageUrl = other.imageUrl;
} }
@ -163,6 +163,14 @@ public class FeedItem extends FeedComponent implements Serializable {
} }
} }
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
/** /**
* Returns the value that uniquely identifies this FeedItem. If the * Returns the value that uniquely identifies this FeedItem. If the
* itemIdentifier attribute is not null, it will be returned. Else it will * itemIdentifier attribute is not null, it will be returned. Else it will
@ -350,11 +358,6 @@ public class FeedItem extends FeedComponent implements Serializable {
this.imageUrl = imageUrl; this.imageUrl = imageUrl;
} }
@Override
public String getHumanReadableIdentifier() {
return title;
}
public boolean hasChapters() { public boolean hasChapters() {
return hasChapters; return hasChapters;
} }

View File

@ -12,11 +12,13 @@ import de.danoeh.antennapod.model.MediaMetadataRetrieverCompat;
import de.danoeh.antennapod.model.playback.MediaType; import de.danoeh.antennapod.model.playback.MediaType;
import de.danoeh.antennapod.model.playback.Playable; import de.danoeh.antennapod.model.playback.Playable;
import de.danoeh.antennapod.model.playback.RemoteMedia; import de.danoeh.antennapod.model.playback.RemoteMedia;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
public class FeedMedia extends FeedFile implements Playable { public class FeedMedia implements Playable {
public static final int FEEDFILETYPE_FEEDMEDIA = 2; public static final int FEEDFILETYPE_FEEDMEDIA = 2;
public static final int PLAYABLE_TYPE_FEEDMEDIA = 1; public static final int PLAYABLE_TYPE_FEEDMEDIA = 1;
public static final String FILENAME_PREFIX_EMBEDDED_COVER = "metadata-retriever:"; public static final String FILENAME_PREFIX_EMBEDDED_COVER = "metadata-retriever:";
@ -33,12 +35,16 @@ public class FeedMedia extends FeedFile implements Playable {
*/ */
private static final int CHECKED_ON_SIZE_BUT_UNKNOWN = Integer.MIN_VALUE; private static final int CHECKED_ON_SIZE_BUT_UNKNOWN = Integer.MIN_VALUE;
private long id;
private String localFileUrl;
private String downloadUrl;
private boolean downloaded;
private int duration; private int duration;
private int position; // Current position in file private int position; // Current position in file
private long lastPlayedTime; // Last time this media was played (in ms) private long lastPlayedTime; // Last time this media was played (in ms)
private int played_duration; // How many ms of this file have been played private int playedDuration; // How many ms of this file have been played
private long size; // File size in Byte private long size; // File size in Byte
private String mime_type; private String mimeType;
@Nullable private volatile FeedItem item; @Nullable private volatile FeedItem item;
private Date playbackCompletionDate; private Date playbackCompletionDate;
private int startPosition = -1; private int startPosition = -1;
@ -50,47 +56,50 @@ public class FeedMedia extends FeedFile implements Playable {
/* Used for loading item when restoring from parcel. */ /* Used for loading item when restoring from parcel. */
private long itemID; private long itemID;
public FeedMedia(FeedItem i, String download_url, long size, public FeedMedia(FeedItem i, String downloadUrl, long size,
String mime_type) { String mimeType) {
super(null, download_url, false); this.localFileUrl = null;
this.downloadUrl = downloadUrl;
this.downloaded = false;
this.item = i; this.item = i;
this.size = size; this.size = size;
this.mime_type = mime_type; this.mimeType = mimeType;
} }
public FeedMedia(long id, FeedItem item, int duration, int position, public FeedMedia(long id, FeedItem item, int duration, int position,
long size, String mime_type, String file_url, String download_url, long size, String mimeType, String localFileUrl, String downloadUrl,
boolean downloaded, Date playbackCompletionDate, int played_duration, boolean downloaded, Date playbackCompletionDate, int playedDuration,
long lastPlayedTime) { long lastPlayedTime) {
super(file_url, download_url, downloaded); this.localFileUrl = localFileUrl;
this.downloadUrl = downloadUrl;
this.downloaded = downloaded;
this.id = id; this.id = id;
this.item = item; this.item = item;
this.duration = duration; this.duration = duration;
this.position = position; this.position = position;
this.played_duration = played_duration; this.playedDuration = playedDuration;
this.playedDurationWhenStarted = played_duration; this.playedDurationWhenStarted = playedDuration;
this.size = size; this.size = size;
this.mime_type = mime_type; this.mimeType = mimeType;
this.playbackCompletionDate = playbackCompletionDate == null this.playbackCompletionDate = playbackCompletionDate == null
? null : (Date) playbackCompletionDate.clone(); ? null : (Date) playbackCompletionDate.clone();
this.lastPlayedTime = lastPlayedTime; this.lastPlayedTime = lastPlayedTime;
} }
public FeedMedia(long id, FeedItem item, int duration, int position, public FeedMedia(long id, FeedItem item, int duration, int position,
long size, String mime_type, String file_url, String download_url, long size, String mimeType, String localFileUrl, String downloadUrl,
boolean downloaded, Date playbackCompletionDate, int played_duration, boolean downloaded, Date playbackCompletionDate, int playedDuration,
Boolean hasEmbeddedPicture, long lastPlayedTime) { Boolean hasEmbeddedPicture, long lastPlayedTime) {
this(id, item, duration, position, size, mime_type, file_url, download_url, downloaded, this(id, item, duration, position, size, mimeType, localFileUrl, downloadUrl, downloaded,
playbackCompletionDate, played_duration, lastPlayedTime); playbackCompletionDate, playedDuration, lastPlayedTime);
this.hasEmbeddedPicture = hasEmbeddedPicture; this.hasEmbeddedPicture = hasEmbeddedPicture;
} }
@Override
public String getHumanReadableIdentifier() { public String getHumanReadableIdentifier() {
if (item != null && item.getTitle() != null) { if (item != null && item.getTitle() != null) {
return item.getTitle(); return item.getTitle();
} else { } else {
return download_url; return downloadUrl;
} }
} }
@ -120,28 +129,35 @@ public class FeedMedia extends FeedFile implements Playable {
* Uses mimetype to determine the type of media. * Uses mimetype to determine the type of media.
*/ */
public MediaType getMediaType() { public MediaType getMediaType() {
return MediaType.fromMimeType(mime_type); return MediaType.fromMimeType(mimeType);
} }
public void updateFromOther(FeedMedia other) { public void updateFromOther(FeedMedia other) {
super.updateFromOther(other); this.downloadUrl = other.downloadUrl;
if (other.size > 0) { if (other.size > 0) {
size = other.size; size = other.size;
} }
if (other.duration > 0 && duration <= 0) { // Do not overwrite duration that we measured after downloading if (other.duration > 0 && duration <= 0) { // Do not overwrite duration that we measured after downloading
duration = other.duration; duration = other.duration;
} }
if (other.mime_type != null) { if (other.mimeType != null) {
mime_type = other.mime_type; mimeType = other.mimeType;
} }
} }
/**
* Compare's this FeedFile's attribute values with another FeedFile's
* attribute values. This method will only compare attributes which were
* read from the feed.
*
* @return true if attribute values are different, false otherwise
*/
public boolean compareWithOther(FeedMedia other) { public boolean compareWithOther(FeedMedia other) {
if (super.compareWithOther(other)) { if (!StringUtils.equals(downloadUrl, other.downloadUrl)) {
return true; return true;
} }
if (other.mime_type != null) { if (other.mimeType != null) {
if (mime_type == null || !mime_type.equals(other.mime_type)) { if (mimeType == null || !mimeType.equals(other.mimeType)) {
return true; return true;
} }
} }
@ -154,11 +170,6 @@ public class FeedMedia extends FeedFile implements Playable {
return false; return false;
} }
@Override
public int getTypeAsInt() {
return FEEDFILETYPE_FEEDMEDIA;
}
public int getDuration() { public int getDuration() {
return duration; return duration;
} }
@ -173,7 +184,7 @@ public class FeedMedia extends FeedFile implements Playable {
} }
public int getPlayedDuration() { public int getPlayedDuration() {
return played_duration; return playedDuration;
} }
public int getPlayedDurationWhenStarted() { public int getPlayedDurationWhenStarted() {
@ -181,7 +192,7 @@ public class FeedMedia extends FeedFile implements Playable {
} }
public void setPlayedDuration(int played_duration) { public void setPlayedDuration(int played_duration) {
this.played_duration = played_duration; this.playedDuration = played_duration;
} }
public int getPosition() { public int getPosition() {
@ -229,7 +240,7 @@ public class FeedMedia extends FeedFile implements Playable {
} }
public String getMime_type() { public String getMime_type() {
return mime_type; return mimeType;
} }
@Nullable @Nullable
@ -283,18 +294,18 @@ public class FeedMedia extends FeedFile implements Playable {
dest.writeInt(duration); dest.writeInt(duration);
dest.writeInt(position); dest.writeInt(position);
dest.writeLong(size); dest.writeLong(size);
dest.writeString(mime_type); dest.writeString(mimeType);
dest.writeString(file_url); dest.writeString(localFileUrl);
dest.writeString(download_url); dest.writeString(downloadUrl);
dest.writeByte((byte) ((downloaded) ? 1 : 0)); dest.writeByte((byte) ((downloaded) ? 1 : 0));
dest.writeLong((playbackCompletionDate != null) ? playbackCompletionDate.getTime() : 0); dest.writeLong((playbackCompletionDate != null) ? playbackCompletionDate.getTime() : 0);
dest.writeInt(played_duration); dest.writeInt(playedDuration);
dest.writeLong(lastPlayedTime); dest.writeLong(lastPlayedTime);
} }
@Override @Override
public void writeToPreferences(Editor prefEditor) { public void writeToPreferences(Editor prefEditor) {
if(item != null && item.getFeed() != null) { if (item != null && item.getFeed() != null) {
prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId()); prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId());
} else { } else {
prefEditor.putLong(PREF_FEED_ID, 0L); prefEditor.putLong(PREF_FEED_ID, 0L);
@ -345,12 +356,12 @@ public class FeedMedia extends FeedFile implements Playable {
@Override @Override
public String getLocalMediaUrl() { public String getLocalMediaUrl() {
return file_url; return localFileUrl;
} }
@Override @Override
public String getStreamUrl() { public String getStreamUrl() {
return download_url; return downloadUrl;
} }
public int getStartPosition() { public int getStartPosition() {
@ -371,7 +382,36 @@ public class FeedMedia extends FeedFile implements Playable {
@Override @Override
public boolean localFileAvailable() { public boolean localFileAvailable() {
return isDownloaded() && file_url != null; return isDownloaded() && localFileUrl != null;
}
public boolean fileExists() {
if (localFileUrl == null) {
return false;
} else {
File f = new File(localFileUrl);
return f.exists();
}
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFile_url() {
return localFileUrl;
}
public boolean isDownloaded() {
return downloaded;
}
public String getDownload_url() {
return downloadUrl;
} }
public long getItemId() { public long getItemId() {
@ -381,14 +421,14 @@ public class FeedMedia extends FeedFile implements Playable {
@Override @Override
public void onPlaybackStart() { public void onPlaybackStart() {
startPosition = Math.max(position, 0); startPosition = Math.max(position, 0);
playedDurationWhenStarted = played_duration; playedDurationWhenStarted = playedDuration;
} }
@Override @Override
public void onPlaybackPause(Context context) { public void onPlaybackPause(Context context) {
if (position > startPosition) { if (position > startPosition) {
played_duration = playedDurationWhenStarted + position - startPosition; playedDuration = playedDurationWhenStarted + position - startPosition;
playedDurationWhenStarted = played_duration; playedDurationWhenStarted = playedDuration;
} }
startPosition = position; startPosition = position;
} }
@ -440,17 +480,18 @@ public class FeedMedia extends FeedFile implements Playable {
this.hasEmbeddedPicture = hasEmbeddedPicture; this.hasEmbeddedPicture = hasEmbeddedPicture;
} }
@Override
public void setDownloaded(boolean downloaded) { public void setDownloaded(boolean downloaded) {
super.setDownloaded(downloaded); this.downloaded = downloaded;
if(item != null && downloaded && item.isNew()) { if (item != null && downloaded && item.isNew()) {
item.setPlayed(false); item.setPlayed(false);
} }
} }
@Override
public void setFile_url(String file_url) { public void setFile_url(String file_url) {
super.setFile_url(file_url); this.localFileUrl = file_url;
if (file_url == null) {
downloaded = false;
}
} }
public void checkEmbeddedPicture() { public void checkEmbeddedPicture() {

View File

@ -252,7 +252,7 @@ public class DownloadRequest implements Parcelable {
this.source = UrlChecker.prepareUrl(media.getDownload_url()); this.source = UrlChecker.prepareUrl(media.getDownload_url());
this.title = media.getHumanReadableIdentifier(); this.title = media.getHumanReadableIdentifier();
this.feedfileId = media.getId(); this.feedfileId = media.getId();
this.feedfileType = media.getTypeAsInt(); this.feedfileType = FeedMedia.FEEDFILETYPE_FEEDMEDIA;
} }
public Builder(@NonNull String destination, @NonNull Feed feed) { public Builder(@NonNull String destination, @NonNull Feed feed) {
@ -260,7 +260,7 @@ public class DownloadRequest implements Parcelable {
this.source = feed.isLocalFeed() ? feed.getDownload_url() : UrlChecker.prepareUrl(feed.getDownload_url()); this.source = feed.isLocalFeed() ? feed.getDownload_url() : UrlChecker.prepareUrl(feed.getDownload_url());
this.title = feed.getHumanReadableIdentifier(); this.title = feed.getHumanReadableIdentifier();
this.feedfileId = feed.getId(); this.feedfileId = feed.getId();
this.feedfileType = feed.getTypeAsInt(); this.feedfileType = Feed.FEEDFILETYPE_FEED;
arguments.putInt(REQUEST_ARG_PAGE_NR, feed.getPageNr()); arguments.putInt(REQUEST_ARG_PAGE_NR, feed.getPageNr());
} }

View File

@ -416,7 +416,7 @@ public class PodDBAdapter {
values.put(KEY_FILE_URL, feed.getFile_url()); values.put(KEY_FILE_URL, feed.getFile_url());
values.put(KEY_DOWNLOAD_URL, feed.getDownload_url()); values.put(KEY_DOWNLOAD_URL, feed.getDownload_url());
values.put(KEY_DOWNLOADED, feed.isDownloaded()); values.put(KEY_DOWNLOADED, feed.isDownloaded());
values.put(KEY_LASTUPDATE, feed.getLastUpdate()); values.put(KEY_LASTUPDATE, feed.getLastModified());
values.put(KEY_TYPE, feed.getType()); values.put(KEY_TYPE, feed.getType());
values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier()); values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier());