summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorByteHamster <info@bytehamster.com>2020-02-10 00:14:16 +0100
committerByteHamster <info@bytehamster.com>2020-02-12 17:12:21 +0100
commita980281d4794a867e9c972b53c87e6355182a916 (patch)
treeef502dcc8cc4ff4da956e0d96fe2b0959394427c /core
parent5caaaa9e5a3305f25338eea72af7f413b9d43969 (diff)
downloadAntennaPod-a980281d4794a867e9c972b53c87e6355182a916.zip
Added id3 chapter image reader
Diffstat (limited to 'core')
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java260
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java25
2 files changed, 176 insertions, 109 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java
index a3f747e09..f7c5bfec7 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java
@@ -1,11 +1,17 @@
package de.danoeh.antennapod.core.util.id3reader;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.Base64;
import android.util.Log;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.ID3Chapter;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.id3reader.model.FrameHeader;
import de.danoeh.antennapod.core.util.id3reader.model.TagHeader;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
@@ -15,110 +21,158 @@ import java.util.List;
public class ChapterReader extends ID3Reader {
private static final String TAG = "ID3ChapterReader";
- private static final String FRAME_ID_CHAPTER = "CHAP";
- private static final String FRAME_ID_TITLE = "TIT2";
+ private static final String FRAME_ID_CHAPTER = "CHAP";
+ private static final String FRAME_ID_TITLE = "TIT2";
private static final String FRAME_ID_LINK = "WXXX";
- private List<Chapter> chapters;
- private ID3Chapter currentChapter;
-
- @Override
- public int onStartTagHeader(TagHeader header) {
- chapters = new ArrayList<>();
- Log.d(TAG, "header: " + header);
- return ID3Reader.ACTION_DONT_SKIP;
- }
-
- @Override
- public int onStartFrameHeader(FrameHeader header, InputStream input)
- throws IOException, ID3ReaderException {
- Log.d(TAG, "header: " + header);
- switch (header.getId()) {
- case FRAME_ID_CHAPTER:
- if (currentChapter != null) {
- if (!hasId3Chapter(currentChapter)) {
- chapters.add(currentChapter);
- Log.d(TAG, "Found chapter: " + currentChapter);
- currentChapter = null;
- }
- }
- StringBuilder elementId = new StringBuilder();
- readISOString(elementId, 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.toString(), startTime);
- skipBytes(input, 12);
- return ID3Reader.ACTION_DONT_SKIP;
- case FRAME_ID_TITLE:
- if (currentChapter != null && currentChapter.getTitle() == null) {
- StringBuilder title = new StringBuilder();
- readString(title, input, header.getSize());
- currentChapter
- .setTitle(title.toString());
- Log.d(TAG, "Found title: " + currentChapter.getTitle());
-
- return ID3Reader.ACTION_DONT_SKIP;
- }
- break;
- case FRAME_ID_LINK:
- if (currentChapter != null) {
- // skip description
- int descriptionLength = readString(null, input, header.getSize());
- StringBuilder link = new StringBuilder();
- readISOString(link, input, header.getSize() - descriptionLength);
- try {
- String decodedLink = URLDecoder.decode(link.toString(), "UTF-8");
- currentChapter.setLink(decodedLink);
- Log.d(TAG, "Found link: " + currentChapter.getLink());
- } catch (IllegalArgumentException iae) {
- Log.w(TAG, "Bad URL found in ID3 data");
- }
-
- return ID3Reader.ACTION_DONT_SKIP;
- }
- break;
- case "APIC":
- Log.d(TAG, header.toString());
- break;
- }
-
- return super.onStartFrameHeader(header, input);
- }
-
- private boolean hasId3Chapter(ID3Chapter chapter) {
- for (Chapter c : chapters) {
- if (((ID3Chapter) c).getId3ID().equals(chapter.getId3ID())) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void onEndTag() {
- if (currentChapter != null) {
- if (!hasId3Chapter(currentChapter)) {
- chapters.add(currentChapter);
- }
- }
- Log.d(TAG, "Reached end of tag");
- if (chapters != null) {
- for (Chapter c : chapters) {
- Log.d(TAG, "chapter: " + c);
- }
- }
- }
-
- @Override
- public void onNoTagHeaderFound() {
- Log.d(TAG, "No tag header found");
- super.onNoTagHeaderFound();
- }
-
- public List<Chapter> getChapters() {
- return chapters;
- }
+ private List<Chapter> chapters;
+ private ID3Chapter currentChapter;
+
+ @Override
+ public int onStartTagHeader(TagHeader header) {
+ chapters = new ArrayList<>();
+ Log.d(TAG, "header: " + header);
+ return ID3Reader.ACTION_DONT_SKIP;
+ }
+
+ @Override
+ public int onStartFrameHeader(FrameHeader header, InputStream input)
+ throws IOException, ID3ReaderException {
+ Log.d(TAG, "header: " + header);
+ switch (header.getId()) {
+ case FRAME_ID_CHAPTER:
+ if (currentChapter != null) {
+ if (!hasId3Chapter(currentChapter)) {
+ chapters.add(currentChapter);
+ Log.d(TAG, "Found chapter: " + currentChapter);
+ currentChapter = null;
+ }
+ }
+ StringBuilder elementId = new StringBuilder();
+ readISOString(elementId, input, Integer.MAX_VALUE);
+ char[] startTimeSource = readChars(input, 4);
+ long startTime = ((int) startTimeSource[0] << 24)
+ | ((int) startTimeSource[1] << 16)
+ | ((int) startTimeSource[2] << 8) | startTimeSource[3];
+ currentChapter = new ID3Chapter(elementId.toString(), startTime);
+ skipBytes(input, 12);
+ return ID3Reader.ACTION_DONT_SKIP;
+ case FRAME_ID_TITLE:
+ if (currentChapter != null && currentChapter.getTitle() == null) {
+ StringBuilder title = new StringBuilder();
+ readString(title, input, header.getSize());
+ currentChapter
+ .setTitle(title.toString());
+ Log.d(TAG, "Found title: " + currentChapter.getTitle());
+
+ return ID3Reader.ACTION_DONT_SKIP;
+ }
+ break;
+ case FRAME_ID_LINK:
+ if (currentChapter != null) {
+ // skip description
+ int descriptionLength = readString(null, input, header.getSize());
+ StringBuilder link = new StringBuilder();
+ readISOString(link, input, header.getSize() - descriptionLength);
+ try {
+ String decodedLink = URLDecoder.decode(link.toString(), "UTF-8");
+ currentChapter.setLink(decodedLink);
+ Log.d(TAG, "Found link: " + currentChapter.getLink());
+ } catch (IllegalArgumentException iae) {
+ Log.w(TAG, "Bad URL found in ID3 data");
+ }
+
+ return ID3Reader.ACTION_DONT_SKIP;
+ }
+ break;
+ case "APIC":
+ Log.d(TAG, header.toString());
+ StringBuilder mime = new StringBuilder();
+ int read = readString(mime, input, header.getSize());
+ byte type = (byte) input.read();
+ // $00 Other
+ // $01 32x32 pixels 'file icon' (PNG only)
+ // $02 Other file icon
+ // $03 Cover (front)
+ // $04 Cover (back)
+ // $05 Leaflet page
+ // $06 Media (e.g. label side of CD)
+ // $07 Lead artist/lead performer/soloist
+ // $08 Artist/performer
+ // $09 Conductor
+ // $0A Band/Orchestra
+ // $0B Composer
+ // $0C Lyricist/text writer
+ // $0D Recording Location
+ // $0E During recording
+ // $0F During performance
+ // $10 Movie/video screen capture
+ // $11 A bright coloured fish
+ // $12 Illustration
+ // $13 Band/artist logotype
+ // $14 Publisher/Studio logotype
+ read++;
+ StringBuilder description = new StringBuilder();
+ read += readISOString(description, input, header.getSize()); // Should use encoding from first string
+
+
+ Log.d(TAG, "Found apic: " + mime + "," + description);
+ if (mime.toString().equals("-->")) {
+ // Data contains a link to a picture
+ StringBuilder link = new StringBuilder();
+ readISOString(link, input, header.getSize());
+ Log.d(TAG, "link: " + link);
+ } else {
+ // Data contains the picture
+ byte[] imageData = readBytes(input, header.getSize() - read);
+
+ Bitmap bmp = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
+ try (FileOutputStream out = new FileOutputStream(new File(UserPreferences.getDataFolder(null),
+ "chapter" + chapters.size() + ".jpg"))) {
+ bmp.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
+ // PNG is a lossless format, the compression factor (100) is ignored
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return ID3Reader.ACTION_DONT_SKIP;
+ }
+
+ return super.onStartFrameHeader(header, input);
+ }
+
+ private boolean hasId3Chapter(ID3Chapter chapter) {
+ for (Chapter c : chapters) {
+ if (((ID3Chapter) c).getId3ID().equals(chapter.getId3ID())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onEndTag() {
+ if (currentChapter != null) {
+ if (!hasId3Chapter(currentChapter)) {
+ chapters.add(currentChapter);
+ }
+ }
+ Log.d(TAG, "Reached end of tag");
+ if (chapters != null) {
+ for (Chapter c : chapters) {
+ Log.d(TAG, "chapter: " + c);
+ }
+ }
+ }
+
+ @Override
+ public void onNoTagHeaderFound() {
+ Log.d(TAG, "No tag header found");
+ super.onNoTagHeaderFound();
+ }
+
+ public List<Chapter> getChapters() {
+ return chapters;
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java
index 3f5993700..85538d94c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java
@@ -37,7 +37,7 @@ public class ID3Reader {
ID3ReaderException {
int rc;
readerPosition = 0;
- char[] tagHeaderSource = readBytes(input, HEADER_LENGTH);
+ char[] tagHeaderSource = readChars(input, HEADER_LENGTH);
tagHeader = createTagHeader(tagHeaderSource);
if (tagHeader == null) {
onNoTagHeaderFound();
@@ -47,7 +47,7 @@ public class ID3Reader {
onEndTag();
} else {
while (readerPosition < tagHeader.getSize()) {
- FrameHeader frameHeader = createFrameHeader(readBytes(input, HEADER_LENGTH));
+ FrameHeader frameHeader = createFrameHeader(readChars(input, HEADER_LENGTH));
if (checkForNullString(frameHeader.getId())) {
break;
}
@@ -84,11 +84,10 @@ public class ID3Reader {
}
/**
- * Read a certain number of bytes from the given input stream. This method
+ * Read a certain number of chars from the given input stream. This method
* changes the readerPosition-attribute.
*/
- char[] readBytes(InputStream input, int number)
- throws IOException, ID3ReaderException {
+ char[] readChars(InputStream input, int number) throws IOException, ID3ReaderException {
char[] header = new char[number];
for (int i = 0; i < number; i++) {
int b = input.read();
@@ -102,6 +101,20 @@ public class ID3Reader {
return header;
}
+ byte[] readBytes(InputStream input, int number) throws IOException, ID3ReaderException {
+ byte[] header = new byte[number];
+ for (int i = 0; i < number; i++) {
+ int b = input.read();
+ readerPosition++;
+ if (b != -1) {
+ header[i] = (byte) 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.
@@ -168,7 +181,7 @@ public class ID3Reader {
protected int readString(StringBuilder buffer, InputStream input, int max) throws IOException,
ID3ReaderException {
if (max > 0) {
- char[] encoding = readBytes(input, 1);
+ char[] encoding = readChars(input, 1);
max--;
if (encoding[0] == ENCODING_UTF16_WITH_BOM || encoding[0] == ENCODING_UTF16_WITHOUT_BOM) {