diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java b/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java index 5d685c24f..7ddaa080a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java @@ -34,6 +34,7 @@ import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.model.feed.FeedPreferences; import de.danoeh.antennapod.model.playback.MediaType; +import de.danoeh.antennapod.parser.feed.util.MimeTypeUtils; public class LocalFeedUpdater { @@ -74,21 +75,8 @@ public class LocalFeedUpdater { List mediaFiles = new ArrayList<>(); Set mediaFileNames = new HashSet<>(); for (DocumentFile file : documentFolder.listFiles()) { - String mime = file.getType(); - if (mime == null) { - continue; - } - - MediaType mediaType = MediaType.fromMimeType(mime); - if (mediaType == MediaType.UNKNOWN) { - String path = file.getUri().toString(); - int fileExtensionPosition = path.lastIndexOf('.'); - if (fileExtensionPosition >= 0) { - String extensionWithoutDot = path.substring(fileExtensionPosition + 1); - mediaType = MediaType.fromFileExtension(extensionWithoutDot); - } - } - + String mimeType = MimeTypeUtils.getMimeType(file.getType(), file.getUri().toString()); + MediaType mediaType = MediaType.fromMimeType(mimeType); if (mediaType == MediaType.AUDIO || mediaType == MediaType.VIDEO) { mediaFiles.add(file); mediaFileNames.add(file.getName()); diff --git a/model/src/main/java/de/danoeh/antennapod/model/playback/MediaType.java b/model/src/main/java/de/danoeh/antennapod/model/playback/MediaType.java index 6a7b36097..799977e9a 100644 --- a/model/src/main/java/de/danoeh/antennapod/model/playback/MediaType.java +++ b/model/src/main/java/de/danoeh/antennapod/model/playback/MediaType.java @@ -15,16 +15,6 @@ public enum MediaType { "application/x-flac" )); - // based on https://developer.android.com/guide/topics/media/media-formats - static final Set AUDIO_FILE_EXTENSIONS = new HashSet<>(Arrays.asList( - "3gp", "aac", "amr", "flac", "imy", "m4a", "mid", "mkv", "mp3", "mp4", "mxmf", "oga", - "ogg", "ogx", "opus", "ota", "rtttl", "rtx", "wav", "xmf" - )); - - static final Set VIDEO_FILE_EXTENSIONS = new HashSet<>(Arrays.asList( - "3gp", "mkv", "mp4", "ogg", "ogv", "ogx", "webm" - )); - public static MediaType fromMimeType(String mimeType) { if (TextUtils.isEmpty(mimeType)) { return MediaType.UNKNOWN; @@ -37,20 +27,4 @@ public enum MediaType { } return MediaType.UNKNOWN; } - - /** - * @param extensionWithoutDot the file extension (suffix) without the dot - * @return the {@link MediaType} that likely corresponds to the extension. However, since the - * extension is not always enough to determine whether a file is an audio or video (3gp - * can be both, for example), this may not be correct. As a result, where possible, - * {@link #fromMimeType(String) fromMimeType} should always be tried first. - */ - public static MediaType fromFileExtension(String extensionWithoutDot) { - if (AUDIO_FILE_EXTENSIONS.contains(extensionWithoutDot)) { - return MediaType.AUDIO; - } else if (VIDEO_FILE_EXTENSIONS.contains(extensionWithoutDot)) { - return MediaType.VIDEO; - } - return MediaType.UNKNOWN; - } } diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java index ef802c355..a79556c2c 100644 --- a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java @@ -13,7 +13,7 @@ import org.xml.sax.Attributes; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.parser.feed.element.SyndElement; -import de.danoeh.antennapod.parser.feed.util.SyndTypeUtils; +import de.danoeh.antennapod.parser.feed.util.MimeTypeUtils; public class Atom extends Namespace { private static final String TAG = "NSAtom"; @@ -91,15 +91,11 @@ public class Atom extends Namespace { } catch (NumberFormatException e) { Log.d(TAG, "Length attribute could not be parsed."); } - String type = attributes.getValue(LINK_TYPE); - - if (type == null) { - type = SyndTypeUtils.getMimeTypeFromUrl(href); - } + String mimeType = MimeTypeUtils.getMimeType(attributes.getValue(LINK_TYPE), href); FeedItem currItem = state.getCurrentItem(); - if (SyndTypeUtils.enclosureTypeValid(type) && currItem != null && !currItem.hasMedia()) { - currItem.setMedia(new FeedMedia(currItem, href, size, type)); + if (MimeTypeUtils.isMediaFile(mimeType) && currItem != null && !currItem.hasMedia()) { + currItem.setMedia(new FeedMedia(currItem, href, size, mimeType)); } } else if (LINK_REL_PAYMENT.equals(rel)) { state.getCurrentItem().setPaymentLink(href); diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Media.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Media.java index f480a0417..85cafea84 100644 --- a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Media.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Media.java @@ -11,7 +11,7 @@ import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.parser.feed.element.AtomText; -import de.danoeh.antennapod.parser.feed.util.SyndTypeUtils; +import de.danoeh.antennapod.parser.feed.util.MimeTypeUtils; /** Processes tags from the http://search.yahoo.com/mrss/ namespace. */ public class Media extends Namespace { @@ -43,33 +43,28 @@ public class Media extends Namespace { Attributes attributes) { if (CONTENT.equals(localName)) { String url = attributes.getValue(DOWNLOAD_URL); - String type = attributes.getValue(MIME_TYPE); String defaultStr = attributes.getValue(DEFAULT); String medium = attributes.getValue(MEDIUM); boolean validTypeMedia = false; boolean validTypeImage = false; boolean isDefault = "true".equals(defaultStr); - String guessedType = SyndTypeUtils.getMimeTypeFromUrl(url); + String mimeType = MimeTypeUtils.getMimeType(attributes.getValue(MIME_TYPE), url); if (MEDIUM_AUDIO.equals(medium)) { validTypeMedia = true; - type = "audio/*"; + mimeType = "audio/*"; } else if (MEDIUM_VIDEO.equals(medium)) { validTypeMedia = true; - type = "video/*"; - } else if (MEDIUM_IMAGE.equals(medium) && (guessedType == null - || (!guessedType.startsWith("audio/") && !guessedType.startsWith("video/")))) { + mimeType = "video/*"; + } else if (MEDIUM_IMAGE.equals(medium) && (mimeType == null + || (!mimeType.startsWith("audio/") && !mimeType.startsWith("video/")))) { // Apparently, some publishers explicitly specify the audio file as an image validTypeImage = true; - type = "image/*"; + mimeType = "image/*"; } else { - if (type == null) { - type = guessedType; - } - - if (SyndTypeUtils.enclosureTypeValid(type)) { + if (MimeTypeUtils.isMediaFile(mimeType)) { validTypeMedia = true; - } else if (SyndTypeUtils.imageTypeValid(type)) { + } else if (MimeTypeUtils.isImageFile(mimeType)) { validTypeImage = true; } } @@ -94,7 +89,7 @@ public class Media extends Namespace { Log.e(TAG, "Duration \"" + durationStr + "\" could not be parsed"); } } - FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, type); + FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, mimeType); if (durationMs > 0) { media.setDuration(durationMs); } diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Rss20.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Rss20.java index a39e1b5b7..1c1ba9f53 100644 --- a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Rss20.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Rss20.java @@ -12,7 +12,7 @@ import org.xml.sax.Attributes; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedMedia; -import de.danoeh.antennapod.parser.feed.util.SyndTypeUtils; +import de.danoeh.antennapod.parser.feed.util.MimeTypeUtils; import java.util.Locale; @@ -46,18 +46,12 @@ public class Rss20 extends Namespace { state.getItems().add(state.getCurrentItem()); state.getCurrentItem().setFeed(state.getFeed()); } else if (ENCLOSURE.equals(localName) && ITEM.equals(state.getTagstack().peek().getName())) { - String type = attributes.getValue(ENC_TYPE); String url = attributes.getValue(ENC_URL); - - boolean validType = SyndTypeUtils.enclosureTypeValid(type); - if (!validType) { - type = SyndTypeUtils.getMimeTypeFromUrl(url); - validType = SyndTypeUtils.enclosureTypeValid(type); - } + String mimeType = MimeTypeUtils.getMimeType(attributes.getValue(ENC_TYPE), url); boolean validUrl = !TextUtils.isEmpty(url); if (state.getCurrentItem() != null && state.getCurrentItem().getMedia() == null - && validType && validUrl) { + && MimeTypeUtils.isMediaFile(mimeType) && validUrl) { long size = 0; try { size = Long.parseLong(attributes.getValue(ENC_LEN)); @@ -68,7 +62,7 @@ public class Rss20 extends Namespace { } catch (NumberFormatException e) { Log.d(TAG, "Length attribute could not be parsed."); } - FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, type); + FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, mimeType); state.getCurrentItem().setMedia(media); } } diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/MimeTypeUtils.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/MimeTypeUtils.java new file mode 100644 index 000000000..be1048050 --- /dev/null +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/MimeTypeUtils.java @@ -0,0 +1,83 @@ +package de.danoeh.antennapod.parser.feed.util; + +import android.webkit.MimeTypeMap; +import androidx.annotation.Nullable; +import org.apache.commons.io.FilenameUtils; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Utility class for handling MIME-Types of enclosures. + * */ +public class MimeTypeUtils { + public static final String OCTET_STREAM = "application/octet-stream"; + + // based on https://developer.android.com/guide/topics/media/media-formats + static final Set AUDIO_FILE_EXTENSIONS = new HashSet<>(Arrays.asList( + "3gp", "aac", "amr", "flac", "imy", "m4a", "mid", "mkv", "mp3", "mp4", "mxmf", "oga", + "ogg", "ogx", "opus", "ota", "rtttl", "rtx", "wav", "xmf" + )); + + static final Set VIDEO_FILE_EXTENSIONS = new HashSet<>(Arrays.asList( + "3gp", "mkv", "mp4", "ogg", "ogv", "ogx", "webm" + )); + + private MimeTypeUtils() { + + } + + @Nullable + public static String getMimeType(@Nullable String type, @Nullable String filename) { + if (isMediaFile(type) && !OCTET_STREAM.equals(type)) { + return type; + } + String filenameType = MimeTypeUtils.getMimeTypeFromUrl(filename); + if (isMediaFile(filenameType)) { + return filenameType; + } + return type; + } + + public static boolean isMediaFile(String type) { + if (type == null) { + return false; + } else { + return type.startsWith("audio/") + || type.startsWith("video/") + || type.equals("application/ogg") + || type.equals("application/octet-stream"); + } + } + + public static boolean isImageFile(String type) { + if (type == null) { + return false; + } else { + return type.startsWith("image/"); + } + } + + /** + * Should be used if mime-type of enclosure tag is not supported. This + * method will return the mime-type of the file extension. + */ + private static String getMimeTypeFromUrl(String url) { + if (url == null) { + return null; + } + String extension = FilenameUtils.getExtension(url); + String mapResult = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + if (mapResult != null) { + return mapResult; + } + + if (AUDIO_FILE_EXTENSIONS.contains(extension)) { + return "audio/*"; + } else if (VIDEO_FILE_EXTENSIONS.contains(extension)) { + return "video/*"; + } + return null; + } +} diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/SyndTypeUtils.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/SyndTypeUtils.java deleted file mode 100644 index 2e6cf864f..000000000 --- a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/SyndTypeUtils.java +++ /dev/null @@ -1,44 +0,0 @@ -package de.danoeh.antennapod.parser.feed.util; - -import android.webkit.MimeTypeMap; -import org.apache.commons.io.FilenameUtils; - -/** - * Utility class for handling MIME-Types of enclosures. - * */ -public class SyndTypeUtils { - private SyndTypeUtils() { - - } - - public static boolean enclosureTypeValid(String type) { - if (type == null) { - return false; - } else { - return type.startsWith("audio/") - || type.startsWith("video/") - || type.equals("application/ogg") - || type.equals("application/octet-stream"); - } - } - - public static boolean imageTypeValid(String type) { - if (type == null) { - return false; - } else { - return type.startsWith("image/"); - } - } - - /** - * Should be used if mime-type of enclosure tag is not supported. This - * method will return the mime-type of the file extension. - */ - public static String getMimeTypeFromUrl(String url) { - if (url == null) { - return null; - } - String extension = FilenameUtils.getExtension(url); - return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - } -}