summaryrefslogtreecommitdiff
path: root/src/de/danoeh/antennapod
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/danoeh/antennapod')
-rw-r--r--src/de/danoeh/antennapod/feed/Chapter.java23
-rw-r--r--src/de/danoeh/antennapod/feed/FeedManager.java28
-rw-r--r--src/de/danoeh/antennapod/feed/ID3Chapter.java36
-rw-r--r--src/de/danoeh/antennapod/util/id3reader/ChapterReader.java90
-rw-r--r--src/de/danoeh/antennapod/util/id3reader/ID3Reader.java182
-rw-r--r--src/de/danoeh/antennapod/util/id3reader/ID3ReaderException.java20
-rw-r--r--src/de/danoeh/antennapod/util/id3reader/model/FrameHeader.java18
-rw-r--r--src/de/danoeh/antennapod/util/id3reader/model/Header.java29
-rw-r--r--src/de/danoeh/antennapod/util/id3reader/model/TagHeader.java26
9 files changed, 442 insertions, 10 deletions
diff --git a/src/de/danoeh/antennapod/feed/Chapter.java b/src/de/danoeh/antennapod/feed/Chapter.java
index b44723d8e..f50053f93 100644
--- a/src/de/danoeh/antennapod/feed/Chapter.java
+++ b/src/de/danoeh/antennapod/feed/Chapter.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.feed;
-public abstract class Chapter extends FeedComponent{
+public abstract class Chapter extends FeedComponent {
/** Defines starting point in milliseconds. */
protected long start;
@@ -8,6 +8,11 @@ public abstract class Chapter extends FeedComponent{
protected FeedItem item;
protected String link;
+ public Chapter(long start) {
+ super();
+ this.start = start;
+ }
+
public Chapter(long start, String title, FeedItem item, String link) {
super();
this.start = start;
@@ -34,4 +39,20 @@ public abstract class Chapter extends FeedComponent{
return link;
}
+ public void setStart(long start) {
+ this.start = start;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public void setItem(FeedItem item) {
+ this.item = item;
+ }
+
+ public void setLink(String link) {
+ this.link = link;
+ }
+
}
diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java
index 526334b2b..1c6d7036f 100644
--- a/src/de/danoeh/antennapod/feed/FeedManager.java
+++ b/src/de/danoeh/antennapod/feed/FeedManager.java
@@ -374,13 +374,13 @@ public class FeedManager {
downloadFeedItem(context, queue.toArray(new FeedItem[queue.size()]));
}
}
-
+
public void downloadFeedItem(final Context context, FeedItem... items) {
boolean autoQueue = PreferenceManager.getDefaultSharedPreferences(
context.getApplicationContext()).getBoolean(
PodcastApp.PREF_AUTO_QUEUE, true);
List<FeedItem> addToQueue = new ArrayList<FeedItem>();
-
+
for (FeedItem item : items) {
if (item.getMedia() != null
&& !requester.isDownloadingFile(item.getMedia())
@@ -390,7 +390,8 @@ public class FeedManager {
}
}
if (autoQueue) {
- addQueueItem(context, addToQueue.toArray(new FeedItem[addToQueue.size()]));
+ addQueueItem(context,
+ addToQueue.toArray(new FeedItem[addToQueue.size()]));
}
}
@@ -921,15 +922,24 @@ public class FeedManager {
if (chapterCursor.moveToFirst()) {
item.setChapters(new ArrayList<Chapter>());
do {
- int chapterType = chapterCursor.getInt(PodDBAdapter.KEY_CHAPTER_TYPE_INDEX);
+ 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);
-
+ 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);
+ chapter = new SimpleChapter(start, title, item,
+ link);
+ break;
+ case ID3Chapter.CHAPTERTYPE_ID3CHAPTER:
+ chapter = new ID3Chapter(start, title, item,
+ link);
break;
}
chapter.setId(chapterCursor
diff --git a/src/de/danoeh/antennapod/feed/ID3Chapter.java b/src/de/danoeh/antennapod/feed/ID3Chapter.java
new file mode 100644
index 000000000..6dde7854e
--- /dev/null
+++ b/src/de/danoeh/antennapod/feed/ID3Chapter.java
@@ -0,0 +1,36 @@
+package de.danoeh.antennapod.feed;
+
+public class ID3Chapter extends Chapter {
+ 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;
+
+ 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);
+ }
+
+ @Override
+ public String toString() {
+ return "ID3Chapter [id3ID=" + id3ID + ", title=" + title + ", start="
+ + start + ", url=" + link + "]";
+ }
+
+ @Override
+ public int getChapterType() {
+ return CHAPTERTYPE_ID3CHAPTER;
+ }
+
+ public String getId3ID() {
+ return id3ID;
+ }
+
+}
diff --git a/src/de/danoeh/antennapod/util/id3reader/ChapterReader.java b/src/de/danoeh/antennapod/util/id3reader/ChapterReader.java
new file mode 100644
index 000000000..3711cb644
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/id3reader/ChapterReader.java
@@ -0,0 +1,90 @@
+package de.danoeh.antennapod.util.id3reader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.danoeh.antennapod.feed.ID3Chapter;
+import de.danoeh.antennapod.util.id3reader.model.FrameHeader;
+import de.danoeh.antennapod.util.id3reader.model.TagHeader;
+
+public class ChapterReader extends ID3Reader {
+
+ private static final String FRAME_ID_CHAPTER = "CHAP";
+ private static final String FRAME_ID_TITLE = "TIT2";
+
+ private List<ID3Chapter> chapters;
+ private ID3Chapter currentChapter;
+
+ @Override
+ public int onStartTagHeader(TagHeader header) {
+ chapters = new ArrayList<ID3Chapter>();
+ System.out.println(header.toString());
+ return ID3Reader.ACTION_DONT_SKIP;
+ }
+
+ @Override
+ public int onStartFrameHeader(FrameHeader header, InputStream input)
+ throws IOException, ID3ReaderException {
+ System.out.println(header.toString());
+ if (header.getId().equals(FRAME_ID_CHAPTER)) {
+ if (currentChapter != null) {
+ if (!hasId3Chapter(currentChapter)) {
+ chapters.add(currentChapter);
+ currentChapter = null;
+ }
+ }
+ System.out.println("Found chapter");
+ String elementId = readString(input, Integer.MAX_VALUE);
+ char[] startTimeSource = readBytes(input, 4);
+ long startTime = ((int) startTimeSource[0] << 24)
+ | ((int) startTimeSource[1] << 16)
+ | ((int) startTimeSource[2] << 8) | startTimeSource[3];
+ currentChapter = new ID3Chapter(elementId, startTime);
+ skipBytes(input, 12);
+ return ID3Reader.ACTION_DONT_SKIP;
+ } else if (header.getId().equals(FRAME_ID_TITLE)) {
+ if (currentChapter != null && currentChapter.getTitle() == null) {
+ System.out.println("Found title");
+ skipBytes(input, 1);
+ currentChapter
+ .setTitle(readString(input, header.getSize() - 1));
+ return ID3Reader.ACTION_DONT_SKIP;
+ }
+ }
+
+ return super.onStartFrameHeader(header, input);
+ }
+
+ private boolean hasId3Chapter(ID3Chapter chapter) {
+ for (ID3Chapter c : chapters) {
+ if (c.getId3ID().equals(chapter.getId3ID())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onEndTag() {
+ if (currentChapter != null) {
+ if (!hasId3Chapter(currentChapter)) {
+ chapters.add(currentChapter);
+ }
+ }
+ System.out.println("Reached end of tag");
+ if (chapters != null) {
+ for (ID3Chapter c : chapters) {
+ System.out.println(c.toString());
+ }
+ }
+ }
+
+ @Override
+ public void onNoTagHeaderFound() {
+ System.out.println("No tag header found");
+ super.onNoTagHeaderFound();
+ }
+
+}
diff --git a/src/de/danoeh/antennapod/util/id3reader/ID3Reader.java b/src/de/danoeh/antennapod/util/id3reader/ID3Reader.java
new file mode 100644
index 000000000..8164170bf
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/id3reader/ID3Reader.java
@@ -0,0 +1,182 @@
+package de.danoeh.antennapod.util.id3reader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+
+import de.danoeh.antennapod.util.id3reader.model.FrameHeader;
+import de.danoeh.antennapod.util.id3reader.model.TagHeader;
+
+/**
+ * Reads the ID3 Tag of a given file. In order to use this class, you should
+ * create a subclass of it and overwrite the onStart* - or onEnd* - methods.
+ */
+public class ID3Reader {
+ private static final int HEADER_LENGTH = 10;
+ private static final int ID3_LENGTH = 3;
+ private static final int FRAME_ID_LENGTH = 4;
+
+ protected static final int ACTION_SKIP = 1;
+ protected static final int ACTION_DONT_SKIP = 2;
+
+ protected int readerPosition;
+
+ private static final char[] LITTLE_ENDIAN_BOM = { 0xff, 0xfe };
+ private static final char[] BIG_ENDIAN_BOM = { 0xfe, 0xff };
+
+ public ID3Reader() {
+ }
+
+ public final void readInputStream(InputStream input) throws IOException,
+ ID3ReaderException {
+ int rc;
+ readerPosition = 0;
+ char[] tagHeaderSource = readBytes(input, HEADER_LENGTH);
+ TagHeader tagHeader = createTagHeader(tagHeaderSource);
+ if (tagHeader == null) {
+ onNoTagHeaderFound();
+ } else {
+ rc = onStartTagHeader(tagHeader);
+ if (rc == ACTION_SKIP) {
+ onEndTag();
+ } else {
+ while (readerPosition < tagHeader.getSize()) {
+ FrameHeader frameHeader = createFrameHeader(readBytes(
+ input, HEADER_LENGTH));
+ rc = onStartFrameHeader(frameHeader, input);
+ if (rc == ACTION_SKIP) {
+ skipBytes(input, frameHeader.getSize());
+ }
+ }
+ onEndTag();
+ }
+ }
+ }
+
+ /**
+ * Read a certain number of bytes from the given input stream. This method
+ * changes the readerPosition-attribute.
+ */
+ protected char[] readBytes(InputStream input, int number)
+ throws IOException, ID3ReaderException {
+ char[] header = new char[number];
+ for (int i = 0; i < number; i++) {
+ int b = input.read();
+ readerPosition++;
+ if (b != -1) {
+ header[i] = (char) b;
+ } else {
+ throw new ID3ReaderException("Unexpected end of stream");
+ }
+ }
+ return header;
+ }
+
+ /**
+ * Skip a certain number of bytes on the given input stream. This method
+ * changes the readerPosition-attribute.
+ */
+ protected void skipBytes(InputStream input, int number) throws IOException {
+ int skipped = 0;
+ while (skipped < number) {
+ skipped += input.skip(number - skipped);
+ System.out.println("Skipped = " + skipped);
+ }
+
+ readerPosition += number;
+ }
+
+ private TagHeader createTagHeader(char[] source) throws ID3ReaderException {
+ boolean hasTag = (source[0] == 0x49) && (source[1] == 0x44)
+ && (source[2] == 0x33);
+ if (source.length != HEADER_LENGTH) {
+ throw new ID3ReaderException("Length of header must be "
+ + HEADER_LENGTH);
+ }
+ if (hasTag) {
+ String id = null;
+ id = new String(source, 0, ID3_LENGTH);
+ char version = (char) ((source[3] << 8) | source[4]);
+ byte flags = (byte) source[5];
+ int size = (source[6] << 24) | (source[7] << 16) | (source[8] << 8)
+ | source[9];
+ return new TagHeader(id, size, version, flags);
+ } else {
+ return null;
+ }
+ }
+
+ private FrameHeader createFrameHeader(char[] source)
+ throws ID3ReaderException {
+ if (source.length != HEADER_LENGTH) {
+ throw new ID3ReaderException("Length of header must be "
+ + HEADER_LENGTH);
+ }
+ String id = null;
+ id = new String(source, 0, FRAME_ID_LENGTH);
+ int size = (((int) source[4]) << 24) | (((int) source[5]) << 16)
+ | (((int) source[6]) << 8) | source[7];
+ char flags = (char) ((source[8] << 8) | source[9]);
+ return new FrameHeader(id, size, flags);
+ }
+
+ protected String readString(InputStream input, int max) throws IOException,
+ ID3ReaderException {
+ char[] bom = readBytes(input, 2);
+ if (bom == LITTLE_ENDIAN_BOM || bom == BIG_ENDIAN_BOM) {
+ return readUnicodeString(input, bom, max);
+ } else {
+ PushbackInputStream pi = new PushbackInputStream(input, 2);
+ pi.unread(bom[1]);
+ pi.unread(bom[0]);
+ return readISOString(pi, max);
+ }
+ }
+
+ private String readISOString(InputStream input, int max)
+ throws IOException, ID3ReaderException {
+ int bytesRead = 0;
+ StringBuilder builder = new StringBuilder();
+ char c;
+ while (++bytesRead <= max && (c = (char) input.read()) > 0) {
+ builder.append(c);
+ }
+ return builder.toString();
+ }
+
+ private String readUnicodeString(InputStream input, char[] bom, int max)
+ throws IOException, ID3ReaderException {
+ StringBuffer builder = new StringBuffer();
+ char c1 = (char) input.read();
+ char c2 = (char) input.read();
+ int bytesRead = 2;
+ while ((c1 > 0 && c2 > 0) && ++bytesRead <= max) {
+
+ builder.append(c1);
+ c1 = c2;
+ c2 = (char) input.read();
+ }
+ if (bom == LITTLE_ENDIAN_BOM) {
+ builder.reverse();
+ }
+ return builder.toString();
+ }
+
+ public int onStartTagHeader(TagHeader header) {
+ return ACTION_SKIP;
+ }
+
+ public int onStartFrameHeader(FrameHeader header, InputStream input)
+ throws IOException, ID3ReaderException {
+ return ACTION_SKIP;
+ }
+
+ public void onEndTag() {
+
+ }
+
+ public void onNoTagHeaderFound() {
+
+ }
+
+}
diff --git a/src/de/danoeh/antennapod/util/id3reader/ID3ReaderException.java b/src/de/danoeh/antennapod/util/id3reader/ID3ReaderException.java
new file mode 100644
index 000000000..c458540ee
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/id3reader/ID3ReaderException.java
@@ -0,0 +1,20 @@
+package de.danoeh.antennapod.util.id3reader;
+
+public class ID3ReaderException extends Exception {
+
+ public ID3ReaderException() {
+ }
+
+ public ID3ReaderException(String arg0) {
+ super(arg0);
+ }
+
+ public ID3ReaderException(Throwable arg0) {
+ super(arg0);
+ }
+
+ public ID3ReaderException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+}
diff --git a/src/de/danoeh/antennapod/util/id3reader/model/FrameHeader.java b/src/de/danoeh/antennapod/util/id3reader/model/FrameHeader.java
new file mode 100644
index 000000000..2c0d8e5ba
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/id3reader/model/FrameHeader.java
@@ -0,0 +1,18 @@
+package de.danoeh.antennapod.util.id3reader.model;
+
+public class FrameHeader extends Header {
+
+ protected char flags;
+
+ public FrameHeader(String id, int size, char flags) {
+ super(id, size);
+ this.flags = flags;
+ }
+
+ @Override
+ public String toString() {
+ return "FrameHeader [flags=" + Integer.toString(flags) + ", id=" + id + ", size=" + size
+ + "]";
+ }
+
+}
diff --git a/src/de/danoeh/antennapod/util/id3reader/model/Header.java b/src/de/danoeh/antennapod/util/id3reader/model/Header.java
new file mode 100644
index 000000000..22d5b6376
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/id3reader/model/Header.java
@@ -0,0 +1,29 @@
+package de.danoeh.antennapod.util.id3reader.model;
+
+public abstract class Header {
+
+ protected String id;
+ protected int size;
+
+ public Header(String id, int size) {
+ super();
+ this.id = id;
+ this.size = size;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ @Override
+ public String toString() {
+ return "Header [id=" + id + ", size=" + size + "]";
+ }
+
+
+
+}
diff --git a/src/de/danoeh/antennapod/util/id3reader/model/TagHeader.java b/src/de/danoeh/antennapod/util/id3reader/model/TagHeader.java
new file mode 100644
index 000000000..ec99ef14e
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/id3reader/model/TagHeader.java
@@ -0,0 +1,26 @@
+package de.danoeh.antennapod.util.id3reader.model;
+
+public class TagHeader extends Header {
+
+ protected char version;
+ protected byte flags;
+
+ public TagHeader(String id, int size, char version, byte flags) {
+ super(id, size);
+ this.version = version;
+ this.flags = flags;
+ }
+
+ @Override
+ public String toString() {
+ return "TagHeader [version=" + version + ", flags=" + flags + ", id="
+ + id + ", size=" + size + "]";
+ }
+
+ public char getVersion() {
+ return version;
+ }
+
+
+
+}