diff options
Diffstat (limited to 'core/src/main/java/de/danoeh')
18 files changed, 8 insertions, 1016 deletions
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 deleted file mode 100644 index 56d63c32e..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java +++ /dev/null @@ -1,38 +0,0 @@ -package de.danoeh.antennapod.core.feed; - -import de.danoeh.antennapod.model.feed.Chapter; - -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, String link, String imageUrl) { - super(start, title, link, imageUrl); - } - - @Override - public String toString() { - return "ID3Chapter [id3ID=" + id3ID + ", title=" + getTitle() + ", start=" - + getStart() + ", url=" + getLink() + "]"; - } - - @Override - public int getChapterType() { - return CHAPTERTYPE_ID3CHAPTER; - } - - public String getId3ID() { - return id3ID; - } - -} 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 deleted file mode 100644 index 6e0b6859d..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java +++ /dev/null @@ -1,89 +0,0 @@ -package de.danoeh.antennapod.core.feed; - -import java.util.concurrent.TimeUnit; - -import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentReaderException; -import de.danoeh.antennapod.model.feed.Chapter; - -public class VorbisCommentChapter extends Chapter { - public static final int CHAPTERTYPE_VORBISCOMMENT_CHAPTER = 3; - - private static final int CHAPTERXXX_LENGTH = "chapterxxx".length(); - - private int vorbisCommentId; - - public VorbisCommentChapter(int vorbisCommentId) { - this.vorbisCommentId = vorbisCommentId; - } - - public VorbisCommentChapter(long start, String title, String link, String imageUrl) { - super(start, title, link, imageUrl); - } - - @Override - public String toString() { - return "VorbisCommentChapter [id=" + getId() + ", title=" + getTitle() - + ", link=" + getLink() + ", start=" + getStart() + "]"; - } - - 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 + ")"); - } - - /** - * 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 int getVorbisCommentId() { - return vorbisCommentId; - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java index 8ad04cb47..defe6c9f8 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java +++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java @@ -14,7 +14,7 @@ import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory; import com.bumptech.glide.load.model.StringLoader; import com.bumptech.glide.module.AppGlideModule; -import de.danoeh.antennapod.core.util.EmbeddedChapterImage; +import de.danoeh.antennapod.model.feed.EmbeddedChapterImage; import java.io.InputStream; import com.bumptech.glide.request.RequestOptions; diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java index d6d63fed0..63126405d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java @@ -10,7 +10,7 @@ import com.bumptech.glide.load.model.ModelLoaderFactory; import com.bumptech.glide.load.model.MultiModelLoaderFactory; import com.bumptech.glide.signature.ObjectKey; import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; -import de.danoeh.antennapod.core.util.EmbeddedChapterImage; +import de.danoeh.antennapod.model.feed.EmbeddedChapterImage; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/ChapterCursorMapper.java b/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/ChapterCursorMapper.java index 61613a25a..5fa376129 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/ChapterCursorMapper.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/ChapterCursorMapper.java @@ -3,10 +3,10 @@ package de.danoeh.antennapod.core.storage.mapper; import android.database.Cursor; import androidx.annotation.NonNull; import de.danoeh.antennapod.model.feed.Chapter; -import de.danoeh.antennapod.core.feed.ID3Chapter; import de.danoeh.antennapod.parser.feed.element.SimpleChapter; -import de.danoeh.antennapod.core.feed.VorbisCommentChapter; import de.danoeh.antennapod.core.storage.PodDBAdapter; +import de.danoeh.antennapod.parser.media.id3.ID3Chapter; +import de.danoeh.antennapod.parser.media.vorbis.VorbisCommentChapter; /** * Converts a {@link Cursor} to a {@link Chapter} object. diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java index 1bc2c13ee..4092087f4 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java @@ -11,11 +11,11 @@ import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.util.comparator.ChapterStartTimeComparator; -import de.danoeh.antennapod.core.util.id3reader.ChapterReader; -import de.danoeh.antennapod.core.util.id3reader.ID3ReaderException; +import de.danoeh.antennapod.parser.media.id3.ChapterReader; +import de.danoeh.antennapod.parser.media.id3.ID3ReaderException; import de.danoeh.antennapod.model.playback.Playable; -import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentChapterReader; -import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentReaderException; +import de.danoeh.antennapod.parser.media.vorbis.VorbisCommentChapterReader; +import de.danoeh.antennapod.parser.media.vorbis.VorbisCommentReaderException; import okhttp3.Request; import okhttp3.Response; import org.apache.commons.io.input.CountingInputStream; diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/EmbeddedChapterImage.java b/core/src/main/java/de/danoeh/antennapod/core/util/EmbeddedChapterImage.java deleted file mode 100644 index a3966a24c..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/EmbeddedChapterImage.java +++ /dev/null @@ -1,73 +0,0 @@ -package de.danoeh.antennapod.core.util; - -import android.text.TextUtils; -import de.danoeh.antennapod.model.playback.Playable; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class EmbeddedChapterImage { - private static final Pattern EMBEDDED_IMAGE_MATCHER = Pattern.compile("embedded-image://(\\d+)/(\\d+)"); - - private final int position; - private final int length; - private final String imageUrl; - private final Playable media; - - public EmbeddedChapterImage(Playable media, String imageUrl) { - this.media = media; - this.imageUrl = imageUrl; - Matcher m = EMBEDDED_IMAGE_MATCHER.matcher(imageUrl); - if (m.find()) { - this.position = Integer.parseInt(m.group(1)); - this.length = Integer.parseInt(m.group(2)); - } else { - throw new IllegalArgumentException("Not an embedded chapter"); - } - } - - public static String makeUrl(int position, int length) { - return "embedded-image://" + position + "/" + length; - } - - public int getPosition() { - return position; - } - - public int getLength() { - return length; - } - - public Playable getMedia() { - return media; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - EmbeddedChapterImage that = (EmbeddedChapterImage) o; - return TextUtils.equals(imageUrl, that.imageUrl); - } - - @Override - public int hashCode() { - return imageUrl.hashCode(); - } - - private static boolean isEmbeddedChapterImage(String imageUrl) { - return EMBEDDED_IMAGE_MATCHER.matcher(imageUrl).matches(); - } - - public static Object getModelFor(Playable media, int chapter) { - String imageUrl = media.getChapters().get(chapter).getImageUrl(); - if (isEmbeddedChapterImage(imageUrl)) { - return new EmbeddedChapterImage(media, imageUrl); - } else { - return imageUrl; - } - } -} 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 deleted file mode 100644 index adc38b0d2..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java +++ /dev/null @@ -1,119 +0,0 @@ -package de.danoeh.antennapod.core.util.id3reader; - -import android.text.TextUtils; -import android.util.Log; -import androidx.annotation.NonNull; -import de.danoeh.antennapod.model.feed.Chapter; -import de.danoeh.antennapod.core.feed.ID3Chapter; -import de.danoeh.antennapod.core.util.EmbeddedChapterImage; -import de.danoeh.antennapod.core.util.id3reader.model.FrameHeader; -import org.apache.commons.io.input.CountingInputStream; - -import java.io.IOException; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.List; - -/** - * Reads ID3 chapters. - * See https://id3.org/id3v2-chapters-1.0 - */ -public class ChapterReader extends ID3Reader { - private static final String TAG = "ID3ChapterReader"; - - public static final String FRAME_ID_CHAPTER = "CHAP"; - public static final String FRAME_ID_TITLE = "TIT2"; - public static final String FRAME_ID_LINK = "WXXX"; - public static final String FRAME_ID_PICTURE = "APIC"; - public static final String MIME_IMAGE_URL = "-->"; - public static final int IMAGE_TYPE_COVER = 3; - - private final List<Chapter> chapters = new ArrayList<>(); - - public ChapterReader(CountingInputStream input) { - super(input); - } - - @Override - protected void readFrame(@NonNull FrameHeader frameHeader) throws IOException, ID3ReaderException { - if (FRAME_ID_CHAPTER.equals(frameHeader.getId())) { - Log.d(TAG, "Handling frame: " + frameHeader.toString()); - Chapter chapter = readChapter(frameHeader); - Log.d(TAG, "Chapter done: " + chapter); - chapters.add(chapter); - } else { - super.readFrame(frameHeader); - } - } - - public Chapter readChapter(@NonNull FrameHeader frameHeader) throws IOException, ID3ReaderException { - int chapterStartedPosition = getPosition(); - String elementId = readIsoStringNullTerminated(100); - long startTime = readInt(); - skipBytes(12); // Ignore end time, start offset, end offset - ID3Chapter chapter = new ID3Chapter(elementId, startTime); - - // Read sub-frames - while (getPosition() < chapterStartedPosition + frameHeader.getSize()) { - FrameHeader subFrameHeader = readFrameHeader(); - readChapterSubFrame(subFrameHeader, chapter); - } - return chapter; - } - - public void readChapterSubFrame(@NonNull FrameHeader frameHeader, @NonNull Chapter chapter) - throws IOException, ID3ReaderException { - Log.d(TAG, "Handling subframe: " + frameHeader.toString()); - int frameStartPosition = getPosition(); - switch (frameHeader.getId()) { - case FRAME_ID_TITLE: - chapter.setTitle(readEncodingAndString(frameHeader.getSize())); - Log.d(TAG, "Found title: " + chapter.getTitle()); - break; - case FRAME_ID_LINK: - readEncodingAndString(frameHeader.getSize()); // skip description - String url = readIsoStringNullTerminated(frameStartPosition + frameHeader.getSize() - getPosition()); - try { - String decodedLink = URLDecoder.decode(url, "ISO-8859-1"); - chapter.setLink(decodedLink); - Log.d(TAG, "Found link: " + chapter.getLink()); - } catch (IllegalArgumentException iae) { - Log.w(TAG, "Bad URL found in ID3 data"); - } - break; - case FRAME_ID_PICTURE: - byte encoding = readByte(); - String mime = readEncodedString(encoding, frameHeader.getSize()); - byte type = readByte(); - String description = readEncodedString(encoding, frameHeader.getSize()); - Log.d(TAG, "Found apic: " + mime + "," + description); - if (MIME_IMAGE_URL.equals(mime)) { - String link = readIsoStringNullTerminated(frameHeader.getSize()); - Log.d(TAG, "Link: " + link); - if (TextUtils.isEmpty(chapter.getImageUrl()) || type == IMAGE_TYPE_COVER) { - chapter.setImageUrl(link); - } - } else { - int alreadyConsumed = getPosition() - frameStartPosition; - int rawImageDataLength = frameHeader.getSize() - alreadyConsumed; - if (TextUtils.isEmpty(chapter.getImageUrl()) || type == IMAGE_TYPE_COVER) { - chapter.setImageUrl(EmbeddedChapterImage.makeUrl(getPosition(), rawImageDataLength)); - } - } - break; - default: - Log.d(TAG, "Unknown chapter sub-frame."); - break; - } - - // Skip garbage to fill frame completely - // This also asserts that we are not reading too many bytes from this frame. - int alreadyConsumed = getPosition() - frameStartPosition; - skipBytes(frameHeader.getSize() - alreadyConsumed); - } - - 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 deleted file mode 100644 index b7baaa8aa..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java +++ /dev/null @@ -1,213 +0,0 @@ -package de.danoeh.antennapod.core.util.id3reader; - -import android.util.Log; -import androidx.annotation.NonNull; -import de.danoeh.antennapod.core.util.id3reader.model.FrameHeader; -import de.danoeh.antennapod.core.util.id3reader.model.TagHeader; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.input.CountingInputStream; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.MalformedInputException; - -/** - * Reads the ID3 Tag of a given file. - * See https://id3.org/id3v2.3.0 - */ -public class ID3Reader { - private static final String TAG = "ID3Reader"; - private static final int FRAME_ID_LENGTH = 4; - public static final byte ENCODING_ISO = 0; - public static final byte ENCODING_UTF16_WITH_BOM = 1; - public static final byte ENCODING_UTF16_WITHOUT_BOM = 2; - public static final byte ENCODING_UTF8 = 3; - - private TagHeader tagHeader; - private final CountingInputStream inputStream; - - public ID3Reader(CountingInputStream input) { - inputStream = input; - } - - public void readInputStream() throws IOException, ID3ReaderException { - tagHeader = readTagHeader(); - int tagContentStartPosition = getPosition(); - while (getPosition() < tagContentStartPosition + tagHeader.getSize()) { - FrameHeader frameHeader = readFrameHeader(); - if (frameHeader.getId().charAt(0) < '0' || frameHeader.getId().charAt(0) > 'z') { - Log.d(TAG, "Stopping because of invalid frame: " + frameHeader.toString()); - return; - } - readFrame(frameHeader); - } - } - - protected void readFrame(@NonNull FrameHeader frameHeader) throws IOException, ID3ReaderException { - Log.d(TAG, "Skipping frame: " + frameHeader.toString()); - skipBytes(frameHeader.getSize()); - } - - int getPosition() { - return inputStream.getCount(); - } - - /** - * Skip a certain number of bytes on the given input stream. - */ - void skipBytes(int number) throws IOException, ID3ReaderException { - if (number < 0) { - throw new ID3ReaderException("Trying to read a negative number of bytes"); - } - IOUtils.skipFully(inputStream, number); - } - - byte readByte() throws IOException { - return (byte) inputStream.read(); - } - - short readShort() throws IOException { - char firstByte = (char) inputStream.read(); - char secondByte = (char) inputStream.read(); - return (short) ((firstByte << 8) | secondByte); - } - - int readInt() throws IOException { - char firstByte = (char) inputStream.read(); - char secondByte = (char) inputStream.read(); - char thirdByte = (char) inputStream.read(); - char fourthByte = (char) inputStream.read(); - return (firstByte << 24) | (secondByte << 16) | (thirdByte << 8) | fourthByte; - } - - void expectChar(char expected) throws ID3ReaderException, IOException { - char read = (char) inputStream.read(); - if (read != expected) { - throw new ID3ReaderException("Expected " + expected + " and got " + read); - } - } - - @NonNull - TagHeader readTagHeader() throws ID3ReaderException, IOException { - expectChar('I'); - expectChar('D'); - expectChar('3'); - short version = readShort(); - byte flags = readByte(); - int size = unsynchsafe(readInt()); - if ((flags & 0b01000000) != 0) { - int extendedHeaderSize = readInt(); - skipBytes(extendedHeaderSize - 4); - } - return new TagHeader("ID3", size, version, flags); - } - - @NonNull - FrameHeader readFrameHeader() throws IOException { - String id = readIsoStringFixed(FRAME_ID_LENGTH); - int size = readInt(); - if (tagHeader != null && tagHeader.getVersion() >= 0x0400) { - size = unsynchsafe(size); - } - short flags = readShort(); - return new FrameHeader(id, size, flags); - } - - private int unsynchsafe(int in) { - int out = 0; - int mask = 0x7F000000; - - while (mask != 0) { - out >>= 1; - out |= in & mask; - mask >>= 8; - } - - return out; - } - - /** - * Reads a null-terminated string with encoding. - */ - protected String readEncodingAndString(int max) throws IOException { - byte encoding = readByte(); - return readEncodedString(encoding, max - 1); - } - - @SuppressWarnings("CharsetObjectCanBeUsed") - protected String readIsoStringFixed(int length) throws IOException { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - int bytesRead = 0; - while (bytesRead < length) { - bytes.write(readByte()); - bytesRead++; - } - return Charset.forName("ISO-8859-1").newDecoder().decode(ByteBuffer.wrap(bytes.toByteArray())).toString(); - } - - protected String readIsoStringNullTerminated(int max) throws IOException { - return readEncodedString(ENCODING_ISO, max); - } - - @SuppressWarnings("CharsetObjectCanBeUsed") - String readEncodedString(int encoding, int max) throws IOException { - if (encoding == ENCODING_UTF16_WITH_BOM || encoding == ENCODING_UTF16_WITHOUT_BOM) { - return readEncodedString2(Charset.forName("UTF-16"), max); - } else if (encoding == ENCODING_UTF8) { - return readEncodedString2(Charset.forName("UTF-8"), max); - } else { - return readEncodedString1(Charset.forName("ISO-8859-1"), max); - } - } - - /** - * Reads chars where the encoding uses 1 char per symbol. - */ - private String readEncodedString1(Charset charset, int max) throws IOException { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - int bytesRead = 0; - while (bytesRead < max) { - byte c = readByte(); - bytesRead++; - if (c == 0) { - break; - } - bytes.write(c); - } - return charset.newDecoder().decode(ByteBuffer.wrap(bytes.toByteArray())).toString(); - } - - /** - * Reads chars where the encoding uses 2 chars per symbol. - */ - private String readEncodedString2(Charset charset, int max) throws IOException { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - int bytesRead = 0; - boolean foundEnd = false; - while (bytesRead + 1 < max) { - byte c1 = readByte(); - byte c2 = readByte(); - if (c1 == 0 && c2 == 0) { - foundEnd = true; - break; - } - bytesRead += 2; - bytes.write(c1); - bytes.write(c2); - } - if (!foundEnd && bytesRead < max) { - // Last character - byte c = readByte(); - if (c != 0) { - bytes.write(c); - } - } - try { - return charset.newDecoder().decode(ByteBuffer.wrap(bytes.toByteArray())).toString(); - } catch (MalformedInputException e) { - return ""; - } - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3ReaderException.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3ReaderException.java deleted file mode 100644 index 7a68bb5ce..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3ReaderException.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.danoeh.antennapod.core.util.id3reader; - -public class ID3ReaderException extends Exception { - private static final long serialVersionUID = 1L; - - public ID3ReaderException(String message) { - super(message); - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/FrameHeader.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/FrameHeader.java deleted file mode 100644 index e4af89a86..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/FrameHeader.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.danoeh.antennapod.core.util.id3reader.model; - -import androidx.annotation.NonNull; - -public class FrameHeader extends Header { - private final short flags; - - public FrameHeader(String id, int size, short flags) { - super(id, size); - this.flags = flags; - } - - @Override - @NonNull - public String toString() { - return String.format("FrameHeader [flags=%s, id=%s, size=%s]", Integer.toBinaryString(flags), id, size); - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/Header.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/Header.java deleted file mode 100644 index 29185748f..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/Header.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.danoeh.antennapod.core.util.id3reader.model; - -public abstract class Header { - - final String id; - final int size; - - 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/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/TagHeader.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/TagHeader.java deleted file mode 100644 index 2590db029..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/model/TagHeader.java +++ /dev/null @@ -1,25 +0,0 @@ -package de.danoeh.antennapod.core.util.id3reader.model; - -import androidx.annotation.NonNull; - -public class TagHeader extends Header { - private final short version; - private final byte flags; - - public TagHeader(String id, int size, short version, byte flags) { - super(id, size); - this.version = version; - this.flags = flags; - } - - @Override - @NonNull - public String toString() { - return "TagHeader [version=" + version + ", flags=" + flags + ", id=" - + id + ", size=" + size + "]"; - } - - public short getVersion() { - return version; - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java deleted file mode 100644 index 9277af6e6..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java +++ /dev/null @@ -1,81 +0,0 @@ -package de.danoeh.antennapod.core.util.vorbiscommentreader; - -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; - -class OggInputStream extends InputStream { - private final InputStream input; - - /** True if OggInputStream is currently inside an Ogg page. */ - private boolean isInPage; - private long bytesLeft; - - public OggInputStream(InputStream input) { - super(); - isInPage = false; - this.input = input; - } - - @Override - public int read() throws IOException { - if (!isInPage) { - readOggPage(); - } - - if (isInPage && bytesLeft > 0) { - int result = input.read(); - bytesLeft -= 1; - if (bytesLeft == 0) { - isInPage = false; - } - return result; - } - return -1; - } - - private void readOggPage() throws IOException { - // find OggS - int[] buffer = new int[4]; - int c; - boolean isInOggS = false; - while ((c = input.read()) != -1) { - switch (c) { - case 'O': - isInOggS = true; - buffer[0] = c; - break; - case 'g': - if (buffer[1] != c) { - buffer[1] = c; - } else { - buffer[2] = c; - } - break; - case 'S': - buffer[3] = c; - break; - default: - if (isInOggS) { - Arrays.fill(buffer, 0); - isInOggS = false; - } - } - if (buffer[0] == 'O' && buffer[1] == 'g' && buffer[2] == 'g' - && buffer[3] == 'S') { - break; - } - } - // read segments - IOUtils.skipFully(input, 22); - bytesLeft = 0; - int numSegments = input.read(); - for (int i = 0; i < numSegments; i++) { - bytesLeft += input.read(); - } - isInPage = true; - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java deleted file mode 100644 index 26955effc..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java +++ /dev/null @@ -1,100 +0,0 @@ -package de.danoeh.antennapod.core.util.vorbiscommentreader; - -import android.util.Log; - -import java.util.ArrayList; -import java.util.List; - -import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.model.feed.Chapter; -import de.danoeh.antennapod.core.feed.VorbisCommentChapter; - -public class VorbisCommentChapterReader extends VorbisCommentReader { - private static final String TAG = "VorbisCommentChptrReadr"; - - private static final String CHAPTER_KEY = "chapter\\d\\d\\d.*"; - private static final String CHAPTER_ATTRIBUTE_TITLE = "name"; - private static final String CHAPTER_ATTRIBUTE_LINK = "url"; - - private List<Chapter> chapters; - - public VorbisCommentChapterReader() { - } - - @Override - public void onVorbisCommentFound() { - System.out.println("Vorbis comment found"); - } - - @Override - public void onVorbisCommentHeaderFound(VorbisCommentHeader header) { - chapters = new ArrayList<>(); - System.out.println(header.toString()); - } - - @Override - public boolean onContentVectorKey(String content) { - return content.matches(CHAPTER_KEY); - } - - @Override - public void onContentVectorValue(String key, String value) throws VorbisCommentReaderException { - if (BuildConfig.DEBUG) { - Log.d(TAG, "Key: " + key + ", value: " + value); - } - String attribute = VorbisCommentChapter.getAttributeTypeFromKey(key); - int id = VorbisCommentChapter.getIDFromKey(key); - Chapter chapter = getChapterById(id); - if (attribute == null) { - if (getChapterById(id) == null) { - // new chapter - long start = VorbisCommentChapter.getStartTimeFromValue(value); - chapter = new VorbisCommentChapter(id); - chapter.setStart(start); - chapters.add(chapter); - } else { - throw new VorbisCommentReaderException("Found chapter with duplicate ID (" + key + ", " + value + ")"); - } - } else if (attribute.equals(CHAPTER_ATTRIBUTE_TITLE)) { - if (chapter != null) { - chapter.setTitle(value); - } - } else if (attribute.equals(CHAPTER_ATTRIBUTE_LINK)) { - if (chapter != null) { - chapter.setLink(value); - } - } - } - - @Override - public void onNoVorbisCommentFound() { - System.out.println("No vorbis comment found"); - } - - @Override - public void onEndOfComment() { - System.out.println("End of comment"); - for (Chapter c : chapters) { - System.out.println(c.toString()); - } - } - - @Override - public void onError(VorbisCommentReaderException exception) { - exception.printStackTrace(); - } - - private Chapter getChapterById(long id) { - for (Chapter c : chapters) { - if (((VorbisCommentChapter) c).getVorbisCommentId() == id) { - return c; - } - } - return null; - } - - public List<Chapter> getChapters() { - return chapters; - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentHeader.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentHeader.java deleted file mode 100644 index ff7508390..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentHeader.java +++ /dev/null @@ -1,26 +0,0 @@ -package de.danoeh.antennapod.core.util.vorbiscommentreader; -class VorbisCommentHeader { - private final String vendorString; - private final long userCommentLength; - - public VorbisCommentHeader(String vendorString, long userCommentLength) { - super(); - this.vendorString = vendorString; - this.userCommentLength = userCommentLength; - } - - @Override - public String toString() { - return "VorbisCommentHeader [vendorString=" + vendorString - + ", userCommentLength=" + userCommentLength + "]"; - } - - public String getVendorString() { - return vendorString; - } - - public long getUserCommentLength() { - return userCommentLength; - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java deleted file mode 100644 index e910e2be4..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java +++ /dev/null @@ -1,166 +0,0 @@ -package de.danoeh.antennapod.core.util.vorbiscommentreader; - -import androidx.annotation.NonNull; -import org.apache.commons.io.EndianUtils; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; - -public abstract class VorbisCommentReader { - /** Length of first page in an ogg file in bytes. */ - private static final int FIRST_OGG_PAGE_LENGTH = 58; - private static final int FIRST_OPUS_PAGE_LENGTH = 47; - private static final int SECOND_PAGE_MAX_LENGTH = 64 * 1024 * 1024; - private static final int PACKET_TYPE_IDENTIFICATION = 1; - private static final int PACKET_TYPE_COMMENT = 3; - - /** Called when Reader finds identification header. */ - protected abstract void onVorbisCommentFound(); - - protected abstract void onVorbisCommentHeaderFound(VorbisCommentHeader header); - - /** - * Is called every time the Reader finds a content vector. The handler - * should return true if it wants to handle the content vector. - */ - protected abstract boolean onContentVectorKey(String content); - - /** - * Is called if onContentVectorKey returned true for the key. - */ - protected abstract void onContentVectorValue(String key, String value) throws VorbisCommentReaderException; - - protected abstract void onNoVorbisCommentFound(); - - protected abstract void onEndOfComment(); - - protected abstract void onError(VorbisCommentReaderException exception); - - public void readInputStream(InputStream input) throws VorbisCommentReaderException { - try { - // look for identification header - if (findIdentificationHeader(input)) { - onVorbisCommentFound(); - input = new OggInputStream(input); - if (findCommentHeader(input)) { - VorbisCommentHeader commentHeader = readCommentHeader(input); - onVorbisCommentHeaderFound(commentHeader); - for (int i = 0; i < commentHeader.getUserCommentLength(); i++) { - readUserComment(input); - } - onEndOfComment(); - } else { - onError(new VorbisCommentReaderException("No comment header found")); - } - } else { - onNoVorbisCommentFound(); - } - } catch (IOException e) { - onError(new VorbisCommentReaderException(e)); - } - } - - private void readUserComment(InputStream input) throws VorbisCommentReaderException { - try { - long vectorLength = EndianUtils.readSwappedUnsignedInteger(input); - String key = readContentVectorKey(input, vectorLength).toLowerCase(); - boolean readValue = onContentVectorKey(key); - if (readValue) { - String value = readUtf8String(input, (int) (vectorLength - key.length() - 1)); - onContentVectorValue(key, value); - } else { - IOUtils.skipFully(input, vectorLength - key.length() - 1); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - private String readUtf8String(InputStream input, long length) throws IOException { - byte[] buffer = new byte[(int) length]; - IOUtils.readFully(input, buffer); - Charset charset = Charset.forName("UTF-8"); - return charset.newDecoder().decode(ByteBuffer.wrap(buffer)).toString(); - } - - /** - * Looks for an identification header in the first page of the file. If an - * identification header is found, it will be skipped completely and the - * method will return true, otherwise false. - */ - private boolean findIdentificationHeader(InputStream input) throws IOException { - byte[] buffer = new byte[FIRST_OPUS_PAGE_LENGTH]; - IOUtils.readFully(input, buffer); - final byte[] oggIdentificationHeader = new byte[]{ PACKET_TYPE_IDENTIFICATION, 'v', 'o', 'r', 'b', 'i', 's' }; - for (int i = 6; i < buffer.length; i++) { - if (bufferMatches(buffer, oggIdentificationHeader, i)) { - IOUtils.skip(input, FIRST_OGG_PAGE_LENGTH - FIRST_OPUS_PAGE_LENGTH); - return true; - } else if (bufferMatches(buffer, "OpusHead".getBytes(), i)) { - return true; - } - } - return false; - } - - private boolean findCommentHeader(InputStream input) throws IOException { - byte[] buffer = new byte[64]; // Enough space for some bytes. Used circularly. - final byte[] oggCommentHeader = new byte[]{ PACKET_TYPE_COMMENT, 'v', 'o', 'r', 'b', 'i', 's' }; - for (int bytesRead = 0; bytesRead < SECOND_PAGE_MAX_LENGTH; bytesRead++) { - buffer[bytesRead % buffer.length] = (byte) input.read(); - if (bufferMatches(buffer, oggCommentHeader, bytesRead)) { - return true; - } else if (bufferMatches(buffer, "OpusTags".getBytes(), bytesRead)) { - return true; - } - } - return false; - } - - /** - * Reads backwards in haystack, starting at position. Checks if the bytes match needle. - * Uses haystack circularly, so when reading at (-1), it reads at (length - 1). - */ - boolean bufferMatches(byte[] haystack, byte[] needle, int position) { - for (int i = 0; i < needle.length; i++) { - int posInHaystack = position - i; - while (posInHaystack < 0) { - posInHaystack += haystack.length; - } - posInHaystack = posInHaystack % haystack.length; - if (haystack[posInHaystack] != needle[needle.length - 1 - i]) { - return false; - } - } - return true; - } - - @NonNull - private VorbisCommentHeader readCommentHeader(InputStream input) throws IOException, VorbisCommentReaderException { - try { - long vendorLength = EndianUtils.readSwappedUnsignedInteger(input); - String vendorName = readUtf8String(input, vendorLength); - long userCommentLength = EndianUtils.readSwappedUnsignedInteger(input); - return new VorbisCommentHeader(vendorName, userCommentLength); - } catch (UnsupportedEncodingException e) { - throw new VorbisCommentReaderException(e); - } - } - - private String readContentVectorKey(InputStream input, long vectorLength) throws IOException { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < vectorLength; i++) { - char c = (char) input.read(); - if (c == '=') { - return builder.toString(); - } else { - builder.append(c); - } - } - return null; // no key found - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReaderException.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReaderException.java deleted file mode 100644 index 8b0f3052b..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReaderException.java +++ /dev/null @@ -1,21 +0,0 @@ -package de.danoeh.antennapod.core.util.vorbiscommentreader; - -public class VorbisCommentReaderException extends Exception { - private static final long serialVersionUID = 1L; - - public VorbisCommentReaderException() { - super(); - } - - public VorbisCommentReaderException(String message, Throwable cause) { - super(message, cause); - } - - public VorbisCommentReaderException(String message) { - super(message); - } - - public VorbisCommentReaderException(Throwable message) { - super(message); - } -} |