diff options
Diffstat (limited to 'core/src/main')
4 files changed, 159 insertions, 79 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 d056917e1..42e4191f6 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 @@ -44,12 +44,45 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr private boolean read; private String paymentLink; private FlattrStatus flattrStatus; + + /** + * Is true if the database contains any chapters that belong to this item. This attribute is only + * written once by DBReader on initialization. + * The FeedItem might still have a non-null chapters value. In this case, the list of chapters + * has not been saved in the database yet. + * */ + private final boolean hasChapters; + + /** + * The list of chapters of this item. This might be null even if there are chapters of this item + * in the database. The 'hasChapters' attribute should be used to check if this item has any chapters. + * */ private List<Chapter> chapters; private FeedImage image; public FeedItem() { this.read = true; this.flattrStatus = new FlattrStatus(); + this.hasChapters = false; + } + + /** + * This constructor is used by DBReader. + * */ + public FeedItem(long id, String title, String link, Date pubDate, String paymentLink, long feedId, + FlattrStatus flattrStatus, boolean hasChapters, FeedImage image, boolean read, + String itemIdentifier) { + this.id = id; + this.title = title; + this.link = link; + this.pubDate = pubDate; + this.paymentLink = paymentLink; + this.feedId = feedId; + this.flattrStatus = flattrStatus; + this.hasChapters = hasChapters; + this.image = image; + this.read = read; + this.itemIdentifier = itemIdentifier; } /** @@ -64,6 +97,22 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr this.read = read; this.feed = feed; this.flattrStatus = new FlattrStatus(); + this.hasChapters = false; + } + + /** + * This constructor should be used for creating test objects involving chapter marks. + */ + public FeedItem(long id, String title, String itemIdentifier, String link, Date pubDate, boolean read, Feed feed, boolean hasChapters) { + this.id = id; + this.title = title; + this.itemIdentifier = itemIdentifier; + this.link = link; + this.pubDate = (pubDate != null) ? (Date) pubDate.clone() : null; + this.read = read; + this.feed = feed; + this.flattrStatus = new FlattrStatus(); + this.hasChapters = hasChapters; } public void updateFromOther(FeedItem other) { @@ -331,4 +380,8 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr public String getHumanReadableIdentifier() { return title; } + + public boolean hasChapters() { + return hasChapters; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java index defcfd598..2434ee0cf 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java @@ -245,14 +245,19 @@ public class FeedMedia extends FeedFile implements Playable { @Override public void loadChapterMarks() { - if (getChapters() == null && !localFileAvailable()) { + if (item == null && itemID != 0) { + item = DBReader.getFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), itemID); + } + // check if chapters are stored in db and not loaded yet. + if (item != null && item.hasChapters() && item.getChapters() == null) { + DBReader.loadChaptersOfFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), item); + } else if (item != null && item.getChapters() == null && !localFileAvailable()) { ChapterUtils.loadChaptersFromStreamUrl(this); if (getChapters() != null && item != null) { DBWriter.setFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), item); } } - } @Override diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index 6c0b6df74..217e6fba5 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -4,8 +4,22 @@ import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.core.feed.*; +import de.danoeh.antennapod.core.feed.Chapter; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedImage; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.feed.FeedPreferences; +import de.danoeh.antennapod.core.feed.ID3Chapter; +import de.danoeh.antennapod.core.feed.SimpleChapter; +import de.danoeh.antennapod.core.feed.VorbisCommentChapter; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.util.DownloadError; import de.danoeh.antennapod.core.util.comparator.DownloadStatusComparator; @@ -14,11 +28,6 @@ import de.danoeh.antennapod.core.util.comparator.PlaybackCompletionDateComparato import de.danoeh.antennapod.core.util.flattr.FlattrStatus; import de.danoeh.antennapod.core.util.flattr.FlattrThing; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; - /** * Provides methods for reading data from the AntennaPod database. * In general, all database calls in DBReader-methods are executed on the caller's thread. @@ -203,75 +212,26 @@ public final class DBReader { if (itemlistCursor.moveToFirst()) { do { - FeedItem item = new FeedItem(); - - item.setId(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_ID)); - item.setTitle(itemlistCursor - .getString(PodDBAdapter.IDX_FI_SMALL_TITLE)); - item.setLink(itemlistCursor - .getString(PodDBAdapter.IDX_FI_SMALL_LINK)); - item.setPubDate(new Date(itemlistCursor - .getLong(PodDBAdapter.IDX_FI_SMALL_PUBDATE))); - item.setPaymentLink(itemlistCursor - .getString(PodDBAdapter.IDX_FI_SMALL_PAYMENT_LINK)); - item.setFeedId(itemlistCursor - .getLong(PodDBAdapter.IDX_FI_SMALL_FEED)); - itemIds.add(String.valueOf(item.getId())); - - item.setRead((itemlistCursor - .getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0)); - item.setItemIdentifier(itemlistCursor - .getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER)); - item.setFlattrStatus(new FlattrStatus(itemlistCursor - .getLong(PodDBAdapter.IDX_FI_SMALL_FLATTR_STATUS))); - long imageIndex = itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_IMAGE); + FeedImage image = null; if (imageIndex != 0) { - item.setImage(getFeedImage(adapter, imageIndex)); + image = getFeedImage(adapter, imageIndex); } - // extract chapters - boolean hasSimpleChapters = itemlistCursor - .getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0; - if (hasSimpleChapters) { - Cursor chapterCursor = adapter - .getSimpleChaptersOfFeedItemCursor(item); - if (chapterCursor.moveToFirst()) { - item.setChapters(new ArrayList<Chapter>()); - do { - int chapterType = chapterCursor - .getInt(PodDBAdapter.KEY_CHAPTER_TYPE_INDEX); - Chapter chapter = null; - long start = chapterCursor - .getLong(PodDBAdapter.KEY_CHAPTER_START_INDEX); - String title = chapterCursor - .getString(PodDBAdapter.KEY_TITLE_INDEX); - String link = chapterCursor - .getString(PodDBAdapter.KEY_CHAPTER_LINK_INDEX); - - switch (chapterType) { - case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: - chapter = new SimpleChapter(start, title, item, - link); - break; - case ID3Chapter.CHAPTERTYPE_ID3CHAPTER: - chapter = new ID3Chapter(start, title, item, - link); - break; - case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER: - chapter = new VorbisCommentChapter(start, - title, item, link); - break; - } - if (chapter != null) { - chapter.setId(chapterCursor - .getLong(PodDBAdapter.KEY_ID_INDEX)); - item.getChapters().add(chapter); - } - } while (chapterCursor.moveToNext()); - } - chapterCursor.close(); - } + FeedItem item = new FeedItem(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_ID), + itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_TITLE), + itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_LINK), + new Date(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_PUBDATE)), + itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_PAYMENT_LINK), + itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_FEED), + new FlattrStatus(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_FLATTR_STATUS)), + itemlistCursor.getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0, + image, + (itemlistCursor.getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0), + itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER)); + + itemIds.add(String.valueOf(item.getId())); + items.add(item); } while (itemlistCursor.moveToNext()); } @@ -367,6 +327,7 @@ public final class DBReader { return feed; } + private static FeedItem getMatchingItemForMedia(long itemId, List<FeedItem> items) { for (FeedItem item : items) { @@ -689,6 +650,9 @@ public final class DBReader { if (list.size() > 0) { item = list.get(0); loadFeedDataOfFeedItemlist(context, list); + if (item.hasChapters()) { + loadChaptersOfFeedItem(adapter, item); + } } } return item; @@ -696,12 +660,13 @@ public final class DBReader { } /** - * Loads a specific FeedItem from the database. + * Loads a specific FeedItem from the database. This method should not be used for loading more + * than one FeedItem because this method might query the database several times for each item. * * @param context A context that is used for opening a database connection. * @param itemId The ID of the FeedItem - * @return The FeedItem or null if the FeedItem could not be found. All FeedComponent-attributes of the FeedItem will - * also be loaded from the database. + * @return The FeedItem or null if the FeedItem could not be found. All FeedComponent-attributes + * as well as chapter marks of the FeedItem will also be loaded from the database. */ public static FeedItem getFeedItem(final Context context, final long itemId) { if (BuildConfig.DEBUG) @@ -737,6 +702,63 @@ public final class DBReader { } /** + * Loads the list of chapters that belongs to this FeedItem if available. This method overwrites + * any chapters that this FeedItem has. If no chapters were found in the database, the chapters + * reference of the FeedItem will be set to null. + * + * @param context A context that is used for opening a database connection. + * @param item The FeedItem + */ + public static void loadChaptersOfFeedItem(final Context context, final FeedItem item) { + PodDBAdapter adapter = new PodDBAdapter(context); + adapter.open(); + loadChaptersOfFeedItem(adapter, item); + adapter.close(); + } + + static void loadChaptersOfFeedItem(PodDBAdapter adapter, FeedItem item) { + Cursor chapterCursor = adapter + .getSimpleChaptersOfFeedItemCursor(item); + if (chapterCursor.moveToFirst()) { + item.setChapters(new ArrayList<Chapter>()); + do { + int chapterType = chapterCursor + .getInt(PodDBAdapter.KEY_CHAPTER_TYPE_INDEX); + Chapter chapter = null; + long start = chapterCursor + .getLong(PodDBAdapter.KEY_CHAPTER_START_INDEX); + String title = chapterCursor + .getString(PodDBAdapter.KEY_TITLE_INDEX); + String link = chapterCursor + .getString(PodDBAdapter.KEY_CHAPTER_LINK_INDEX); + + switch (chapterType) { + case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: + chapter = new SimpleChapter(start, title, item, + link); + break; + case ID3Chapter.CHAPTERTYPE_ID3CHAPTER: + chapter = new ID3Chapter(start, title, item, + link); + break; + case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER: + chapter = new VorbisCommentChapter(start, + title, item, link); + break; + } + if (chapter != null) { + chapter.setId(chapterCursor + .getLong(PodDBAdapter.KEY_ID_INDEX)); + item.getChapters().add(chapter); + } + } while (chapterCursor.moveToNext()); + } else { + item.setChapters(null); + } + chapterCursor.close(); + } + + /** * Returns the number of downloaded episodes. * * @param context A context that is used for opening a database connection. @@ -788,7 +810,7 @@ public final class DBReader { static FeedImage getFeedImage(PodDBAdapter adapter, final long id) { Cursor cursor = adapter.getImageCursor(id); if ((cursor.getCount() == 0) || !cursor.moveToFirst()) { - throw new SQLException("No FeedImage found at index: " + id); + return null; } FeedImage image = new FeedImage(id, cursor.getString(cursor .getColumnIndex(PodDBAdapter.KEY_TITLE)), 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 79124521f..ce41147e1 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 @@ -693,7 +693,7 @@ public class PodDBAdapter { } values.put(KEY_FEED, item.getFeed().getId()); values.put(KEY_READ, item.isRead()); - values.put(KEY_HAS_CHAPTERS, item.getChapters() != null); + values.put(KEY_HAS_CHAPTERS, item.getChapters() != null || item.hasChapters()); values.put(KEY_ITEM_IDENTIFIER, item.getItemIdentifier()); values.put(KEY_FLATTR_STATUS, item.getFlattrStatus().toLong()); if (item.hasItemImage()) { @@ -848,7 +848,7 @@ public class PodDBAdapter { if (item.getMedia() != null) { removeFeedMedia(item.getMedia()); } - if (item.getChapters() != null) { + if (item.hasChapters() || item.getChapters() != null) { removeChaptersOfItem(item); } if (item.hasItemImage()) { |