Allow retrying chapter loading if interrupted (#6828)

Chapter loading can sometimes get interrupted, most importantly if
the corresponding fragment tries to refresh the view again.
Before, this set the chapters to an empty list, indicating that it
should not be tried again. Now, interrupted exceptions do not set
the list to be empty, so it can be retried later.
This commit is contained in:
Tony Tam 2024-03-17 00:52:16 -10:00 committed by GitHub
parent 48c0ccb4a2
commit 8dc8cc64a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 51 additions and 32 deletions

View File

@ -10,6 +10,7 @@ import de.danoeh.antennapod.model.MediaMetadataRetrieverCompat;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.io.InterruptedIOException;
import java.util.concurrent.ExecutionException;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
@ -54,14 +55,18 @@ public class MediaDownloadedHandler implements Runnable {
media.setSize(new File(request.getDestination()).length());
media.checkEmbeddedPicture(); // enforce check
// check if file has chapters
if (media.getItem() != null && !media.getItem().hasChapters()) {
media.setChapters(ChapterUtils.loadChaptersFromMediaFile(media, context));
try {
// Cache chapters if file has them
if (media.getItem() != null && !media.getItem().hasChapters()) {
media.setChapters(ChapterUtils.loadChaptersFromMediaFile(media, context));
}
if (media.getItem() != null && media.getItem().getPodcastIndexChapterUrl() != null) {
ChapterUtils.loadChaptersFromUrl(media.getItem().getPodcastIndexChapterUrl(), false);
}
} catch (InterruptedIOException ignore) {
// Ignore
}
if (media.getItem() != null && media.getItem().getPodcastIndexChapterUrl() != null) {
ChapterUtils.loadChaptersFromUrl(media.getItem().getPodcastIndexChapterUrl(), false);
}
// Get duration
String durationStr = null;
try (MediaMetadataRetrieverCompat mmr = new MediaMetadataRetrieverCompat()) {

View File

@ -28,6 +28,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.util.Collections;
import java.util.List;
@ -60,42 +61,50 @@ public class ChapterUtils {
return;
}
List<Chapter> chaptersFromDatabase = null;
List<Chapter> chaptersFromPodcastIndex = null;
if (playable instanceof FeedMedia) {
FeedMedia feedMedia = (FeedMedia) playable;
if (feedMedia.getItem() == null) {
feedMedia.setItem(DBReader.getFeedItem(feedMedia.getItemId()));
}
if (feedMedia.getItem().hasChapters()) {
chaptersFromDatabase = DBReader.loadChaptersOfFeedItem(feedMedia.getItem());
try {
List<Chapter> chaptersFromDatabase = null;
List<Chapter> chaptersFromPodcastIndex = null;
if (playable instanceof FeedMedia) {
FeedMedia feedMedia = (FeedMedia) playable;
if (feedMedia.getItem() == null) {
feedMedia.setItem(DBReader.getFeedItem(feedMedia.getItemId()));
}
if (feedMedia.getItem().hasChapters()) {
chaptersFromDatabase = DBReader.loadChaptersOfFeedItem(feedMedia.getItem());
}
if (!TextUtils.isEmpty(feedMedia.getItem().getPodcastIndexChapterUrl())) {
chaptersFromPodcastIndex = ChapterUtils.loadChaptersFromUrl(
feedMedia.getItem().getPodcastIndexChapterUrl(), forceRefresh);
}
}
if (!TextUtils.isEmpty(feedMedia.getItem().getPodcastIndexChapterUrl())) {
chaptersFromPodcastIndex = ChapterUtils.loadChaptersFromUrl(
feedMedia.getItem().getPodcastIndexChapterUrl(), forceRefresh);
List<Chapter> chaptersFromMediaFile = ChapterUtils.loadChaptersFromMediaFile(playable, context);
List<Chapter> chaptersMergePhase1 = ChapterMerger.merge(chaptersFromDatabase, chaptersFromMediaFile);
List<Chapter> chapters = ChapterMerger.merge(chaptersMergePhase1, chaptersFromPodcastIndex);
if (chapters == null) {
// Do not try loading again. There are no chapters or parsing failed.
playable.setChapters(Collections.emptyList());
} else {
playable.setChapters(chapters);
}
}
List<Chapter> chaptersFromMediaFile = ChapterUtils.loadChaptersFromMediaFile(playable, context);
List<Chapter> chaptersMergePhase1 = ChapterMerger.merge(chaptersFromDatabase, chaptersFromMediaFile);
List<Chapter> chapters = ChapterMerger.merge(chaptersMergePhase1, chaptersFromPodcastIndex);
if (chapters == null) {
// Do not try loading again. There are no chapters.
playable.setChapters(Collections.emptyList());
} else {
playable.setChapters(chapters);
} catch (InterruptedIOException e) {
Log.d(TAG, "Chapter loading interrupted");
playable.setChapters(null); // Allow later retry
}
}
public static List<Chapter> loadChaptersFromMediaFile(Playable playable, Context context) {
public static List<Chapter> loadChaptersFromMediaFile(Playable playable, Context context)
throws InterruptedIOException {
try (CountingInputStream in = openStream(playable, context)) {
List<Chapter> chapters = readId3ChaptersFrom(in);
if (!chapters.isEmpty()) {
Log.i(TAG, "Chapters loaded");
return chapters;
}
} catch (InterruptedIOException e) {
throw e;
} catch (IOException | ID3ReaderException e) {
Log.e(TAG, "Unable to load ID3 chapters: " + e.getMessage());
}
@ -106,6 +115,8 @@ public class ChapterUtils {
Log.i(TAG, "Chapters loaded");
return chapters;
}
} catch (InterruptedIOException e) {
throw e;
} catch (IOException | VorbisCommentReaderException e) {
Log.e(TAG, "Unable to load vorbis chapters: " + e.getMessage());
}
@ -135,7 +146,7 @@ public class ChapterUtils {
}
}
public static List<Chapter> loadChaptersFromUrl(String url, boolean forceRefresh) {
public static List<Chapter> loadChaptersFromUrl(String url, boolean forceRefresh) throws InterruptedIOException {
if (forceRefresh) {
return loadChaptersFromUrl(url, CacheControl.FORCE_NETWORK);
}
@ -147,7 +158,8 @@ public class ChapterUtils {
return cachedChapters;
}
private static List<Chapter> loadChaptersFromUrl(String url, CacheControl cacheControl) {
private static List<Chapter> loadChaptersFromUrl(String url, CacheControl cacheControl)
throws InterruptedIOException {
Response response = null;
try {
Request request = new Request.Builder().url(url).cacheControl(cacheControl).build();
@ -155,6 +167,8 @@ public class ChapterUtils {
if (response.isSuccessful() && response.body() != null) {
return PodcastIndexChapterParser.parse(response.body().string());
}
} catch (InterruptedIOException e) {
throw e;
} catch (IOException e) {
e.printStackTrace();
} finally {