Merge pull request #5670 from ByteHamster/mime-octet-stream
When mime type is octet-stream, guess from the file name
This commit is contained in:
commit
37eec9902b
|
@ -34,6 +34,7 @@ import de.danoeh.antennapod.model.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||||
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
||||||
import de.danoeh.antennapod.model.playback.MediaType;
|
import de.danoeh.antennapod.model.playback.MediaType;
|
||||||
|
import de.danoeh.antennapod.parser.feed.util.MimeTypeUtils;
|
||||||
|
|
||||||
public class LocalFeedUpdater {
|
public class LocalFeedUpdater {
|
||||||
|
|
||||||
|
@ -74,21 +75,8 @@ public class LocalFeedUpdater {
|
||||||
List<DocumentFile> mediaFiles = new ArrayList<>();
|
List<DocumentFile> mediaFiles = new ArrayList<>();
|
||||||
Set<String> mediaFileNames = new HashSet<>();
|
Set<String> mediaFileNames = new HashSet<>();
|
||||||
for (DocumentFile file : documentFolder.listFiles()) {
|
for (DocumentFile file : documentFolder.listFiles()) {
|
||||||
String mime = file.getType();
|
String mimeType = MimeTypeUtils.getMimeType(file.getType(), file.getUri().toString());
|
||||||
if (mime == null) {
|
MediaType mediaType = MediaType.fromMimeType(mimeType);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mediaType == MediaType.AUDIO || mediaType == MediaType.VIDEO) {
|
if (mediaType == MediaType.AUDIO || mediaType == MediaType.VIDEO) {
|
||||||
mediaFiles.add(file);
|
mediaFiles.add(file);
|
||||||
mediaFileNames.add(file.getName());
|
mediaFileNames.add(file.getName());
|
||||||
|
|
|
@ -15,16 +15,6 @@ public enum MediaType {
|
||||||
"application/x-flac"
|
"application/x-flac"
|
||||||
));
|
));
|
||||||
|
|
||||||
// based on https://developer.android.com/guide/topics/media/media-formats
|
|
||||||
static final Set<String> 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<String> VIDEO_FILE_EXTENSIONS = new HashSet<>(Arrays.asList(
|
|
||||||
"3gp", "mkv", "mp4", "ogg", "ogv", "ogx", "webm"
|
|
||||||
));
|
|
||||||
|
|
||||||
public static MediaType fromMimeType(String mimeType) {
|
public static MediaType fromMimeType(String mimeType) {
|
||||||
if (TextUtils.isEmpty(mimeType)) {
|
if (TextUtils.isEmpty(mimeType)) {
|
||||||
return MediaType.UNKNOWN;
|
return MediaType.UNKNOWN;
|
||||||
|
@ -37,20 +27,4 @@ public enum MediaType {
|
||||||
}
|
}
|
||||||
return MediaType.UNKNOWN;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import org.xml.sax.Attributes;
|
||||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||||
import de.danoeh.antennapod.parser.feed.element.SyndElement;
|
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 {
|
public class Atom extends Namespace {
|
||||||
private static final String TAG = "NSAtom";
|
private static final String TAG = "NSAtom";
|
||||||
|
@ -91,15 +91,11 @@ public class Atom extends Namespace {
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
Log.d(TAG, "Length attribute could not be parsed.");
|
Log.d(TAG, "Length attribute could not be parsed.");
|
||||||
}
|
}
|
||||||
String type = attributes.getValue(LINK_TYPE);
|
String mimeType = MimeTypeUtils.getMimeType(attributes.getValue(LINK_TYPE), href);
|
||||||
|
|
||||||
if (type == null) {
|
|
||||||
type = SyndTypeUtils.getMimeTypeFromUrl(href);
|
|
||||||
}
|
|
||||||
|
|
||||||
FeedItem currItem = state.getCurrentItem();
|
FeedItem currItem = state.getCurrentItem();
|
||||||
if (SyndTypeUtils.enclosureTypeValid(type) && currItem != null && !currItem.hasMedia()) {
|
if (MimeTypeUtils.isMediaFile(mimeType) && currItem != null && !currItem.hasMedia()) {
|
||||||
currItem.setMedia(new FeedMedia(currItem, href, size, type));
|
currItem.setMedia(new FeedMedia(currItem, href, size, mimeType));
|
||||||
}
|
}
|
||||||
} else if (LINK_REL_PAYMENT.equals(rel)) {
|
} else if (LINK_REL_PAYMENT.equals(rel)) {
|
||||||
state.getCurrentItem().setPaymentLink(href);
|
state.getCurrentItem().setPaymentLink(href);
|
||||||
|
|
|
@ -11,7 +11,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||||
import de.danoeh.antennapod.parser.feed.element.AtomText;
|
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. */
|
/** Processes tags from the http://search.yahoo.com/mrss/ namespace. */
|
||||||
public class Media extends Namespace {
|
public class Media extends Namespace {
|
||||||
|
@ -43,33 +43,28 @@ public class Media extends Namespace {
|
||||||
Attributes attributes) {
|
Attributes attributes) {
|
||||||
if (CONTENT.equals(localName)) {
|
if (CONTENT.equals(localName)) {
|
||||||
String url = attributes.getValue(DOWNLOAD_URL);
|
String url = attributes.getValue(DOWNLOAD_URL);
|
||||||
String type = attributes.getValue(MIME_TYPE);
|
|
||||||
String defaultStr = attributes.getValue(DEFAULT);
|
String defaultStr = attributes.getValue(DEFAULT);
|
||||||
String medium = attributes.getValue(MEDIUM);
|
String medium = attributes.getValue(MEDIUM);
|
||||||
boolean validTypeMedia = false;
|
boolean validTypeMedia = false;
|
||||||
boolean validTypeImage = false;
|
boolean validTypeImage = false;
|
||||||
boolean isDefault = "true".equals(defaultStr);
|
boolean isDefault = "true".equals(defaultStr);
|
||||||
String guessedType = SyndTypeUtils.getMimeTypeFromUrl(url);
|
String mimeType = MimeTypeUtils.getMimeType(attributes.getValue(MIME_TYPE), url);
|
||||||
|
|
||||||
if (MEDIUM_AUDIO.equals(medium)) {
|
if (MEDIUM_AUDIO.equals(medium)) {
|
||||||
validTypeMedia = true;
|
validTypeMedia = true;
|
||||||
type = "audio/*";
|
mimeType = "audio/*";
|
||||||
} else if (MEDIUM_VIDEO.equals(medium)) {
|
} else if (MEDIUM_VIDEO.equals(medium)) {
|
||||||
validTypeMedia = true;
|
validTypeMedia = true;
|
||||||
type = "video/*";
|
mimeType = "video/*";
|
||||||
} else if (MEDIUM_IMAGE.equals(medium) && (guessedType == null
|
} else if (MEDIUM_IMAGE.equals(medium) && (mimeType == null
|
||||||
|| (!guessedType.startsWith("audio/") && !guessedType.startsWith("video/")))) {
|
|| (!mimeType.startsWith("audio/") && !mimeType.startsWith("video/")))) {
|
||||||
// Apparently, some publishers explicitly specify the audio file as an image
|
// Apparently, some publishers explicitly specify the audio file as an image
|
||||||
validTypeImage = true;
|
validTypeImage = true;
|
||||||
type = "image/*";
|
mimeType = "image/*";
|
||||||
} else {
|
} else {
|
||||||
if (type == null) {
|
if (MimeTypeUtils.isMediaFile(mimeType)) {
|
||||||
type = guessedType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SyndTypeUtils.enclosureTypeValid(type)) {
|
|
||||||
validTypeMedia = true;
|
validTypeMedia = true;
|
||||||
} else if (SyndTypeUtils.imageTypeValid(type)) {
|
} else if (MimeTypeUtils.isImageFile(mimeType)) {
|
||||||
validTypeImage = true;
|
validTypeImage = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +89,7 @@ public class Media extends Namespace {
|
||||||
Log.e(TAG, "Duration \"" + durationStr + "\" could not be parsed");
|
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) {
|
if (durationMs > 0) {
|
||||||
media.setDuration(durationMs);
|
media.setDuration(durationMs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import org.xml.sax.Attributes;
|
||||||
|
|
||||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
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;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@ -46,18 +46,12 @@ public class Rss20 extends Namespace {
|
||||||
state.getItems().add(state.getCurrentItem());
|
state.getItems().add(state.getCurrentItem());
|
||||||
state.getCurrentItem().setFeed(state.getFeed());
|
state.getCurrentItem().setFeed(state.getFeed());
|
||||||
} else if (ENCLOSURE.equals(localName) && ITEM.equals(state.getTagstack().peek().getName())) {
|
} else if (ENCLOSURE.equals(localName) && ITEM.equals(state.getTagstack().peek().getName())) {
|
||||||
String type = attributes.getValue(ENC_TYPE);
|
|
||||||
String url = attributes.getValue(ENC_URL);
|
String url = attributes.getValue(ENC_URL);
|
||||||
|
String mimeType = MimeTypeUtils.getMimeType(attributes.getValue(ENC_TYPE), url);
|
||||||
boolean validType = SyndTypeUtils.enclosureTypeValid(type);
|
|
||||||
if (!validType) {
|
|
||||||
type = SyndTypeUtils.getMimeTypeFromUrl(url);
|
|
||||||
validType = SyndTypeUtils.enclosureTypeValid(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean validUrl = !TextUtils.isEmpty(url);
|
boolean validUrl = !TextUtils.isEmpty(url);
|
||||||
if (state.getCurrentItem() != null && state.getCurrentItem().getMedia() == null
|
if (state.getCurrentItem() != null && state.getCurrentItem().getMedia() == null
|
||||||
&& validType && validUrl) {
|
&& MimeTypeUtils.isMediaFile(mimeType) && validUrl) {
|
||||||
long size = 0;
|
long size = 0;
|
||||||
try {
|
try {
|
||||||
size = Long.parseLong(attributes.getValue(ENC_LEN));
|
size = Long.parseLong(attributes.getValue(ENC_LEN));
|
||||||
|
@ -68,7 +62,7 @@ public class Rss20 extends Namespace {
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
Log.d(TAG, "Length attribute could not be parsed.");
|
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);
|
state.getCurrentItem().setMedia(media);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<String> 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<String> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue