summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/close-if-no-reply.yml10
-rw-r--r--CONTRIBUTING.md4
-rw-r--r--app/build.gradle4
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayLocalActionButton.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java28
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/StreamingConfirmationDialog.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java9
-rw-r--r--app/src/main/res/layout/audio_controls.xml25
-rw-r--r--common.gradle6
-rw-r--r--core/build.gradle4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java35
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/GenerativePlaceholderImageModelLoader.java139
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java12
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java82
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java16
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/widget/WidgetUpdater.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/widget/WidgetUpdaterJobService.java4
-rw-r--r--core/src/main/res/raw/local_feed_default_icon.pngbin1240 -> 0 bytes
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/feed/LocalFeedUpdaterTest.java28
-rw-r--r--event/build.gradle4
-rw-r--r--model/build.gradle4
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java1
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/playback/MediaType.java26
-rw-r--r--net/ssl/build.gradle4
-rw-r--r--net/sync/gpoddernet/build.gradle4
-rw-r--r--net/sync/model/build.gradle4
-rw-r--r--parser/feed/build.gradle4
-rw-r--r--parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java12
-rw-r--r--parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Media.java25
-rw-r--r--parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Rss20.java14
-rw-r--r--parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/MimeTypeUtils.java83
-rw-r--r--parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/SyndTypeUtils.java44
-rw-r--r--parser/media/build.gradle4
-rw-r--r--playback/base/build.gradle4
-rw-r--r--playback/cast/build.gradle4
-rw-r--r--ui/app-start-intent/build.gradle4
-rw-r--r--ui/common/build.gradle4
-rw-r--r--ui/png-icons/build.gradle4
48 files changed, 368 insertions, 328 deletions
diff --git a/.github/workflows/close-if-no-reply.yml b/.github/workflows/close-if-no-reply.yml
index c0c32843a..78e4d340a 100644
--- a/.github/workflows/close-if-no-reply.yml
+++ b/.github/workflows/close-if-no-reply.yml
@@ -13,13 +13,15 @@ jobs:
steps:
- uses: actions/stale@v4
with:
- days-before-stale: 10
- days-before-close: 10
+ days-before-stale: 15
+ days-before-close: 15
only-labels: 'Awaiting reply'
stale-issue-label: 'Still awaiting reply'
stale-pr-label: 'Still awaiting reply'
+ stale-issue-message: "This issue will be closed when we don't get a reply within 15 days."
+ stale-pr-message: "This PR will be closed when we don't get a reply within 15 days."
labels-to-remove-when-unstale: 'Awaiting reply'
close-issue-label: "Close reason: no reply"
close-pr-label: "Close reason: no reply"
- close-issue-message: "This issue was closed because we didn't get a reply for 20 days."
- close-pr-message: "This pr was closed because we didn't get a reply for 20 days."
+ close-issue-message: "This issue was closed because we didn't get a reply for 30 days."
+ close-pr-message: "This PR was closed because we didn't get a reply for 30 days."
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e3bc7269d..0017c897d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,7 +8,7 @@ How to report a bug
- If possible, add instructions on how to reproduce the bug.
- If possible, add a logfile to your post. This is especially useful if the bug makes the application crash. AntennaPod has an `export logs` feature for this.
- Usually, you can take a screenshot of your smartphone by pressing *Power* + *Volume down* for a few seconds.
-- Please use the following **[template](.github/ISSUE_TEMPLATE/bug_report.md)**.
+- Please use the following **[template](https://github.com/AntennaPod/AntennaPod/issues/new?assignees=&labels=Type%3A+Possible+bug&template=bug_report.yml)**.
How to submit a feature request
@@ -18,7 +18,7 @@ How to submit a feature request
- To make it easier for us to keep track of requests, please only make one feature request per issue.
- Give a brief explanation about the problem that may currently exist and how your requested feature solves this problem.
- Try to be as specific as possible. Please not only explain what the feature does, but also how. If your request is about (or includes) changing or extending the UI, describe what the UI would look like and how the user would interact with it.
-- Please use the following **[template](.github/ISSUE_TEMPLATE/feature_request.md)**.
+- Please use the following **[template](https://github.com/AntennaPod/AntennaPod/issues/new?assignees=&labels=&template=feature_request.yml)**.
Translating AntennaPod
diff --git a/app/build.gradle b/app/build.gradle
index d011a4404..7b324e878 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -43,8 +43,8 @@ android {
signingConfigs {
releaseConfig {
- v1SigningEnabled true
- v2SigningEnabled true
+ enableV1Signing true
+ enableV2Signing true
if (project.hasProperty("releaseStoreFile")) {
storeFile file(releaseStoreFile)
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java b/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java
index 23c129cb1..c9b8ef371 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java
@@ -100,7 +100,6 @@ public class AutoDownloadTest {
new PlaybackServiceStarter(context, media)
.callEvenIfRunning(true)
.startWhenPrepared(true)
- .shouldStream(true)
.start();
Awaitility.await("episode is playing")
.atMost(2000, MILLISECONDS)
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
index 5ddb6407c..6073e97be 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java
@@ -80,7 +80,6 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> {
}
new PlaybackServiceStarter(getContext(), playable)
- .shouldStream(true)
.startWhenPrepared(true)
.callEvenIfRunning(true)
.start();
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
index 5ab354d05..8351d1fb5 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsRecyclerAdapter.java
@@ -33,7 +33,6 @@ import java.util.Locale;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.NavDrawerData;
import de.danoeh.antennapod.fragment.FeedItemlistFragment;
@@ -255,7 +254,7 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter<Subscription
if (drawerItem.type == NavDrawerData.DrawerItem.Type.FEED) {
Feed feed = ((NavDrawerData.FeedDrawerItem) drawerItem).feed;
boolean textAndImageCombind = feed.isLocalFeed()
- && LocalFeedUpdater.getDefaultIconUrl(itemView.getContext()).equals(feed.getImageUrl());
+ && feed.getImageUrl() != null && feed.getImageUrl().startsWith(Feed.PREFIX_GENERATIVE_COVER);
new CoverLoader(mainActivityRef.get())
.withUri(feed.getImageUrl())
.withPlaceholderView(feedTitle, textAndImageCombind)
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
index 974b12bab..528f38ba7 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java
@@ -42,7 +42,6 @@ public class PlayActionButton extends ItemActionButton {
new PlaybackServiceStarter(context, media)
.callEvenIfRunning(true)
.startWhenPrepared(true)
- .shouldStream(false)
.start();
if (media.getMediaType() == MediaType.VIDEO) {
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayLocalActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayLocalActionButton.java
index ab2122b12..47cd4d66b 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayLocalActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayLocalActionButton.java
@@ -38,7 +38,6 @@ public class PlayLocalActionButton extends ItemActionButton {
new PlaybackServiceStarter(context, media)
.callEvenIfRunning(true)
.startWhenPrepared(true)
- .shouldStream(true)
.start();
if (media.getMediaType() == MediaType.VIDEO) {
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java
index 94c446f50..244022c1c 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java
@@ -48,7 +48,6 @@ public class StreamActionButton extends ItemActionButton {
new PlaybackServiceStarter(context, media)
.callEvenIfRunning(true)
.startWhenPrepared(true)
- .shouldStream(true)
.start();
if (media.getMediaType() == MediaType.VIDEO) {
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
index 5cc1f99c6..841c121e9 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
@@ -10,24 +10,14 @@ import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import android.widget.Button;
import android.widget.CheckBox;
-import android.widget.TextView;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.event.playback.SpeedChangedEvent;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
-import de.danoeh.antennapod.view.PlaybackSpeedSeekBar;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
import java.util.List;
-import java.util.Locale;
public class PlaybackControlsDialog extends DialogFragment {
private PlaybackController controller;
private AlertDialog dialog;
- private PlaybackSpeedSeekBar speedSeekBar;
- private TextView txtvPlaybackSpeed;
public static PlaybackControlsDialog newInstance() {
Bundle arguments = new Bundle();
@@ -48,12 +38,10 @@ public class PlaybackControlsDialog extends DialogFragment {
public void loadMediaInfo() {
setupUi();
setupAudioTracks();
- updateSpeed(new SpeedChangedEvent(getCurrentPlaybackSpeedMultiplier()));
}
};
controller.init();
setupUi();
- EventBus.getDefault().register(this);
}
@Override
@@ -61,7 +49,6 @@ public class PlaybackControlsDialog extends DialogFragment {
super.onStop();
controller.release();
controller = null;
- EventBus.getDefault().unregister(this);
}
@NonNull
@@ -75,15 +62,6 @@ public class PlaybackControlsDialog extends DialogFragment {
}
private void setupUi() {
- txtvPlaybackSpeed = dialog.findViewById(R.id.txtvPlaybackSpeed);
- speedSeekBar = dialog.findViewById(R.id.speed_seek_bar);
- speedSeekBar.setProgressChangedListener(speed -> {
- if (controller != null) {
- controller.setPlaybackSpeed(speed);
- }
- });
- updateSpeed(new SpeedChangedEvent(controller.getCurrentPlaybackSpeedMultiplier()));
-
final CheckBox stereoToMono = dialog.findViewById(R.id.stereo_to_mono);
stereoToMono.setChecked(UserPreferences.stereoToMono());
if (controller != null && !controller.canDownmix()) {
@@ -111,12 +89,6 @@ public class PlaybackControlsDialog extends DialogFragment {
});
}
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void updateSpeed(SpeedChangedEvent event) {
- txtvPlaybackSpeed.setText(String.format(Locale.getDefault(), "%.2fx", event.getNewSpeed()));
- speedSeekBar.updateSpeed(event.getNewSpeed());
- }
-
private void setupAudioTracks() {
List<String> audioTracks = controller.getAudioTracks();
int selectedAudioTrack = controller.getSelectedAudioTrack();
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/StreamingConfirmationDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/StreamingConfirmationDialog.java
index 22f62d410..e0bd59625 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/StreamingConfirmationDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/StreamingConfirmationDialog.java
@@ -33,7 +33,6 @@ public class StreamingConfirmationDialog {
new PlaybackServiceStarter(context, playable)
.callEvenIfRunning(true)
.startWhenPrepared(true)
- .shouldStream(true)
.shouldStreamThisTime(true)
.start();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
index 120d1def8..ee56bb9f9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.fragment;
import android.content.ActivityNotFoundException;
+import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
@@ -140,9 +141,12 @@ public class AddFeedFragment extends Fragment {
alertViewBinding.urlEditText.setHint(R.string.add_podcast_by_url_hint);
ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
- String clipboardContent = clipboard.getText() != null ? clipboard.getText().toString() : "";
- if (clipboardContent.trim().startsWith("http")) {
- alertViewBinding.urlEditText.setText(clipboardContent.trim());
+ final ClipData clipData = clipboard.getPrimaryClip();
+ if (clipData != null && clipData.getItemCount() > 0 && clipData.getItemAt(0).getText() != null) {
+ final String clipboardContent = clipData.getItemAt(0).getText().toString();
+ if (clipboardContent.trim().startsWith("http")) {
+ alertViewBinding.urlEditText.setText(clipboardContent.trim());
+ }
}
builder.setView(alertViewBinding.getRoot());
builder.setPositiveButton(R.string.confirm_label,
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
index 8bfcfd1ed..f76b902cd 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java
@@ -119,13 +119,12 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
String countryCode = prefs.getString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE,
Locale.getDefault().getCountry());
if (countryCode.equals(ItunesTopListLoader.DISCOVER_HIDE_FAKE_COUNTRY_CODE)) {
- errorTextView.setText(String.format(getResources().getString(R.string.discover_is_hidden),
- getResources().getString(R.string.discover_hide)));
+ errorTextView.setText(R.string.discover_is_hidden);
errorView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
- discoverGridLayout.setVisibility(View.INVISIBLE);
- errorRetry.setVisibility(View.INVISIBLE);
- poweredByTextView.setVisibility(View.INVISIBLE);
+ discoverGridLayout.setVisibility(View.GONE);
+ errorRetry.setVisibility(View.GONE);
+ poweredByTextView.setVisibility(View.GONE);
return;
}
diff --git a/app/src/main/res/layout/audio_controls.xml b/app/src/main/res/layout/audio_controls.xml
index 0bfa4f521..dc48006bb 100644
--- a/app/src/main/res/layout/audio_controls.xml
+++ b/app/src/main/res/layout/audio_controls.xml
@@ -19,31 +19,6 @@
android:visibility="gone"
android:layout_marginBottom="8dp" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <TextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/playback_speed"
- style="@style/AntennaPod.TextView.ListItemPrimaryTitle" />
-
- <TextView
- android:id="@+id/txtvPlaybackSpeed"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="1.00x" />
-
- </LinearLayout>
-
- <de.danoeh.antennapod.view.PlaybackSpeedSeekBar
- android:id="@+id/speed_seek_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/common.gradle b/common.gradle
index 4f023212b..8284d2325 100644
--- a/common.gradle
+++ b/common.gradle
@@ -1,9 +1,9 @@
android {
- compileSdkVersion 31
+ compileSdk 31
defaultConfig {
- minSdkVersion 19
- targetSdkVersion 30
+ minSdk 19
+ targetSdk 30
multiDexEnabled false
vectorDrawables.useSupportLibrary true
diff --git a/core/build.gradle b/core/build.gradle
index 700487701..af0e2a7a7 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../common.gradle"
apply from: "../playFlavor.gradle"
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..e0e1bbaa5 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
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.core.feed;
-import android.content.ContentResolver;
import android.content.Context;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
@@ -34,6 +33,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 +74,8 @@ public class LocalFeedUpdater {
List<DocumentFile> mediaFiles = new ArrayList<>();
Set<String> 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());
@@ -116,7 +103,7 @@ public class LocalFeedUpdater {
}
}
- feed.setImageUrl(getImageUrl(context, documentFolder));
+ feed.setImageUrl(getImageUrl(documentFolder));
feed.getPreferences().setAutoDownload(false);
feed.getPreferences().setAutoDeleteAction(FeedPreferences.AutoDeleteAction.NO);
@@ -134,7 +121,7 @@ public class LocalFeedUpdater {
* Returns the image URL for the local feed.
*/
@NonNull
- static String getImageUrl(@NonNull Context context, @NonNull DocumentFile documentFolder) {
+ static String getImageUrl(@NonNull DocumentFile documentFolder) {
// look for special file names
for (String iconLocation : PREFERRED_FEED_IMAGE_FILENAMES) {
DocumentFile image = documentFolder.findFile(iconLocation);
@@ -152,17 +139,7 @@ public class LocalFeedUpdater {
}
// use default icon as fallback
- return getDefaultIconUrl(context);
- }
-
- /**
- * Returns the URL of the default icon for a local feed. The URL refers to an app resource file.
- */
- public static String getDefaultIconUrl(Context context) {
- String resourceEntryName = context.getResources().getResourceEntryName(R.raw.local_feed_default_icon);
- return ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
- + context.getPackageName() + "/raw/"
- + resourceEntryName;
+ return Feed.PREFIX_GENERATIVE_COVER + documentFolder.getUri();
}
private static FeedItem feedContainsFile(Feed feed, String filename) {
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 797addcc1..593b683f7 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
@@ -42,6 +42,7 @@ public class ApGlideModule extends AppGlideModule {
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
registry.replace(String.class, InputStream.class, new MetadataRetrieverLoader.Factory(context));
+ registry.append(String.class, InputStream.class, new GenerativePlaceholderImageModelLoader.Factory());
registry.append(String.class, InputStream.class, new ApOkHttpUrlLoader.Factory());
registry.append(String.class, InputStream.class, new NoHttpStringLoader.StreamFactory());
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/GenerativePlaceholderImageModelLoader.java b/core/src/main/java/de/danoeh/antennapod/core/glide/GenerativePlaceholderImageModelLoader.java
new file mode 100644
index 000000000..a2263bc28
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/GenerativePlaceholderImageModelLoader.java
@@ -0,0 +1,139 @@
+package de.danoeh.antennapod.core.glide;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Shader;
+import androidx.annotation.NonNull;
+import com.bumptech.glide.Priority;
+import com.bumptech.glide.load.DataSource;
+import com.bumptech.glide.load.Options;
+import com.bumptech.glide.load.data.DataFetcher;
+import com.bumptech.glide.load.model.ModelLoader;
+import com.bumptech.glide.load.model.ModelLoaderFactory;
+import com.bumptech.glide.load.model.MultiModelLoaderFactory;
+import com.bumptech.glide.signature.ObjectKey;
+import de.danoeh.antennapod.model.feed.Feed;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Random;
+
+public final class GenerativePlaceholderImageModelLoader implements ModelLoader<String, InputStream> {
+
+ public static class Factory implements ModelLoaderFactory<String, InputStream> {
+ @NonNull
+ @Override
+ public ModelLoader<String, InputStream> build(@NonNull MultiModelLoaderFactory unused) {
+ return new GenerativePlaceholderImageModelLoader();
+ }
+
+ @Override
+ public void teardown() {
+ // Do nothing.
+ }
+ }
+
+ @Override
+ public LoadData<InputStream> buildLoadData(@NonNull String model, int width, int height, @NonNull Options options) {
+ return new LoadData<>(new ObjectKey(model), new EmbeddedImageFetcher(model, width, height));
+ }
+
+ @Override
+ public boolean handles(@NonNull String model) {
+ return model.startsWith(Feed.PREFIX_GENERATIVE_COVER);
+ }
+
+ static class EmbeddedImageFetcher implements DataFetcher<InputStream> {
+ private static final int[] PALETTES = {0xff78909c, 0xffff6f00, 0xff388e3c,
+ 0xff00838f, 0xff7b1fa2, 0xffb71c1c, 0xff2196f3};
+ private final String model;
+ private final int width;
+ private final int height;
+
+ public EmbeddedImageFetcher(String model, int width, int height) {
+ this.model = model;
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
+ final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
+ final Random generator = new Random(model.hashCode());
+ final int lineGridSteps = 4 + generator.nextInt(4);
+ final int slope = width / 4;
+ final float shadowWidth = width * 0.01f;
+ final float lineDistance = ((float) width / (lineGridSteps - 2));
+ final int baseColor = PALETTES[generator.nextInt(PALETTES.length)];
+
+ Paint paint = new Paint();
+ int color = randomShadeOfGrey(generator);
+ paint.setColor(color);
+ paint.setStrokeWidth(lineDistance);
+ paint.setColorFilter(new PorterDuffColorFilter(baseColor, PorterDuff.Mode.MULTIPLY));
+ Paint paintShadow = new Paint();
+ paintShadow.setColor(0xff000000);
+ paintShadow.setStrokeWidth(lineDistance);
+
+ int forcedColorChange = 1 + generator.nextInt(lineGridSteps - 2);
+ for (int i = lineGridSteps - 1; i >= 0; i--) {
+ float linePos = (i - 0.5f) * lineDistance;
+ boolean switchColor = generator.nextFloat() < 0.3f || i == forcedColorChange;
+ if (switchColor) {
+ int newColor = color;
+ while (newColor == color) {
+ newColor = randomShadeOfGrey(generator);
+ }
+ color = newColor;
+ paint.setColor(newColor);
+ canvas.drawLine(linePos + slope + shadowWidth, -slope,
+ linePos - slope + shadowWidth, height + slope, paintShadow);
+ }
+ canvas.drawLine(linePos + slope, -slope,
+ linePos - slope, height + slope, paint);
+ }
+
+ Paint gradientPaint = new Paint();
+ paint.setDither(true);
+ gradientPaint.setShader(new LinearGradient(0, 0, 0, height, 0x00000000, 0x55000000, Shader.TileMode.CLAMP));
+ canvas.drawRect(0, 0, width, height, gradientPaint);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
+ InputStream is = new ByteArrayInputStream(baos.toByteArray());
+ callback.onDataReady(is);
+ }
+
+ private static int randomShadeOfGrey(Random generator) {
+ return 0xff777777 + 0x222222 * generator.nextInt(5);
+ }
+
+ @Override
+ public void cleanup() {
+ // nothing to clean up
+ }
+
+ @Override
+ public void cancel() {
+ // cannot cancel
+ }
+
+ @NonNull
+ @Override
+ public Class<InputStream> getDataClass() {
+ return InputStream.class;
+ }
+
+ @NonNull
+ @Override
+ public DataSource getDataSource() {
+ return DataSource.LOCAL;
+ }
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
index f0c61403f..b0321bff6 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
@@ -45,11 +45,6 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
= "de.danoeh.antennapod.preferences.currentlyPlayingMedia";
/**
- * True if last played media was streamed.
- */
- private static final String PREF_CURRENT_EPISODE_IS_STREAM = "de.danoeh.antennapod.preferences.lastIsStream";
-
- /**
* True if last played media was a video.
*/
private static final String PREF_CURRENT_EPISODE_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo";
@@ -113,10 +108,6 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
return prefs.getLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING);
}
- public static boolean getCurrentEpisodeIsStream() {
- return prefs.getBoolean(PREF_CURRENT_EPISODE_IS_STREAM, true);
- }
-
public static boolean getCurrentEpisodeIsVideo() {
return prefs.getBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, false);
}
@@ -138,7 +129,7 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
editor.apply();
}
- public static void writeMediaPlaying(Playable playable, PlayerStatus playerStatus, boolean stream) {
+ public static void writeMediaPlaying(Playable playable, PlayerStatus playerStatus) {
Log.d(TAG, "Writing playback preferences");
SharedPreferences.Editor editor = prefs.edit();
@@ -146,7 +137,6 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
writeNoMediaPlaying();
} else {
editor.putLong(PREF_CURRENTLY_PLAYING_MEDIA_TYPE, playable.getPlayableType());
- editor.putBoolean(PREF_CURRENT_EPISODE_IS_STREAM, stream);
editor.putBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, playable.getMediaType() == MediaType.VIDEO);
if (playable instanceof FeedMedia) {
FeedMedia feedMedia = (FeedMedia) playable;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java
index 21d3452d6..7e3b07880 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.core.service.download.handler;
+import android.text.TextUtils;
import android.util.Log;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedItem;
@@ -48,6 +49,9 @@ public class FeedParserTask implements Callable<FeedHandlerResult> {
result = feedHandler.parseFeed(feed);
Log.d(TAG, feed.getTitle() + " parsed");
checkFeedData(feed);
+ if (TextUtils.isEmpty(feed.getImageUrl())) {
+ feed.setImageUrl(Feed.PREFIX_GENERATIVE_COVER + feed.getDownload_url());
+ }
} catch (SAXException | IOException | ParserConfigurationException e) {
successful = false;
e.printStackTrace();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
index db6088d8d..1ef06c511 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
@@ -868,7 +868,6 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
pausedBecauseOfTransientAudiofocusLoss = false;
new PlaybackServiceStarter(context, getPlayable())
.startWhenPrepared(true)
- .streamIfLastWasStream()
.callEvenIfRunning(false)
.start();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index 76fdc1040..c6cff1bd3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -108,7 +108,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
private static final String TAG = "PlaybackService";
public static final String EXTRA_PLAYABLE = "PlaybackService.PlayableExtra";
- public static final String EXTRA_SHOULD_STREAM = "extra.de.danoeh.antennapod.core.service.shouldStream";
public static final String EXTRA_ALLOW_STREAM_THIS_TIME = "extra.de.danoeh.antennapod.core.service.allowStream";
public static final String EXTRA_ALLOW_STREAM_ALWAYS = "extra.de.danoeh.antennapod.core.service.allowStreamAlways";
public static final String EXTRA_START_WHEN_PREPARED = "extra.de.danoeh.antennapod.core.service.startWhenPrepared";
@@ -522,7 +521,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
} else {
stateManager.validStartCommandWasReceived();
- boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM, true);
boolean allowStreamThisTime = intent.getBooleanExtra(EXTRA_ALLOW_STREAM_THIS_TIME, false);
boolean allowStreamAlways = intent.getBooleanExtra(EXTRA_ALLOW_STREAM_ALWAYS, false);
boolean startWhenPrepared = intent.getBooleanExtra(EXTRA_START_WHEN_PREPARED, false);
@@ -531,14 +529,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
if (allowStreamAlways) {
UserPreferences.setAllowMobileStreaming(true);
}
- boolean localFeed = URLUtil.isContentUrl(playable.getStreamUrl());
- if (stream && !NetworkUtils.isStreamingAllowed() && !allowStreamThisTime && !localFeed) {
- displayStreamingNotAllowedNotification(intent);
- PlaybackPreferences.writeNoMediaPlaying();
- stateManager.stopService();
- return Service.START_NOT_STICKY;
- }
-
Observable.fromCallable(
() -> {
if (playable instanceof FeedMedia) {
@@ -550,15 +540,9 @@ public class PlaybackService extends MediaBrowserServiceCompat {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
- playableLoaded -> {
- if (!playable.getIdentifier().equals(
- PlaybackPreferences.getCurrentlyPlayingFeedMediaId())) {
- PlaybackPreferences.clearCurrentlyPlayingTemporaryPlaybackSpeed();
- }
- mediaPlayer.playMediaObject(playableLoaded, stream, startWhenPrepared,
- prepareImmediately);
- addPlayableToQueue(playableLoaded);
- }, error -> {
+ loadedPlayable -> startPlaying(loadedPlayable, allowStreamThisTime,
+ startWhenPrepared, prepareImmediately),
+ error -> {
Log.d(TAG, "Playable was not found. Stopping service.");
error.printStackTrace();
stateManager.stopService();
@@ -741,32 +725,39 @@ public class PlaybackService extends MediaBrowserServiceCompat {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
- playable -> {
- boolean localFeed = URLUtil.isContentUrl(playable.getStreamUrl());
- if (PlaybackPreferences.getCurrentEpisodeIsStream()
- && !NetworkUtils.isStreamingAllowed() && !localFeed) {
- displayStreamingNotAllowedNotification(
- new PlaybackServiceStarter(this, playable)
- .prepareImmediately(true)
- .startWhenPrepared(true)
- .shouldStream(true)
- .getIntent());
- PlaybackPreferences.writeNoMediaPlaying();
- stateManager.stopService();
- return;
- }
- mediaPlayer.playMediaObject(playable, PlaybackPreferences.getCurrentEpisodeIsStream(),
- true, true);
- stateManager.validStartCommandWasReceived();
- updateNotificationAndMediaSession(playable);
- addPlayableToQueue(playable);
- }, error -> {
+ playable -> startPlaying(playable, false, true, true),
+ error -> {
Log.d(TAG, "Playable was not loaded from preferences. Stopping service.");
error.printStackTrace();
stateManager.stopService();
});
}
+ private void startPlaying(Playable playable, boolean allowStreamThisTime,
+ boolean startWhenPrepared, boolean prepareImmediately) {
+ boolean localFeed = URLUtil.isContentUrl(playable.getStreamUrl());
+ boolean stream = !playable.localFileAvailable() || localFeed;
+ if (stream && !localFeed && !NetworkUtils.isStreamingAllowed() && !allowStreamThisTime) {
+ displayStreamingNotAllowedNotification(
+ new PlaybackServiceStarter(this, playable)
+ .prepareImmediately(true)
+ .startWhenPrepared(true)
+ .getIntent());
+ PlaybackPreferences.writeNoMediaPlaying();
+ stateManager.stopService();
+ return;
+ }
+
+ if (!playable.getIdentifier().equals(PlaybackPreferences.getCurrentlyPlayingFeedMediaId())) {
+ PlaybackPreferences.clearCurrentlyPlayingTemporaryPlaybackSpeed();
+ }
+
+ mediaPlayer.playMediaObject(playable, stream, startWhenPrepared, prepareImmediately);
+ stateManager.validStartCommandWasReceived();
+ updateNotificationAndMediaSession(playable);
+ addPlayableToQueue(playable);
+ }
+
/**
* Called by a mediaplayer Activity as soon as it has prepared its
* mediaplayer.
@@ -792,7 +783,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
@Override
public WidgetUpdater.WidgetState requestWidgetState() {
return new WidgetUpdater.WidgetState(getPlayable(), getStatus(),
- getCurrentPosition(), getDuration(), getCurrentPlaybackSpeed(), isCasting());
+ getCurrentPosition(), getDuration(), getCurrentPlaybackSpeed());
}
@Override
@@ -814,7 +805,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
switch (newInfo.playerStatus) {
case INITIALIZED:
PlaybackPreferences.writeMediaPlaying(mediaPlayer.getPSMPInfo().playable,
- mediaPlayer.getPSMPInfo().playerStatus, mediaPlayer.isStreaming());
+ mediaPlayer.getPSMPInfo().playerStatus);
updateNotificationAndMediaSession(newInfo.playable);
break;
case PREPARED:
@@ -1005,7 +996,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
if (!UserPreferences.isFollowQueue()) {
Log.d(TAG, "getNextInQueue(), but follow queue is not enabled.");
- PlaybackPreferences.writeMediaPlaying(nextItem.getMedia(), PlayerStatus.STOPPED, false);
+ PlaybackPreferences.writeMediaPlaying(nextItem.getMedia(), PlayerStatus.STOPPED);
updateNotificationAndMediaSession(nextItem.getMedia());
return null;
}
@@ -1016,7 +1007,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
new PlaybackServiceStarter(this, nextItem.getMedia())
.prepareImmediately(true)
.startWhenPrepared(true)
- .shouldStream(true)
.getIntent());
PlaybackPreferences.writeNoMediaPlaying();
stateManager.stopService();
@@ -1805,8 +1795,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
Log.d(TAG, "onPlayFromMediaId: mediaId: " + mediaId + " extras: " + extras.toString());
FeedMedia p = DBReader.getFeedMedia(Long.parseLong(mediaId));
if (p != null) {
- mediaPlayer.playMediaObject(p, !p.localFileAvailable(), true, true);
- addPlayableToQueue(p);
+ startPlaying(p, false, true, true);
}
}
@@ -1817,8 +1806,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
List<FeedItem> results = FeedSearcher.searchFeedItems(getBaseContext(), query, 0);
if (results.size() > 0 && results.get(0).getMedia() != null) {
FeedMedia media = results.get(0).getMedia();
- mediaPlayer.playMediaObject(media, !media.localFileAvailable(), true, true);
- addPlayableToQueue(media);
+ startPlaying(media, false, true, true);
return;
}
onPlay();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
index 549171c76..687a0d80a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
@@ -331,7 +331,6 @@ public abstract class PlaybackController {
if (playbackService == null) {
new PlaybackServiceStarter(activity, media)
.startWhenPrepared(true)
- .streamIfLastWasStream()
.start();
Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!");
return;
@@ -354,7 +353,6 @@ public abstract class PlaybackController {
default:
new PlaybackServiceStarter(activity, media)
.startWhenPrepared(true)
- .streamIfLastWasStream()
.callEvenIfRunning(true)
.start();
Log.w(TAG, "Play/Pause button was pressed and PlaybackService state was unknown");
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java
index 3efded9ed..7cf6b9adb 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java
@@ -5,7 +5,6 @@ import android.content.Intent;
import android.os.Parcelable;
import androidx.core.content.ContextCompat;
-import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.model.playback.Playable;
@@ -13,7 +12,6 @@ public class PlaybackServiceStarter {
private final Context context;
private final Playable media;
private boolean startWhenPrepared = false;
- private boolean shouldStream = false;
private boolean shouldStreamThisTime = false;
private boolean callEvenIfRunning = false;
private boolean prepareImmediately = true;
@@ -26,19 +24,6 @@ public class PlaybackServiceStarter {
/**
* Default value: false
*/
- public PlaybackServiceStarter shouldStream(boolean shouldStream) {
- this.shouldStream = shouldStream;
- return this;
- }
-
- public PlaybackServiceStarter streamIfLastWasStream() {
- boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream();
- return shouldStream(lastIsStream);
- }
-
- /**
- * Default value: false
- */
public PlaybackServiceStarter startWhenPrepared(boolean startWhenPrepared) {
this.startWhenPrepared = startWhenPrepared;
return this;
@@ -69,7 +54,6 @@ public class PlaybackServiceStarter {
Intent launchIntent = new Intent(context, PlaybackService.class);
launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, (Parcelable) media);
launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, startWhenPrepared);
- launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, shouldStream);
launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, prepareImmediately);
launchIntent.putExtra(PlaybackService.EXTRA_ALLOW_STREAM_THIS_TIME, shouldStreamThisTime);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/widget/WidgetUpdater.java b/core/src/main/java/de/danoeh/antennapod/core/widget/WidgetUpdater.java
index 2762fb9fe..1253c747b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/widget/WidgetUpdater.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/widget/WidgetUpdater.java
@@ -45,20 +45,17 @@ public abstract class WidgetUpdater {
final int position;
final int duration;
final float playbackSpeed;
- final boolean isCasting;
- public WidgetState(Playable media, PlayerStatus status, int position, int duration,
- float playbackSpeed, boolean isCasting) {
+ public WidgetState(Playable media, PlayerStatus status, int position, int duration, float playbackSpeed) {
this.media = media;
this.status = status;
this.position = position;
this.duration = duration;
this.playbackSpeed = playbackSpeed;
- this.isCasting = isCasting;
}
public WidgetState(PlayerStatus status) {
- this(null, status, Playable.INVALID_TIME, Playable.INVALID_TIME, 1.0f, false);
+ this(null, status, Playable.INVALID_TIME, Playable.INVALID_TIME, 1.0f);
}
}
@@ -71,8 +68,7 @@ public abstract class WidgetUpdater {
}
PendingIntent startMediaPlayer;
- if (widgetState.media != null && widgetState.media.getMediaType() == MediaType.VIDEO
- && !widgetState.isCasting) {
+ if (widgetState.media != null && widgetState.media.getMediaType() == MediaType.VIDEO) {
startMediaPlayer = new VideoPlayerActivityStarter(context).getPendingIntent();
} else {
startMediaPlayer = new MainActivityStarter(context).withOpenPlayer().getPendingIntent();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/widget/WidgetUpdaterJobService.java b/core/src/main/java/de/danoeh/antennapod/core/widget/WidgetUpdaterJobService.java
index 325c508c5..598544a0c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/widget/WidgetUpdaterJobService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/widget/WidgetUpdaterJobService.java
@@ -5,7 +5,6 @@ import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.core.app.SafeJobIntentService;
import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
-import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.model.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlayableUtils;
import de.danoeh.antennapod.playback.base.PlayerStatus;
@@ -26,8 +25,7 @@ public class WidgetUpdaterJobService extends SafeJobIntentService {
Playable media = PlayableUtils.createInstanceFromPreferences(getApplicationContext());
if (media != null) {
WidgetUpdater.updateWidget(this, new WidgetUpdater.WidgetState(media, PlayerStatus.STOPPED,
- media.getPosition(), media.getDuration(), PlaybackSpeedUtils.getCurrentPlaybackSpeed(media),
- PlaybackPreferences.getCurrentEpisodeIsStream()));
+ media.getPosition(), media.getDuration(), PlaybackSpeedUtils.getCurrentPlaybackSpeed(media)));
} else {
WidgetUpdater.updateWidget(this, new WidgetUpdater.WidgetState(PlayerStatus.STOPPED));
}
diff --git a/core/src/main/res/raw/local_feed_default_icon.png b/core/src/main/res/raw/local_feed_default_icon.png
deleted file mode 100644
index c1b24a729..000000000
--- a/core/src/main/res/raw/local_feed_default_icon.png
+++ /dev/null
Binary files differ
diff --git a/core/src/test/java/de/danoeh/antennapod/core/feed/LocalFeedUpdaterTest.java b/core/src/test/java/de/danoeh/antennapod/core/feed/LocalFeedUpdaterTest.java
index eb56a1876..37d525670 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/feed/LocalFeedUpdaterTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/feed/LocalFeedUpdaterTest.java
@@ -31,7 +31,6 @@ import java.util.List;
import de.danoeh.antennapod.core.ApplicationCallbacks;
import de.danoeh.antennapod.core.ClientConfig;
-import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
@@ -41,6 +40,7 @@ import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
@@ -158,8 +158,7 @@ public class LocalFeedUpdaterTest {
callUpdateFeed(LOCAL_FEED_DIR1);
Feed feedAfter = verifySingleFeedInDatabase();
- String resourceEntryName = context.getResources().getResourceEntryName(R.raw.local_feed_default_icon);
- assertThat(feedAfter.getImageUrl(), endsWith(resourceEntryName));
+ assertThat(feedAfter.getImageUrl(), startsWith(Feed.PREFIX_GENERATIVE_COVER));
}
/**
@@ -191,17 +190,15 @@ public class LocalFeedUpdaterTest {
@Test
public void testGetImageUrl_EmptyFolder() {
DocumentFile documentFolder = mockDocumentFolder();
- String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
- String defaultImageName = context.getResources().getResourceEntryName(R.raw.local_feed_default_icon);
- assertThat(imageUrl, endsWith(defaultImageName));
+ String imageUrl = LocalFeedUpdater.getImageUrl(documentFolder);
+ assertThat(imageUrl, startsWith(Feed.PREFIX_GENERATIVE_COVER));
}
@Test
public void testGetImageUrl_NoImageButAudioFiles() {
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"));
- String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
- String defaultImageName = context.getResources().getResourceEntryName(R.raw.local_feed_default_icon);
- assertThat(imageUrl, endsWith(defaultImageName));
+ String imageUrl = LocalFeedUpdater.getImageUrl(documentFolder);
+ assertThat(imageUrl, startsWith(Feed.PREFIX_GENERATIVE_COVER));
}
@Test
@@ -209,7 +206,7 @@ public class LocalFeedUpdaterTest {
for (String filename : LocalFeedUpdater.PREFERRED_FEED_IMAGE_FILENAMES) {
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"),
mockDocumentFile(filename, "image/jpeg")); // image MIME type doesn't matter
- String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
+ String imageUrl = LocalFeedUpdater.getImageUrl(documentFolder);
assertThat(imageUrl, endsWith(filename));
}
}
@@ -218,7 +215,7 @@ public class LocalFeedUpdaterTest {
public void testGetImageUrl_OtherImageFilenameJpg() {
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"),
mockDocumentFile("my-image.jpg", "image/jpeg"));
- String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
+ String imageUrl = LocalFeedUpdater.getImageUrl(documentFolder);
assertThat(imageUrl, endsWith("my-image.jpg"));
}
@@ -226,7 +223,7 @@ public class LocalFeedUpdaterTest {
public void testGetImageUrl_OtherImageFilenameJpeg() {
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"),
mockDocumentFile("my-image.jpeg", "image/jpeg"));
- String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
+ String imageUrl = LocalFeedUpdater.getImageUrl(documentFolder);
assertThat(imageUrl, endsWith("my-image.jpeg"));
}
@@ -234,7 +231,7 @@ public class LocalFeedUpdaterTest {
public void testGetImageUrl_OtherImageFilenamePng() {
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"),
mockDocumentFile("my-image.png", "image/png"));
- String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
+ String imageUrl = LocalFeedUpdater.getImageUrl(documentFolder);
assertThat(imageUrl, endsWith("my-image.png"));
}
@@ -242,9 +239,8 @@ public class LocalFeedUpdaterTest {
public void testGetImageUrl_OtherImageFilenameUnsupportedMimeType() {
DocumentFile documentFolder = mockDocumentFolder(mockDocumentFile("audio.mp3", "audio/mp3"),
mockDocumentFile("my-image.svg", "image/svg+xml"));
- String imageUrl = LocalFeedUpdater.getImageUrl(context, documentFolder);
- String defaultImageName = context.getResources().getResourceEntryName(R.raw.local_feed_default_icon);
- assertThat(imageUrl, endsWith(defaultImageName));
+ String imageUrl = LocalFeedUpdater.getImageUrl(documentFolder);
+ assertThat(imageUrl, startsWith(Feed.PREFIX_GENERATIVE_COVER));
}
/**
diff --git a/event/build.gradle b/event/build.gradle
index c852c0351..033fc5a3c 100644
--- a/event/build.gradle
+++ b/event/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../common.gradle"
dependencies {
diff --git a/model/build.gradle b/model/build.gradle
index 6f956a2d5..751a52ef6 100644
--- a/model/build.gradle
+++ b/model/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../common.gradle"
dependencies {
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java b/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java
index e570f9bce..006505eb1 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/Feed.java
@@ -19,6 +19,7 @@ public class Feed extends FeedFile {
public static final String TYPE_RSS2 = "rss";
public static final String TYPE_ATOM1 = "atom";
public static final String PREFIX_LOCAL_FOLDER = "antennapod_local:";
+ public static final String PREFIX_GENERATIVE_COVER = "antennapod_generative_cover:";
/**
* title as defined by the feed.
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<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) {
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/net/ssl/build.gradle b/net/ssl/build.gradle
index 2a47968d3..f76823e2a 100644
--- a/net/ssl/build.gradle
+++ b/net/ssl/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../../common.gradle"
apply from: "../../playFlavor.gradle"
diff --git a/net/sync/gpoddernet/build.gradle b/net/sync/gpoddernet/build.gradle
index 13674b5c3..7a765e828 100644
--- a/net/sync/gpoddernet/build.gradle
+++ b/net/sync/gpoddernet/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../../../common.gradle"
dependencies {
diff --git a/net/sync/model/build.gradle b/net/sync/model/build.gradle
index 72d962536..205a00fb0 100644
--- a/net/sync/model/build.gradle
+++ b/net/sync/model/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../../../common.gradle"
dependencies {
diff --git a/parser/feed/build.gradle b/parser/feed/build.gradle
index 774e08a66..56b4ff740 100644
--- a/parser/feed/build.gradle
+++ b/parser/feed/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../../common.gradle"
android {
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 420bc0000..b19500895 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..99faaa133
--- /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<String> AUDIO_FILE_EXTENSIONS = new HashSet<>(Arrays.asList(
+ "3gp", "aac", "amr", "flac", "imy", "m4a", "m4b", "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;
+ }
+}
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);
- }
-}
diff --git a/parser/media/build.gradle b/parser/media/build.gradle
index e463040b9..7dce7b86a 100644
--- a/parser/media/build.gradle
+++ b/parser/media/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../../common.gradle"
dependencies {
diff --git a/playback/base/build.gradle b/playback/base/build.gradle
index a1d344492..df49b2fb6 100644
--- a/playback/base/build.gradle
+++ b/playback/base/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../../common.gradle"
dependencies {
diff --git a/playback/cast/build.gradle b/playback/cast/build.gradle
index c51354838..64c16eb26 100644
--- a/playback/cast/build.gradle
+++ b/playback/cast/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../../common.gradle"
apply from: "../../playFlavor.gradle"
diff --git a/ui/app-start-intent/build.gradle b/ui/app-start-intent/build.gradle
index 2f6d821b1..1f5161392 100644
--- a/ui/app-start-intent/build.gradle
+++ b/ui/app-start-intent/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../../common.gradle"
dependencies {
diff --git a/ui/common/build.gradle b/ui/common/build.gradle
index 5390b85d8..bacb9f84c 100644
--- a/ui/common/build.gradle
+++ b/ui/common/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../../common.gradle"
dependencies {
diff --git a/ui/png-icons/build.gradle b/ui/png-icons/build.gradle
index f0d9f7a57..ad0b9d0b0 100644
--- a/ui/png-icons/build.gradle
+++ b/ui/png-icons/build.gradle
@@ -1,4 +1,6 @@
-apply plugin: "com.android.library"
+plugins {
+ id("com.android.library")
+}
apply from: "../../common.gradle"
android {