create RemoteMedia class, add more fields to remote mediametadata
This commit is contained in:
parent
c4b6f366ca
commit
94a16bb9ba
@ -0,0 +1,257 @@
|
||||
package de.danoeh.antennapod.core.cast;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.util.ChapterUtils;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
|
||||
/**
|
||||
* Playable implementation for media on a Cast Device for which a local version of
|
||||
* {@link de.danoeh.antennapod.core.feed.FeedMedia} could not be found.
|
||||
*/
|
||||
public class RemoteMedia implements Playable {
|
||||
|
||||
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 mime_type;
|
||||
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 mime_type, 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.mime_type = mime_type;
|
||||
this.pubDate = pubDate;
|
||||
}
|
||||
|
||||
public void setNotes(String notes) {
|
||||
this.notes = 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() {
|
||||
if (TextUtils.isEmpty(mime_type)) {
|
||||
return MediaType.UNKNOWN;
|
||||
} else {
|
||||
if (mime_type.startsWith("audio")) {
|
||||
return MediaType.AUDIO;
|
||||
} else if (mime_type.startsWith("video")) {
|
||||
return MediaType.VIDEO;
|
||||
} else if (mime_type.equals("application/ogg")) {
|
||||
return MediaType.AUDIO;
|
||||
}
|
||||
}
|
||||
return MediaType.UNKNOWN;
|
||||
}
|
||||
|
||||
@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 onPlaybackCompleted() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayableType() {
|
||||
return PLAYABLE_TYPE_REMOTE_MEDIA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChapters(List<Chapter> chapters) {
|
||||
this.chapters = chapters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getImageUri() {
|
||||
if (imageUrl != null) {
|
||||
return Uri.parse(imageUrl);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@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(mime_type);
|
||||
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(), 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];
|
||||
}
|
||||
};
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.cast.CastDevice;
|
||||
@ -11,6 +12,7 @@ import com.google.android.gms.common.images.WebImage;
|
||||
import java.util.Calendar;
|
||||
|
||||
import de.danoeh.antennapod.core.cast.CastManager;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
@ -23,7 +25,27 @@ import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
public class CastUtils {
|
||||
private static final String TAG = "CastUtils";
|
||||
|
||||
public static final String KEY_MEDIA_ID = "CastUtils.Id";
|
||||
public static final String KEY_MEDIA_ID = "AntennaPod.MediaId";
|
||||
|
||||
public static final String KEY_EPISODE_IDENTIFIER = "AntennaPod.EpisodeId";
|
||||
public static final String KEY_EPISODE_LINK = "AntennaPod.EpisodeLink";
|
||||
public static final String KEY_FEED_URL = "AntennaPod.FeedUrl";
|
||||
public static final String KEY_FEED_WEBSITE = "AntennaPod.FeedWebsite";
|
||||
public static final String KEY_EPISODE_NOTES = "AntennaPod.EpisodeNotes";
|
||||
public static final int EPISODE_NOTES_MAX_LENGTH = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* The field <code>AntennaPod.FormatVersion</code> specifies which version of MediaMetaData
|
||||
* fields we're using. Future implementations should try to be backwards compatible with earlier
|
||||
* versions, and earlier versions should be forward compatible until the version indicated by
|
||||
* <code>MAX_VERSION_FORWARD_COMPATIBILITY</code>. If an update makes the format unreadable for
|
||||
* an earlier version, then its version number should be greater than the
|
||||
* <code>MAX_VERSION_FORWARD_COMPATIBILITY</code> value set on the earlier one, so that it
|
||||
* doesn't try to parse the object.
|
||||
*/
|
||||
public static final String KEY_FORMAT_VERSION = "AntennaPod.FormatVersion";
|
||||
public static final int FORMAT_VERSION_VALUE = 1;
|
||||
public static final int MAX_VERSION_FORWARD_COMPATIBILITY = 9999;
|
||||
|
||||
public static boolean isCastable(Playable media){
|
||||
if (media == null || media instanceof ExternalMedia) {
|
||||
@ -75,17 +97,53 @@ public class CastUtils {
|
||||
metadata.putString(MediaMetadata.KEY_SUBTITLE, subtitle);
|
||||
}
|
||||
FeedImage image = feedItem.getImage();
|
||||
if (image != null && image.getDownload_url() != null &&
|
||||
!image.getDownload_url().isEmpty()) {
|
||||
if (image != null && !TextUtils.isEmpty(image.getDownload_url())) {
|
||||
metadata.addImage(new WebImage(Uri.parse(image.getDownload_url())));
|
||||
}
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(media.getItem().getPubDate());
|
||||
metadata.putDate(MediaMetadata.KEY_RELEASE_DATE, calendar);
|
||||
|
||||
Feed feed = feedItem.getFeed();
|
||||
if (feed != null) {
|
||||
if (!TextUtils.isEmpty(feed.getAuthor())) {
|
||||
metadata.putString(MediaMetadata.KEY_ARTIST, feed.getAuthor());
|
||||
}
|
||||
if (!TextUtils.isEmpty(feed.getDownload_url())) {
|
||||
metadata.putString(KEY_FEED_URL, feed.getDownload_url());
|
||||
}
|
||||
if (!TextUtils.isEmpty(feed.getLink())) {
|
||||
metadata.putString(KEY_FEED_WEBSITE, feed.getLink());
|
||||
}
|
||||
}
|
||||
if (!TextUtils.isEmpty(feedItem.getItemIdentifier())) {
|
||||
metadata.putString(KEY_EPISODE_IDENTIFIER, feedItem.getItemIdentifier());
|
||||
} else {
|
||||
metadata.putString(KEY_EPISODE_IDENTIFIER, media.getStreamUrl());
|
||||
}
|
||||
if (!TextUtils.isEmpty(feedItem.getLink())) {
|
||||
metadata.putString(KEY_EPISODE_LINK, feedItem.getLink());
|
||||
}
|
||||
}
|
||||
//metadata.putString(MediaMetadata.KEY_ARTIST, null);
|
||||
metadata.putString(KEY_MEDIA_ID, media.getIdentifier().toString());
|
||||
String notes = null;
|
||||
try {
|
||||
notes = media.loadShownotes().call();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to load FeedMedia notes", e);
|
||||
}
|
||||
if (notes != null) {
|
||||
if (notes.length() > EPISODE_NOTES_MAX_LENGTH) {
|
||||
notes = notes.substring(0, EPISODE_NOTES_MAX_LENGTH);
|
||||
}
|
||||
metadata.putString(KEY_EPISODE_NOTES, notes);
|
||||
}
|
||||
// This field only identifies the id on the device that has the original version.
|
||||
// Idea is to perhaps, on a first approach, check if the version on the local DB with the
|
||||
// same id matches the remote object, and if not then search for episode and feed identifiers.
|
||||
// This at least should make media recognition for a single device much quicker.
|
||||
metadata.putInt(KEY_MEDIA_ID, ((Long) media.getIdentifier()).intValue());
|
||||
// A way to identify different casting media formats in case we change it in the future and
|
||||
// senders with different versions share a casting device.
|
||||
metadata.putInt(KEY_FORMAT_VERSION, FORMAT_VERSION_VALUE);
|
||||
|
||||
return new MediaInfo.Builder(media.getStreamUrl())
|
||||
.setContentType(media.getMime_type())
|
||||
@ -94,5 +152,7 @@ public class CastUtils {
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//TODO Queue handling perhaps
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import android.util.Log;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.asynctask.ImageResource;
|
||||
import de.danoeh.antennapod.core.cast.RemoteMedia;
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
@ -183,6 +184,9 @@ public interface Playable extends Parcelable,
|
||||
case ExternalMedia.PLAYABLE_TYPE_EXTERNAL_MEDIA:
|
||||
result = createExternalMediaInstance(pref);
|
||||
break;
|
||||
case RemoteMedia.PLAYABLE_TYPE_REMOTE_MEDIA:
|
||||
result = createRemoteMediaInstance(pref);
|
||||
break;
|
||||
}
|
||||
if (result == null) {
|
||||
Log.e(TAG, "Could not restore Playable object from preferences");
|
||||
@ -211,6 +215,12 @@ public interface Playable extends Parcelable,
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Playable createRemoteMediaInstance(SharedPreferences pref) {
|
||||
//TODO there's probably no point in restoring RemoteMedia from preferences, because we
|
||||
//only care about it while it's playing on the cast device.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class PlayableException extends Exception {
|
||||
|
Loading…
x
Reference in New Issue
Block a user