From 5a234a367df3de297a4c48f67e5bfb73a19958f0 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Mon, 15 Feb 2021 11:07:57 +0100 Subject: [PATCH] Simplified chapter reader No longer uses code duplication for opening local and remote streams. Also, switched to OkHttp to handle redirects. --- .../antennapod/core/feed/FeedMedia.java | 9 +- .../handler/MediaDownloadedHandler.java | 2 +- .../antennapod/core/util/ChapterUtils.java | 223 +++++------------- .../core/util/playback/ExternalMedia.java | 4 +- .../core/util/playback/RemoteMedia.java | 2 +- 5 files changed, 67 insertions(+), 173 deletions(-) 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 b3b3d5c7a..0af70061e 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 @@ -407,14 +407,7 @@ public class FeedMedia extends FeedFile implements Playable { if (item.hasChapters()) { chaptersFromDatabase = DBReader.loadChaptersOfFeedItem(item); } - - List chaptersFromMediaFile; - if (localFileAvailable()) { - chaptersFromMediaFile = ChapterUtils.loadChaptersFromFileUrl(this); - } else { - chaptersFromMediaFile = ChapterUtils.loadChaptersFromStreamUrl(this, context); - } - + List chaptersFromMediaFile = ChapterUtils.loadChaptersFromMediaFile(this, context); return ChapterMerger.merge(chaptersFromDatabase, chaptersFromMediaFile); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java index 501214399..7712ca36b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java @@ -56,7 +56,7 @@ public class MediaDownloadedHandler implements Runnable { // check if file has chapters if (media.getItem() != null && !media.getItem().hasChapters()) { - media.setChapters(ChapterUtils.loadChaptersFromFileUrl(media)); + media.setChapters(ChapterUtils.loadChaptersFromMediaFile(media, context)); } // Get duration 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 d4a2cdca6..ee07759d2 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 @@ -3,32 +3,27 @@ package de.danoeh.antennapod.core.util; import android.content.ContentResolver; import android.content.Context; import android.net.Uri; -import androidx.annotation.NonNull; import android.util.Log; - -import java.net.URLConnection; -import de.danoeh.antennapod.core.ClientConfig; -import org.apache.commons.io.IOUtils; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Collections; -import java.util.List; - +import androidx.annotation.NonNull; import de.danoeh.antennapod.core.feed.Chapter; +import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; 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.core.util.playback.Playable; import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentChapterReader; import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentReaderException; +import okhttp3.Request; +import okhttp3.Response; import org.apache.commons.io.input.CountingInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.List; + /** * Utility class for getting chapter data from media files. */ @@ -52,93 +47,54 @@ public class ChapterUtils { return chapters.size() - 1; } - public static List loadChaptersFromStreamUrl(Playable media, Context context) { - List chapters = ChapterUtils.readID3ChaptersFromPlayableStreamUrl(media, context); - if (chapters == null) { - chapters = ChapterUtils.readOggChaptersFromPlayableStreamUrl(media, context); - } - return chapters; - } - - public static List loadChaptersFromFileUrl(Playable media) { - if (!media.localFileAvailable()) { - Log.e(TAG, "Could not load chapters from file url: local file not available"); - return null; - } - List chapters = ChapterUtils.readID3ChaptersFromPlayableFileUrl(media); - if (chapters == null) { - chapters = ChapterUtils.readOggChaptersFromPlayableFileUrl(media); - } - return chapters; - } - - /** - * Uses the download URL of a media object of a feeditem to read its ID3 - * chapters. - */ - private static List readID3ChaptersFromPlayableStreamUrl(Playable p, Context context) { - if (p == null || p.getStreamUrl() == null) { - Log.e(TAG, "Unable to read ID3 chapters: media or download URL was null"); - return null; - } - Log.d(TAG, "Reading id3 chapters from item " + p.getEpisodeTitle()); - CountingInputStream in = null; - try { - if (p.getStreamUrl().startsWith(ContentResolver.SCHEME_CONTENT)) { - Uri uri = Uri.parse(p.getStreamUrl()); - in = new CountingInputStream(context.getContentResolver().openInputStream(uri)); - } else { - URL url = new URL(p.getStreamUrl()); - URLConnection urlConnection = url.openConnection(); - urlConnection.setRequestProperty("User-Agent", ClientConfig.USER_AGENT); - in = new CountingInputStream(urlConnection.getInputStream()); - } - List chapters = readChaptersFrom(in); + public static List loadChaptersFromMediaFile(Playable playable, Context context) { + try (CountingInputStream in = openStream(playable, context)) { + List chapters = readId3ChaptersFrom(in); if (!chapters.isEmpty()) { + Log.i(TAG, "Chapters loaded"); return chapters; } - Log.i(TAG, "Chapters loaded"); - } catch (IOException | ID3ReaderException | IllegalArgumentException e) { - Log.e(TAG, Log.getStackTraceString(e)); - } finally { - IOUtils.closeQuietly(in); - } - return null; - } - - /** - * Uses the file URL of a media object of a feeditem to read its ID3 - * chapters. - */ - private static List readID3ChaptersFromPlayableFileUrl(Playable p) { - if (p == null || !p.localFileAvailable() || p.getLocalMediaUrl() == null) { - return null; - } - Log.d(TAG, "Reading id3 chapters from item " + p.getEpisodeTitle()); - File source = new File(p.getLocalMediaUrl()); - if (!source.exists()) { - Log.e(TAG, "Unable to read id3 chapters: Source doesn't exist"); - return null; - } - - CountingInputStream in = null; - try { - in = new CountingInputStream(new BufferedInputStream(new FileInputStream(source))); - List chapters = readChaptersFrom(in); - if (!chapters.isEmpty()) { - return chapters; - } - Log.i(TAG, "Chapters loaded"); } catch (IOException | ID3ReaderException e) { - Log.e(TAG, Log.getStackTraceString(e)); - } finally { - IOUtils.closeQuietly(in); + Log.e(TAG, "Unable to load ID3 chapters: " + e.getMessage()); + } + + try (CountingInputStream in = openStream(playable, context)) { + List chapters = readOggChaptersFromInputStream(in); + if (!chapters.isEmpty()) { + Log.i(TAG, "Chapters loaded"); + return chapters; + } + } catch (IOException | VorbisCommentReaderException e) { + Log.e(TAG, "Unable to load vorbis chapters: " + e.getMessage()); } return null; } + private static CountingInputStream openStream(Playable playable, Context context) throws IOException { + if (playable.localFileAvailable()) { + if (playable.getLocalMediaUrl() == null) { + throw new IOException("No local url"); + } + File source = new File(playable.getLocalMediaUrl()); + if (!source.exists()) { + throw new IOException("Local file does not exist"); + } + return new CountingInputStream(new FileInputStream(source)); + } else if (playable.getStreamUrl().startsWith(ContentResolver.SCHEME_CONTENT)) { + Uri uri = Uri.parse(playable.getStreamUrl()); + return new CountingInputStream(context.getContentResolver().openInputStream(uri)); + } else { + Request request = new Request.Builder().url(playable.getStreamUrl()).build(); + Response response = AntennapodHttpClient.getHttpClient().newCall(request).execute(); + if (response.body() == null) { + throw new IOException("Body is null"); + } + return new CountingInputStream(response.body().byteStream()); + } + } + @NonNull - private static List readChaptersFrom(CountingInputStream in) throws IOException, ID3ReaderException { + private static List readId3ChaptersFrom(CountingInputStream in) throws IOException, ID3ReaderException { ChapterReader reader = new ChapterReader(); reader.readInputStream(in); List chapters = reader.getChapters(); @@ -156,73 +112,21 @@ public class ChapterUtils { return chapters; } - private static List readOggChaptersFromPlayableStreamUrl(Playable media, Context context) { - if (media == null || !media.streamAvailable()) { - return null; + @NonNull + private static List readOggChaptersFromInputStream(InputStream input) throws VorbisCommentReaderException { + VorbisCommentChapterReader reader = new VorbisCommentChapterReader(); + reader.readInputStream(input); + List chapters = reader.getChapters(); + if (chapters == null) { + Log.i(TAG, "ChapterReader could not find any Ogg vorbis chapters"); + return Collections.emptyList(); } - InputStream input = null; - try { - if (media.getStreamUrl().startsWith(ContentResolver.SCHEME_CONTENT)) { - Uri uri = Uri.parse(media.getStreamUrl()); - input = context.getContentResolver().openInputStream(uri); - } else { - URL url = new URL(media.getStreamUrl()); - URLConnection urlConnection = url.openConnection(); - urlConnection.setRequestProperty("User-Agent", ClientConfig.USER_AGENT); - input = urlConnection.getInputStream(); - } - if (input != null) { - return readOggChaptersFromInputStream(media, input); - } - } catch (IOException | IllegalArgumentException e) { - Log.e(TAG, Log.getStackTraceString(e)); - } finally { - IOUtils.closeQuietly(input); + Collections.sort(chapters, new ChapterStartTimeComparator()); + enumerateEmptyChapterTitles(chapters); + if (chaptersValid(chapters)) { + return chapters; } - return null; - } - - private static List readOggChaptersFromPlayableFileUrl(Playable media) { - if (media == null || media.getLocalMediaUrl() == null) { - return null; - } - File source = new File(media.getLocalMediaUrl()); - if (source.exists()) { - InputStream input = null; - try { - input = new BufferedInputStream(new FileInputStream(source)); - return readOggChaptersFromInputStream(media, input); - } catch (FileNotFoundException e) { - Log.e(TAG, Log.getStackTraceString(e)); - } finally { - IOUtils.closeQuietly(input); - } - } - return null; - } - - private static List readOggChaptersFromInputStream(Playable p, InputStream input) { - Log.d(TAG, "Trying to read chapters from item with title " + p.getEpisodeTitle()); - try { - VorbisCommentChapterReader reader = new VorbisCommentChapterReader(); - reader.readInputStream(input); - List chapters = reader.getChapters(); - if (chapters == null) { - Log.i(TAG, "ChapterReader could not find any Ogg vorbis chapters"); - return null; - } - Collections.sort(chapters, new ChapterStartTimeComparator()); - enumerateEmptyChapterTitles(chapters); - if (chaptersValid(chapters)) { - Log.i(TAG, "Chapters loaded"); - return chapters; - } else { - Log.e(TAG, "Chapter data was invalid"); - } - } catch (VorbisCommentReaderException e) { - e.printStackTrace(); - } - return null; + return Collections.emptyList(); } /** @@ -248,5 +152,4 @@ public class ChapterUtils { } return true; } - } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java index 39fceb27c..007658626 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java @@ -118,13 +118,11 @@ public class ExternalMedia implements Playable { } else { pubDate = null; } - - setChapters(ChapterUtils.loadChaptersFromFileUrl(this)); } @Override public void loadChapterMarks(Context context) { - + setChapters(ChapterUtils.loadChaptersFromMediaFile(this, context)); } @Override diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/RemoteMedia.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/RemoteMedia.java index 29eb20aca..7de1a7812 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/RemoteMedia.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/RemoteMedia.java @@ -130,7 +130,7 @@ public class RemoteMedia implements Playable { @Override public void loadChapterMarks(Context context) { - setChapters(ChapterUtils.loadChaptersFromStreamUrl(this, context)); + setChapters(ChapterUtils.loadChaptersFromMediaFile(this, context)); } @Override