294 lines
8.8 KiB
Java
294 lines
8.8 KiB
Java
package de.danoeh.antennapod.net.sync.serviceinterface;
|
|
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import org.json.JSONException;
|
|
import org.json.JSONObject;
|
|
|
|
import java.text.ParseException;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Date;
|
|
import java.util.Locale;
|
|
import java.util.Objects;
|
|
import java.util.TimeZone;
|
|
|
|
import de.danoeh.antennapod.model.feed.FeedItem;
|
|
|
|
public class EpisodeAction {
|
|
private static final String TAG = "EpisodeAction";
|
|
private static final String PATTERN_ISO_DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss";
|
|
public static final Action NEW = Action.NEW;
|
|
public static final Action DOWNLOAD = Action.DOWNLOAD;
|
|
public static final Action PLAY = Action.PLAY;
|
|
public static final Action DELETE = Action.DELETE;
|
|
|
|
private final String podcast;
|
|
private final String episode;
|
|
private final String guid;
|
|
private final Action action;
|
|
private final Date timestamp;
|
|
private final int started;
|
|
private final int position;
|
|
private final int total;
|
|
|
|
private EpisodeAction(Builder builder) {
|
|
this.podcast = builder.podcast;
|
|
this.episode = builder.episode;
|
|
this.guid = builder.guid;
|
|
this.action = builder.action;
|
|
this.timestamp = builder.timestamp;
|
|
this.started = builder.started;
|
|
this.position = builder.position;
|
|
this.total = builder.total;
|
|
}
|
|
|
|
/**
|
|
* Create an episode action object from JSON representation. Mandatory fields are "podcast",
|
|
* "episode" and "action".
|
|
*
|
|
* @param object JSON representation
|
|
* @return episode action object, or null if mandatory values are missing
|
|
*/
|
|
public static EpisodeAction readFromJsonObject(JSONObject object) {
|
|
String podcast = object.optString("podcast", null);
|
|
String episode = object.optString("episode", null);
|
|
String actionString = object.optString("action", null);
|
|
if (TextUtils.isEmpty(podcast) || TextUtils.isEmpty(episode) || TextUtils.isEmpty(actionString)) {
|
|
return null;
|
|
}
|
|
EpisodeAction.Action action;
|
|
try {
|
|
action = EpisodeAction.Action.valueOf(actionString.toUpperCase(Locale.US));
|
|
} catch (IllegalArgumentException e) {
|
|
return null;
|
|
}
|
|
EpisodeAction.Builder builder = new EpisodeAction.Builder(podcast, episode, action);
|
|
String utcTimestamp = object.optString("timestamp", null);
|
|
if (!TextUtils.isEmpty(utcTimestamp)) {
|
|
try {
|
|
SimpleDateFormat parser = new SimpleDateFormat(PATTERN_ISO_DATEFORMAT, Locale.US);
|
|
parser.setTimeZone(TimeZone.getTimeZone("UTC"));
|
|
builder.timestamp(parser.parse(utcTimestamp));
|
|
} catch (ParseException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
String guid = object.optString("guid", null);
|
|
if (!TextUtils.isEmpty(guid)) {
|
|
builder.guid(guid);
|
|
}
|
|
if (action == EpisodeAction.Action.PLAY) {
|
|
int started = object.optInt("started", -1);
|
|
int position = object.optInt("position", -1);
|
|
int total = object.optInt("total", -1);
|
|
if (started >= 0 && position > 0 && total > 0) {
|
|
builder
|
|
.started(started)
|
|
.position(position)
|
|
.total(total);
|
|
}
|
|
}
|
|
return builder.build();
|
|
}
|
|
|
|
public String getPodcast() {
|
|
return this.podcast;
|
|
}
|
|
|
|
public String getEpisode() {
|
|
return this.episode;
|
|
}
|
|
|
|
public String getGuid() {
|
|
return this.guid;
|
|
}
|
|
|
|
public Action getAction() {
|
|
return this.action;
|
|
}
|
|
|
|
private String getActionString() {
|
|
return this.action.name().toLowerCase(Locale.US);
|
|
}
|
|
|
|
public Date getTimestamp() {
|
|
return this.timestamp;
|
|
}
|
|
|
|
/**
|
|
* Returns the position (in seconds) at which the client started playback.
|
|
*
|
|
* @return start position (in seconds)
|
|
*/
|
|
public int getStarted() {
|
|
return this.started;
|
|
}
|
|
|
|
/**
|
|
* Returns the position (in seconds) at which the client stopped playback.
|
|
*
|
|
* @return stop position (in seconds)
|
|
*/
|
|
public int getPosition() {
|
|
return this.position;
|
|
}
|
|
|
|
/**
|
|
* Returns the total length of the file in seconds.
|
|
*
|
|
* @return total length in seconds
|
|
*/
|
|
public int getTotal() {
|
|
return this.total;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object o) {
|
|
if (this == o) {
|
|
return true;
|
|
}
|
|
if (!(o instanceof EpisodeAction)) {
|
|
return false;
|
|
}
|
|
|
|
EpisodeAction that = (EpisodeAction) o;
|
|
return started == that.started
|
|
&& position == that.position
|
|
&& total == that.total
|
|
&& action != that.action
|
|
&& Objects.equals(podcast, that.podcast)
|
|
&& Objects.equals(episode, that.episode)
|
|
&& Objects.equals(timestamp, that.timestamp)
|
|
&& Objects.equals(guid, that.guid);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
int result = podcast != null ? podcast.hashCode() : 0;
|
|
result = 31 * result + (episode != null ? episode.hashCode() : 0);
|
|
result = 31 * result + (guid != null ? guid.hashCode() : 0);
|
|
result = 31 * result + (action != null ? action.hashCode() : 0);
|
|
result = 31 * result + (timestamp != null ? timestamp.hashCode() : 0);
|
|
result = 31 * result + started;
|
|
result = 31 * result + position;
|
|
result = 31 * result + total;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns a JSON object representation of this object.
|
|
*
|
|
* @return JSON object representation, or null if the object is invalid
|
|
*/
|
|
public JSONObject writeToJsonObject() {
|
|
JSONObject obj = new JSONObject();
|
|
try {
|
|
obj.putOpt("podcast", this.podcast);
|
|
obj.putOpt("episode", this.episode);
|
|
obj.putOpt("guid", this.guid);
|
|
obj.put("action", this.getActionString());
|
|
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
|
|
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
|
|
obj.put("timestamp", formatter.format(this.timestamp));
|
|
if (this.getAction() == Action.PLAY) {
|
|
obj.put("started", this.started);
|
|
obj.put("position", this.position);
|
|
obj.put("total", this.total);
|
|
}
|
|
} catch (JSONException e) {
|
|
Log.e(TAG, "writeToJSONObject(): " + e.getMessage());
|
|
return null;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public String toString() {
|
|
return "EpisodeAction{"
|
|
+ "podcast='" + podcast + '\''
|
|
+ ", episode='" + episode + '\''
|
|
+ ", guid='" + guid + '\''
|
|
+ ", action=" + action
|
|
+ ", timestamp=" + timestamp
|
|
+ ", started=" + started
|
|
+ ", position=" + position
|
|
+ ", total=" + total
|
|
+ '}';
|
|
}
|
|
|
|
public enum Action {
|
|
NEW, DOWNLOAD, PLAY, DELETE
|
|
}
|
|
|
|
public static class Builder {
|
|
|
|
// mandatory
|
|
private final String podcast;
|
|
private final String episode;
|
|
private final Action action;
|
|
|
|
// optional
|
|
private Date timestamp;
|
|
private int started = -1;
|
|
private int position = -1;
|
|
private int total = -1;
|
|
private String guid;
|
|
|
|
public Builder(FeedItem item, Action action) {
|
|
this(item.getFeed().getDownloadUrl(), item.getMedia().getDownloadUrl(), action);
|
|
this.guid(item.getItemIdentifier());
|
|
}
|
|
|
|
public Builder(String podcast, String episode, Action action) {
|
|
this.podcast = podcast;
|
|
this.episode = episode;
|
|
this.action = action;
|
|
}
|
|
|
|
public Builder timestamp(Date timestamp) {
|
|
this.timestamp = timestamp;
|
|
return this;
|
|
}
|
|
|
|
public Builder guid(String guid) {
|
|
this.guid = guid;
|
|
return this;
|
|
}
|
|
|
|
public Builder currentTimestamp() {
|
|
return timestamp(new Date());
|
|
}
|
|
|
|
public Builder started(int seconds) {
|
|
if (action == Action.PLAY) {
|
|
this.started = seconds;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public Builder position(int seconds) {
|
|
if (action == Action.PLAY) {
|
|
this.position = seconds;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public Builder total(int seconds) {
|
|
if (action == Action.PLAY) {
|
|
this.total = seconds;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public EpisodeAction build() {
|
|
return new EpisodeAction(this);
|
|
}
|
|
|
|
}
|
|
|
|
}
|