From 5caaaa9e5a3305f25338eea72af7f413b9d43969 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 7 Feb 2020 00:41:44 +0100 Subject: [PATCH] Initial database support for chapter images --- .../test/antennapod/storage/DBTestUtils.java | 3 +- .../danoeh/antennapod/core/feed/Chapter.java | 136 ++++++++------- .../antennapod/core/feed/ID3Chapter.java | 50 +++--- .../antennapod/core/feed/SimpleChapter.java | 27 +-- .../core/feed/VorbisCommentChapter.java | 161 ++++++++---------- .../antennapod/core/storage/DBReader.java | 13 +- .../antennapod/core/storage/DBUpgrader.java | 8 +- .../antennapod/core/storage/PodDBAdapter.java | 4 +- .../namespace/NSSimpleChapters.java | 9 +- 9 files changed, 194 insertions(+), 217 deletions(-) diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java index ebf59fea7..840a7d01f 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java @@ -58,7 +58,8 @@ class DBTestUtils { List chapters = new ArrayList<>(); item.setChapters(chapters); for (int k = 0; k < numChapters; k++) { - chapters.add(new SimpleChapter(k, "item " + j + " chapter " + k, item, "http://example.com")); + chapters.add(new SimpleChapter(k, "item " + j + " chapter " + k, + "http://example.com", "http://example.com/image.png")); } } f.getItems().add(item); diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java index f3dfdfdb6..2af946c67 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java @@ -2,85 +2,99 @@ package de.danoeh.antennapod.core.feed; import android.database.Cursor; +import android.text.TextUtils; import de.danoeh.antennapod.core.storage.PodDBAdapter; +import java.util.Objects; + public abstract class Chapter extends FeedComponent { - /** Defines starting point in milliseconds. */ + /** Defines starting point in milliseconds. */ long start; - String title; - String link; + String title; + String link; + String imageUrl; - Chapter() { - } - - Chapter(long start) { - super(); - this.start = start; - } + Chapter() { + } - Chapter(long start, String title, FeedItem item, String link) { - super(); - this.start = start; - this.title = title; - this.link = link; - } + Chapter(long start) { + super(); + this.start = start; + } - public static Chapter fromCursor(Cursor cursor, FeedItem item) { - int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); - int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_TITLE); - int indexStart = cursor.getColumnIndex(PodDBAdapter.KEY_START); - int indexLink = cursor.getColumnIndex(PodDBAdapter.KEY_LINK); - int indexChapterType = cursor.getColumnIndex(PodDBAdapter.KEY_CHAPTER_TYPE); + Chapter(long start, String title, String link, String imageUrl) { + super(); + this.start = start; + this.title = title; + this.link = link; + this.imageUrl = imageUrl; + } - long id = cursor.getLong(indexId); - String title = cursor.getString(indexTitle); - long start = cursor.getLong(indexStart); - String link = cursor.getString(indexLink); - int chapterType = cursor.getInt(indexChapterType); + public static Chapter fromCursor(Cursor cursor) { + int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); + int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_TITLE); + int indexStart = cursor.getColumnIndex(PodDBAdapter.KEY_START); + int indexLink = cursor.getColumnIndex(PodDBAdapter.KEY_LINK); + int indexImage = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE_URL); + int indexChapterType = cursor.getColumnIndex(PodDBAdapter.KEY_CHAPTER_TYPE); - Chapter chapter = null; - 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; - } - chapter.setId(id); - return chapter; - } + long id = cursor.getLong(indexId); + String title = cursor.getString(indexTitle); + long start = cursor.getLong(indexStart); + String link = cursor.getString(indexLink); + String imageUrl = cursor.getString(indexImage); + int chapterType = cursor.getInt(indexChapterType); + Chapter chapter = null; + switch (chapterType) { + case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: + chapter = new SimpleChapter(start, title, link, imageUrl); + break; + case ID3Chapter.CHAPTERTYPE_ID3CHAPTER: + chapter = new ID3Chapter(start, title, link, imageUrl); + break; + case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER: + chapter = new VorbisCommentChapter(start, title, link, imageUrl); + break; + } + chapter.setId(id); + return chapter; + } - public abstract int getChapterType(); + public abstract int getChapterType(); - public long getStart() { - return start; - } + public long getStart() { + return start; + } - public String getTitle() { - return title; - } + public String getTitle() { + return title; + } - public String getLink() { - return link; - } + public String getLink() { + return link; + } - public void setStart(long start) { - this.start = start; - } + public void setStart(long start) { + this.start = start; + } - public void setTitle(String title) { - this.title = title; - } + public void setTitle(String title) { + this.title = title; + } - public void setLink(String link) { - this.link = link; - } + public void setLink(String link) { + this.link = link; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } @Override public String getHumanReadableIdentifier() { diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java index f0ff03a93..b69d537fb 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java @@ -1,36 +1,36 @@ package de.danoeh.antennapod.core.feed; public class ID3Chapter extends Chapter { - public static final int CHAPTERTYPE_ID3CHAPTER = 2; + public static final int CHAPTERTYPE_ID3CHAPTER = 2; - /** - * Identifies the chapter in its ID3 tag. This attribute does not have to be - * store in the DB and is only used for parsing. - */ - private String id3ID; + /** + * Identifies the chapter in its ID3 tag. This attribute does not have to be + * store in the DB and is only used for parsing. + */ + private String id3ID; - public ID3Chapter(String id3ID, long start) { - super(start); - this.id3ID = id3ID; - } + public ID3Chapter(String id3ID, long start) { + super(start); + this.id3ID = id3ID; + } - public ID3Chapter(long start, String title, FeedItem item, String link) { - super(start, title, item, link); - } + public ID3Chapter(long start, String title, String link, String imageUrl) { + super(start, title, link, imageUrl); + } - @Override - public String toString() { - return "ID3Chapter [id3ID=" + id3ID + ", title=" + title + ", start=" - + start + ", url=" + link + "]"; - } + @Override + public String toString() { + return "ID3Chapter [id3ID=" + id3ID + ", title=" + title + ", start=" + + start + ", url=" + link + "]"; + } - @Override - public int getChapterType() { - return CHAPTERTYPE_ID3CHAPTER; - } + @Override + public int getChapterType() { + return CHAPTERTYPE_ID3CHAPTER; + } - public String getId3ID() { - return id3ID; - } + public String getId3ID() { + return id3ID; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java index 2dadd3ec8..45c71a014 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java @@ -1,25 +1,14 @@ package de.danoeh.antennapod.core.feed; public class SimpleChapter extends Chapter { - public static final int CHAPTERTYPE_SIMPLECHAPTER = 0; - - public SimpleChapter(long start, String title, FeedItem item, String link) { - super(start, title, item, link); - } + public static final int CHAPTERTYPE_SIMPLECHAPTER = 0; - @Override - public int getChapterType() { - return CHAPTERTYPE_SIMPLECHAPTER; - } + public SimpleChapter(long start, String title, String link, String imageUrl) { + super(start, title, link, imageUrl); + } - public void updateFromOther(SimpleChapter other) { - super.updateFromOther(other); - start = other.start; - if (other.title != null) { - title = other.title; - } - if (other.link != null) { - link = other.link; - } - } + @Override + public int getChapterType() { + return CHAPTERTYPE_SIMPLECHAPTER; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java index 5ab9868a6..eac50aed8 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java @@ -5,105 +5,84 @@ import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentReaderException; public class VorbisCommentChapter extends Chapter { - public static final int CHAPTERTYPE_VORBISCOMMENT_CHAPTER = 3; + public static final int CHAPTERTYPE_VORBISCOMMENT_CHAPTER = 3; - private static final int CHAPTERXXX_LENGTH = "chapterxxx".length(); + private static final int CHAPTERXXX_LENGTH = "chapterxxx".length(); - private int vorbisCommentId; + private int vorbisCommentId; - public VorbisCommentChapter(int vorbisCommentId) { - this.vorbisCommentId = vorbisCommentId; - } + public VorbisCommentChapter(int vorbisCommentId) { + this.vorbisCommentId = vorbisCommentId; + } - public VorbisCommentChapter(long start, String title, FeedItem item, - String link) { - super(start, title, item, link); - } + public VorbisCommentChapter(long start, String title, String link, String imageUrl) { + super(start, title, link, imageUrl); + } - @Override - public String toString() { - return "VorbisCommentChapter [id=" + id + ", title=" + title - + ", link=" + link + ", start=" + start + "]"; - } + @Override + public String toString() { + return "VorbisCommentChapter [id=" + id + ", title=" + title + + ", link=" + link + ", start=" + start + "]"; + } - public static long getStartTimeFromValue(String value) - throws VorbisCommentReaderException { - String[] parts = value.split(":"); - if (parts.length >= 3) { - try { - long hours = TimeUnit.MILLISECONDS.convert( - Long.parseLong(parts[0]), TimeUnit.HOURS); - long minutes = TimeUnit.MILLISECONDS.convert( - Long.parseLong(parts[1]), TimeUnit.MINUTES); - if (parts[2].contains("-->")) { - parts[2] = parts[2].substring(0, parts[2].indexOf("-->")); - } - long seconds = TimeUnit.MILLISECONDS.convert( - ((long) Float.parseFloat(parts[2])), TimeUnit.SECONDS); - return hours + minutes + seconds; - } catch (NumberFormatException e) { - throw new VorbisCommentReaderException(e); - } - } else { - throw new VorbisCommentReaderException("Invalid time string"); - } - } + public static long getStartTimeFromValue(String value) + throws VorbisCommentReaderException { + String[] parts = value.split(":"); + if (parts.length >= 3) { + try { + long hours = TimeUnit.MILLISECONDS.convert( + Long.parseLong(parts[0]), TimeUnit.HOURS); + long minutes = TimeUnit.MILLISECONDS.convert( + Long.parseLong(parts[1]), TimeUnit.MINUTES); + if (parts[2].contains("-->")) { + parts[2] = parts[2].substring(0, parts[2].indexOf("-->")); + } + long seconds = TimeUnit.MILLISECONDS.convert( + ((long) Float.parseFloat(parts[2])), TimeUnit.SECONDS); + return hours + minutes + seconds; + } catch (NumberFormatException e) { + throw new VorbisCommentReaderException(e); + } + } else { + throw new VorbisCommentReaderException("Invalid time string"); + } + } - /** - * Return the id of a vorbiscomment chapter from a string like CHAPTERxxx* - * - * @return the id of the chapter key or -1 if the id couldn't be read. - * @throws VorbisCommentReaderException - * */ - public static int getIDFromKey(String key) - throws VorbisCommentReaderException { - if (key.length() >= CHAPTERXXX_LENGTH) { // >= CHAPTERxxx - try { - String strId = key.substring(8, 10); - return Integer.parseInt(strId); - } catch (NumberFormatException e) { - throw new VorbisCommentReaderException(e); - } - } - throw new VorbisCommentReaderException("key is too short (" + key + ")"); - } + /** + * Return the id of a vorbiscomment chapter from a string like CHAPTERxxx* + * + * @return the id of the chapter key or -1 if the id couldn't be read. + * @throws VorbisCommentReaderException + * */ + public static int getIDFromKey(String key) throws VorbisCommentReaderException { + if (key.length() >= CHAPTERXXX_LENGTH) { // >= CHAPTERxxx + try { + String strId = key.substring(8, 10); + return Integer.parseInt(strId); + } catch (NumberFormatException e) { + throw new VorbisCommentReaderException(e); + } + } + throw new VorbisCommentReaderException("key is too short (" + key + ")"); + } - /** - * Get the string that comes after 'CHAPTERxxx', for example 'name' or - * 'url'. - */ - public static String getAttributeTypeFromKey(String key) { - if (key.length() > CHAPTERXXX_LENGTH) { - return key.substring(CHAPTERXXX_LENGTH, key.length()); - } - return null; - } + /** + * Get the string that comes after 'CHAPTERxxx', for example 'name' or + * 'url'. + */ + public static String getAttributeTypeFromKey(String key) { + if (key.length() > CHAPTERXXX_LENGTH) { + return key.substring(CHAPTERXXX_LENGTH); + } + return null; + } - @Override - public int getChapterType() { - return CHAPTERTYPE_VORBISCOMMENT_CHAPTER; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setLink(String link) { - this.link = link; - } - - public void setStart(long start) { - this.start = start; - } - - public int getVorbisCommentId() { - return vorbisCommentId; - } - - public void setVorbisCommentId(int vorbisCommentId) { - this.vorbisCommentId = vorbisCommentId; - } - - + @Override + public int getChapterType() { + return CHAPTERTYPE_VORBISCOMMENT_CHAPTER; + } + public int getVorbisCommentId() { + return vorbisCommentId; + } } 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 4f4ee4721..e818f3072 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 @@ -795,9 +795,7 @@ public final class DBReader { } private static void loadChaptersOfFeedItem(PodDBAdapter adapter, FeedItem item) { - Cursor cursor = null; - try { - cursor = adapter.getSimpleChaptersOfFeedItemCursor(item); + try (Cursor cursor = adapter.getSimpleChaptersOfFeedItemCursor(item)) { int chaptersCount = cursor.getCount(); if (chaptersCount == 0) { item.setChapters(null); @@ -805,14 +803,7 @@ public final class DBReader { } item.setChapters(new ArrayList<>(chaptersCount)); while (cursor.moveToNext()) { - Chapter chapter = Chapter.fromCursor(cursor, item); - if (chapter != null) { - item.getChapters().add(chapter); - } - } - } finally { - if (cursor != null) { - cursor.close(); + item.getChapters().add(Chapter.fromCursor(cursor)); } } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java index 234ce8367..ee31c8cc4 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java @@ -95,7 +95,7 @@ class DBUpgrader { + " ADD COLUMN " + PodDBAdapter.KEY_PASSWORD + " TEXT"); db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS - + " ADD COLUMN " + PodDBAdapter.KEY_IMAGE + + " ADD COLUMN image" + " INTEGER"); } if (oldVersion <= 12) { @@ -280,13 +280,13 @@ class DBUpgrader { + " SELECT " + PodDBAdapter.KEY_DOWNLOAD_URL + " FROM " + PodDBAdapter.TABLE_NAME_FEED_IMAGES + " WHERE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES + "." + PodDBAdapter.KEY_ID - + " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_IMAGE + ")"); + + " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + ".image)"); db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + " SET " + PodDBAdapter.KEY_IMAGE_URL + " = (" + " SELECT " + PodDBAdapter.KEY_DOWNLOAD_URL + " FROM " + PodDBAdapter.TABLE_NAME_FEED_IMAGES + " WHERE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES + "." + PodDBAdapter.KEY_ID - + " = " + PodDBAdapter.TABLE_NAME_FEEDS + "." + PodDBAdapter.KEY_IMAGE + ")"); + + " = " + PodDBAdapter.TABLE_NAME_FEEDS + ".image)"); db.execSQL("DROP TABLE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES); } @@ -301,6 +301,8 @@ class DBUpgrader { if (oldVersion < 1090000) { db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_FEED_VOLUME_ADAPTION + " INTEGER DEFAULT 0"); + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS + + " ADD COLUMN " + PodDBAdapter.KEY_IMAGE_URL + " TEXT DEFAULT NULL"); } } 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 4e2588f22..af6a8ef81 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 @@ -69,7 +69,6 @@ public class PodDBAdapter { public static final String KEY_POSITION = "position"; public static final String KEY_SIZE = "filesize"; public static final String KEY_MIME_TYPE = "mime_type"; - public static final String KEY_IMAGE = "image"; public static final String KEY_IMAGE_URL = "image_url"; public static final String KEY_FEED = "feed"; public static final String KEY_MEDIA = "media"; @@ -183,7 +182,7 @@ public class PodDBAdapter { private static final String CREATE_TABLE_SIMPLECHAPTERS = "CREATE TABLE " + TABLE_NAME_SIMPLECHAPTERS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE + " TEXT," + KEY_START + " INTEGER," + KEY_FEEDITEM + " INTEGER," - + KEY_LINK + " TEXT," + KEY_CHAPTER_TYPE + " INTEGER)"; + + KEY_LINK + " TEXT," + KEY_IMAGE_URL + " TEXT," + KEY_CHAPTER_TYPE + " INTEGER)"; // SQL Statements for creating indexes static final String CREATE_INDEX_FEEDITEMS_FEED = "CREATE INDEX " @@ -674,6 +673,7 @@ public class PodDBAdapter { values.put(KEY_START, chapter.getStart()); values.put(KEY_FEEDITEM, item.getId()); values.put(KEY_LINK, chapter.getLink()); + values.put(KEY_IMAGE_URL, chapter.getImageUrl()); values.put(KEY_CHAPTER_TYPE, chapter.getChapterType()); if (chapter.getId() == 0) { chapter.setId(db.insert(TABLE_NAME_SIMPLECHAPTERS, null, values)); diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java index 45266569a..5761f37c8 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java @@ -22,12 +22,12 @@ public class NSSimpleChapters extends Namespace { private static final String START = "start"; private static final String TITLE = "title"; private static final String HREF = "href"; + private static final String IMAGE = "image"; @Override - public SyndElement handleElementStart(String localName, HandlerState state, - Attributes attributes) { + public SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes) { FeedItem currentItem = state.getCurrentItem(); - if(currentItem != null) { + if (currentItem != null) { if (localName.equals(CHAPTERS)) { currentItem.setChapters(new ArrayList<>()); } else if (localName.equals(CHAPTER)) { @@ -35,7 +35,8 @@ public class NSSimpleChapters extends Namespace { long start = DateUtils.parseTimeString(attributes.getValue(START)); String title = attributes.getValue(TITLE); String link = attributes.getValue(HREF); - SimpleChapter chapter = new SimpleChapter(start, title, currentItem, link); + String imageUrl = attributes.getValue(IMAGE); + SimpleChapter chapter = new SimpleChapter(start, title, link, imageUrl); currentItem.getChapters().add(chapter); } catch (NumberFormatException e) { Log.e(TAG, "Unable to read chapter", e);