summaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java94
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/RemoteMedia.java342
-rw-r--r--core/src/main/res/values/strings.xml2
4 files changed, 370 insertions, 74 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
index 89ecf271b..4b14a72d2 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
@@ -30,12 +30,16 @@ public class FeedItemEvent {
return new FeedItemEvent(Action.DELETE_MEDIA, items);
}
+ public static FeedItemEvent deletedMedia(FeedItem... items) {
+ return deletedMedia(Arrays.asList(items));
+ }
+
public static FeedItemEvent updated(List<FeedItem> items) {
return new FeedItemEvent(Action.UPDATE, items);
}
public static FeedItemEvent updated(FeedItem... items) {
- return new FeedItemEvent(Action.UPDATE, Arrays.asList(items));
+ return updated(Arrays.asList(items));
}
@Override
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
index 8ebe18dc0..5b7e62964 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
@@ -6,9 +6,22 @@ import android.database.Cursor;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
-
import androidx.annotation.VisibleForTesting;
-
+import de.danoeh.antennapod.core.ClientConfig;
+import de.danoeh.antennapod.core.R;
+import de.danoeh.antennapod.core.event.FeedItemEvent;
+import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.core.event.MessageEvent;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.feed.FeedPreferences;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.GpodnetSyncService;
+import de.danoeh.antennapod.core.service.download.DownloadStatus;
+import de.danoeh.antennapod.core.util.DownloadError;
+import de.danoeh.antennapod.core.util.LongList;
+import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
import org.greenrobot.eventbus.EventBus;
import java.util.ArrayList;
@@ -24,23 +37,6 @@ import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicBoolean;
-import de.danoeh.antennapod.core.ClientConfig;
-import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.feed.FeedPreferences;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.GpodnetSyncService;
-import de.danoeh.antennapod.core.service.download.DownloadStatus;
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.util.DownloadError;
-import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.LongList;
-import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
-import de.danoeh.antennapod.core.util.exception.MediaFileNotFoundException;
-import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
-
import static android.content.Context.MODE_PRIVATE;
/**
@@ -100,53 +96,6 @@ public final class DBTasks {
}
}
- /**
- * Starts playback of a FeedMedia object's file. This method will build an Intent based on the given parameters to
- * start the {@link PlaybackService}.
- *
- * @param context Used for sending starting Services and Activities.
- * @param media The FeedMedia object.
- * @param showPlayer If true, starts the appropriate player activity ({@link de.danoeh.antennapod.activity.AudioplayerActivity}
- * or {@link de.danoeh.antennapod.activity.VideoplayerActivity}
- * @param startWhenPrepared Parameter for the {@link PlaybackService} start intent. If true, playback will start as
- * soon as the PlaybackService has finished loading the FeedMedia object's file.
- * @param shouldStream Parameter for the {@link PlaybackService} start intent. If true, the FeedMedia object's file
- * will be streamed, otherwise the downloaded file will be used. If the downloaded file cannot be
- * found, the PlaybackService will shutdown and the database entry of the FeedMedia object will be
- * corrected.
- */
- public static void playMedia(final Context context, final FeedMedia media,
- boolean showPlayer, boolean startWhenPrepared, boolean shouldStream) {
- try {
- if (!shouldStream) {
- if (!media.fileExists()) {
- throw new MediaFileNotFoundException(
- "No episode was found at " + media.getFile_url(),
- media);
- }
- }
-
- new PlaybackServiceStarter(context, media)
- .callEvenIfRunning(true)
- .startWhenPrepared(startWhenPrepared)
- .shouldStream(shouldStream)
- .start();
-
- if (showPlayer) {
- // Launch media player
- context.startActivity(PlaybackService.getPlayerActivityIntent(
- context, media));
- }
- DBWriter.addQueueItemAt(context, media.getItem().getId(), 0, false);
- } catch (MediaFileNotFoundException e) {
- e.printStackTrace();
- if (media.isPlaying()) {
- IntentUtils.sendLocalBroadcast(context, PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE);
- }
- notifyMissingFeedMediaFile(context, media);
- }
- }
-
private static final AtomicBoolean isRefreshing = new AtomicBoolean(false);
/**
@@ -293,17 +242,16 @@ public final class DBTasks {
}
/**
- * Notifies the database about a missing FeedMedia file. This method will correct the FeedMedia object's values in the
- * DB and send a FeedUpdateBroadcast.
+ * Notifies the database about a missing FeedMedia file. This method will correct the FeedMedia object's
+ * values in the DB and send a FeedItemEvent.
*/
- public static void notifyMissingFeedMediaFile(final Context context,
- final FeedMedia media) {
- Log.i(TAG,
- "The feedmanager was notified about a missing episode. It will update its database now.");
+ public static void notifyMissingFeedMediaFile(final Context context, final FeedMedia media) {
+ Log.i(TAG, "The feedmanager was notified about a missing episode. It will update its database now.");
media.setDownloaded(false);
media.setFile_url(null);
DBWriter.setFeedMedia(media);
- EventBus.getDefault().post(new FeedListUpdateEvent(media.getItem().getFeed()));
+ EventBus.getDefault().post(FeedItemEvent.deletedMedia(media.getItem()));
+ EventBus.getDefault().post(new MessageEvent(context.getString(R.string.error_file_not_found)));
}
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/RemoteMedia.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/RemoteMedia.java
new file mode 100644
index 000000000..c39121564
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/RemoteMedia.java
@@ -0,0 +1,342 @@
+package de.danoeh.antennapod.core.util.playback;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import androidx.annotation.Nullable;
+import de.danoeh.antennapod.core.feed.Chapter;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.feed.MediaType;
+import de.danoeh.antennapod.core.util.ChapterUtils;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Callable;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+/**
+ * Playable implementation for media for which a local version of
+ * {@link de.danoeh.antennapod.core.feed.FeedMedia} hasn't been found.
+ * Used for Casting and for previewing unsubscribed feeds.
+ */
+public class RemoteMedia implements Playable {
+ public static final String TAG = "RemoteMedia";
+
+ public static final int PLAYABLE_TYPE_REMOTE_MEDIA = 3;
+
+ private String downloadUrl;
+ private String itemIdentifier;
+ private String feedUrl;
+ private String feedTitle;
+ private String episodeTitle;
+ private String episodeLink;
+ private String feedAuthor;
+ private String imageUrl;
+ private String feedLink;
+ private String mimeType;
+ private Date pubDate;
+ private String notes;
+ private List<Chapter> chapters;
+ private int duration;
+ private int position;
+ private long lastPlayedTime;
+
+ public RemoteMedia(String downloadUrl, String itemId, String feedUrl, String feedTitle,
+ String episodeTitle, String episodeLink, String feedAuthor,
+ String imageUrl, String feedLink, String mimeType, Date pubDate) {
+ this.downloadUrl = downloadUrl;
+ this.itemIdentifier = itemId;
+ this.feedUrl = feedUrl;
+ this.feedTitle = feedTitle;
+ this.episodeTitle = episodeTitle;
+ this.episodeLink = episodeLink;
+ this.feedAuthor = feedAuthor;
+ this.imageUrl = imageUrl;
+ this.feedLink = feedLink;
+ this.mimeType = mimeType;
+ this.pubDate = pubDate;
+ }
+
+ public RemoteMedia(FeedItem item) {
+ this.downloadUrl = item.getMedia().getDownload_url();
+ this.itemIdentifier = item.getItemIdentifier();
+ this.feedUrl = item.getFeed().getDownload_url();
+ this.feedTitle = item.getFeed().getTitle();
+ this.episodeTitle = item.getTitle();
+ this.episodeLink = item.getLink();
+ this.feedAuthor = item.getFeed().getAuthor();
+ this.imageUrl = item.getImageUrl();
+ this.feedLink = item.getFeed().getLink();
+ this.mimeType = item.getMedia().getMime_type();
+ this.pubDate = item.getPubDate();
+ }
+
+ public void setNotes(String notes) {
+ this.notes = notes;
+ }
+
+ public String getEpisodeIdentifier() {
+ return itemIdentifier;
+ }
+
+ public String getFeedUrl() {
+ return feedUrl;
+ }
+
+ public String getDownloadUrl() {
+ return downloadUrl;
+ }
+
+ public String getEpisodeLink() {
+ return episodeLink;
+ }
+
+ public String getFeedAuthor() {
+ return feedAuthor;
+ }
+
+ public String getImageUrl() {
+ return imageUrl;
+ }
+
+ public String getFeedLink() {
+ return feedLink;
+ }
+
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ public Date getPubDate() {
+ return pubDate;
+ }
+
+ public String getNotes() {
+ return notes;
+ }
+
+ @Override
+ public void writeToPreferences(SharedPreferences.Editor prefEditor) {
+ //it seems pointless to do it, since the session should be kept by the remote device.
+ }
+
+ @Override
+ public void loadMetadata() throws PlayableException {
+ //Already loaded
+ }
+
+ @Override
+ public void loadChapterMarks() {
+ ChapterUtils.loadChaptersFromStreamUrl(this);
+ }
+
+ @Override
+ public String getEpisodeTitle() {
+ return episodeTitle;
+ }
+
+ @Override
+ public List<Chapter> getChapters() {
+ return chapters;
+ }
+
+ @Override
+ public String getWebsiteLink() {
+ if (episodeLink != null) {
+ return episodeLink;
+ } else {
+ return feedUrl;
+ }
+ }
+
+ @Override
+ public String getPaymentLink() {
+ return null;
+ }
+
+ @Override
+ public String getFeedTitle() {
+ return feedTitle;
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return itemIdentifier + "@" + feedUrl;
+ }
+
+ @Override
+ public int getDuration() {
+ return duration;
+ }
+
+ @Override
+ public int getPosition() {
+ return position;
+ }
+
+ @Override
+ public long getLastPlayedTime() {
+ return lastPlayedTime;
+ }
+
+ @Override
+ public MediaType getMediaType() {
+ return MediaType.fromMimeType(mimeType);
+ }
+
+ @Override
+ public String getLocalMediaUrl() {
+ return null;
+ }
+
+ @Override
+ public String getStreamUrl() {
+ return downloadUrl;
+ }
+
+ @Override
+ public boolean localFileAvailable() {
+ return false;
+ }
+
+ @Override
+ public boolean streamAvailable() {
+ return true;
+ }
+
+ @Override
+ public void saveCurrentPosition(SharedPreferences pref, int newPosition, long timestamp) {
+ //we're not saving playback information for this kind of items on preferences
+ setPosition(newPosition);
+ setLastPlayedTime(timestamp);
+ }
+
+ @Override
+ public void setPosition(int newPosition) {
+ position = newPosition;
+ }
+
+ @Override
+ public void setDuration(int newDuration) {
+ duration = newDuration;
+ }
+
+ @Override
+ public void setLastPlayedTime(long lastPlayedTimestamp) {
+ lastPlayedTime = lastPlayedTimestamp;
+ }
+
+ @Override
+ public void onPlaybackStart() {
+ // no-op
+ }
+
+ @Override
+ public void onPlaybackPause(Context context) {
+ // no-op
+ }
+
+ @Override
+ public void onPlaybackCompleted(Context context) {
+ // no-op
+ }
+
+ @Override
+ public int getPlayableType() {
+ return PLAYABLE_TYPE_REMOTE_MEDIA;
+ }
+
+ @Override
+ public void setChapters(List<Chapter> chapters) {
+ this.chapters = chapters;
+ }
+
+ @Override
+ @Nullable
+ public String getImageLocation() {
+ return imageUrl;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public Callable<String> loadShownotes() {
+ return () -> (notes != null) ? notes : "";
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(downloadUrl);
+ dest.writeString(itemIdentifier);
+ dest.writeString(feedUrl);
+ dest.writeString(feedTitle);
+ dest.writeString(episodeTitle);
+ dest.writeString(episodeLink);
+ dest.writeString(feedAuthor);
+ dest.writeString(imageUrl);
+ dest.writeString(feedLink);
+ dest.writeString(mimeType);
+ dest.writeLong(pubDate.getTime());
+ dest.writeString(notes);
+ dest.writeInt(duration);
+ dest.writeInt(position);
+ dest.writeLong(lastPlayedTime);
+ }
+
+ public static final Parcelable.Creator<RemoteMedia> CREATOR = new Parcelable.Creator<RemoteMedia>() {
+ @Override
+ public RemoteMedia createFromParcel(Parcel in) {
+ RemoteMedia result = new RemoteMedia(in.readString(), in.readString(), in.readString(),
+ in.readString(), in.readString(), in.readString(), in.readString(), in.readString(),
+ in.readString(), in.readString(), new Date(in.readLong()));
+ result.setNotes(in.readString());
+ result.setDuration(in.readInt());
+ result.setPosition(in.readInt());
+ result.setLastPlayedTime(in.readLong());
+ return result;
+ }
+
+ @Override
+ public RemoteMedia[] newArray(int size) {
+ return new RemoteMedia[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof RemoteMedia) {
+ RemoteMedia rm = (RemoteMedia) other;
+ return TextUtils.equals(downloadUrl, rm.downloadUrl)
+ && TextUtils.equals(feedUrl, rm.feedUrl)
+ && TextUtils.equals(itemIdentifier, rm.itemIdentifier);
+ }
+ if (other instanceof FeedMedia) {
+ FeedMedia fm = (FeedMedia) other;
+ if (!TextUtils.equals(downloadUrl, fm.getStreamUrl())) {
+ return false;
+ }
+ FeedItem fi = fm.getItem();
+ if (fi == null || !TextUtils.equals(itemIdentifier, fi.getItemIdentifier())) {
+ return false;
+ }
+ Feed feed = fi.getFeed();
+ return feed != null && TextUtils.equals(feedUrl, feed.getDownload_url());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder()
+ .append(downloadUrl)
+ .append(feedUrl)
+ .append(itemIdentifier)
+ .toHashCode();
+ }
+}
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index bbdcb912e..57d0ca38d 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -289,6 +289,7 @@
<string name="player_buffering_msg">Buffering</string>
<string name="player_go_to_picture_in_picture">Picture-in-picture mode</string>
<string name="unknown_media_key">AntennaPod - Unknown media key: %1$d</string>
+ <string name="error_file_not_found">File not found</string>
<!-- Queue operations -->
<string name="lock_queue">Lock Queue</string>
@@ -657,6 +658,7 @@
<!-- Online feed view -->
<string name="subscribe_label">Subscribe</string>
<string name="subscribing_label">Subscribing&#8230;</string>
+ <string name="preview_episode">Preview</string>
<!-- Content descriptions for image buttons -->
<string name="rewind_label">Rewind</string>