Sync actions regularly, local subscriptions changes overwrite remote ones
This commit is contained in:
parent
1d25137edd
commit
108daed5a9
|
@ -258,7 +258,7 @@ public class GpodnetEpisodeAction {
|
||||||
private int total = -1;
|
private int total = -1;
|
||||||
|
|
||||||
public Builder(FeedItem item, Action action) {
|
public Builder(FeedItem item, Action action) {
|
||||||
this(item.getFeed().getDownload_url(), item.getItemIdentifier(), action);
|
this(item.getFeed().getDownload_url(), item.getMedia().getDownload_url(), action);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder(String podcast, String episode, Action action) {
|
public Builder(String podcast, String episode, Action action) {
|
||||||
|
|
|
@ -173,7 +173,7 @@ public class GpodnetPreferences {
|
||||||
writePreference(PREF_SYNC_REMOVED, removedFeeds);
|
writePreference(PREF_SYNC_REMOVED, removedFeeds);
|
||||||
}
|
}
|
||||||
feedListLock.unlock();
|
feedListLock.unlock();
|
||||||
GpodnetSyncService.sendSyncIntent(ClientConfig.applicationCallbacks.getApplicationInstance());
|
GpodnetSyncService.sendSyncSubscriptionsIntent(ClientConfig.applicationCallbacks.getApplicationInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addRemovedFeed(String feed) {
|
public static void addRemovedFeed(String feed) {
|
||||||
|
@ -186,7 +186,7 @@ public class GpodnetPreferences {
|
||||||
writePreference(PREF_SYNC_ADDED, addedFeeds);
|
writePreference(PREF_SYNC_ADDED, addedFeeds);
|
||||||
}
|
}
|
||||||
feedListLock.unlock();
|
feedListLock.unlock();
|
||||||
GpodnetSyncService.sendSyncIntent(ClientConfig.applicationCallbacks.getApplicationInstance());
|
GpodnetSyncService.sendSyncSubscriptionsIntent(ClientConfig.applicationCallbacks.getApplicationInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<String> getAddedFeedsCopy() {
|
public static Set<String> getAddedFeedsCopy() {
|
||||||
|
@ -225,6 +225,7 @@ public class GpodnetPreferences {
|
||||||
ensurePreferencesLoaded();
|
ensurePreferencesLoaded();
|
||||||
queuedEpisodeActions.add(action);
|
queuedEpisodeActions.add(action);
|
||||||
writePreference(PREF_SYNC_EPISODE_ACTIONS, writeEpisodeActionsToString(queuedEpisodeActions));
|
writePreference(PREF_SYNC_EPISODE_ACTIONS, writeEpisodeActionsToString(queuedEpisodeActions));
|
||||||
|
GpodnetSyncService.sendSyncActionsIntent(ClientConfig.applicationCallbacks.getApplicationInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GpodnetEpisodeAction> getQueuedEpisodeActions() {
|
public static List<GpodnetEpisodeAction> getQueuedEpisodeActions() {
|
||||||
|
|
|
@ -12,7 +12,6 @@ import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -22,6 +21,7 @@ import de.danoeh.antennapod.core.ClientConfig;
|
||||||
import de.danoeh.antennapod.core.R;
|
import de.danoeh.antennapod.core.R;
|
||||||
import de.danoeh.antennapod.core.feed.Feed;
|
import de.danoeh.antennapod.core.feed.Feed;
|
||||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||||
|
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||||
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
|
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
|
||||||
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceAuthenticationException;
|
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceAuthenticationException;
|
||||||
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
|
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
|
||||||
|
@ -50,17 +50,38 @@ public class GpodnetSyncService extends Service {
|
||||||
public static final String ARG_ACTION = "action";
|
public static final String ARG_ACTION = "action";
|
||||||
|
|
||||||
public static final String ACTION_SYNC = "de.danoeh.antennapod.intent.action.sync";
|
public static final String ACTION_SYNC = "de.danoeh.antennapod.intent.action.sync";
|
||||||
|
public static final String ACTION_SYNC_SUBSCRIPTIONS = "de.danoeh.antennapod.intent.action.sync_subscriptions";
|
||||||
|
public static final String ACTION_SYNC_ACTIONS = "de.danoeh.antennapod.intent.action.sync_ACTIONS";
|
||||||
|
|
||||||
private GpodnetService service;
|
private GpodnetService service;
|
||||||
|
|
||||||
|
private boolean syncSubscriptions = false;
|
||||||
|
private boolean syncActions = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
final String action = (intent != null) ? intent.getStringExtra(ARG_ACTION) : null;
|
final String action = (intent != null) ? intent.getStringExtra(ARG_ACTION) : null;
|
||||||
if (action != null && action.equals(ACTION_SYNC)) {
|
if (action != null) {
|
||||||
|
switch(action) {
|
||||||
|
case ACTION_SYNC:
|
||||||
|
syncSubscriptions = true;
|
||||||
|
syncActions = true;
|
||||||
|
break;
|
||||||
|
case ACTION_SYNC_SUBSCRIPTIONS:
|
||||||
|
syncSubscriptions = true;
|
||||||
|
break;
|
||||||
|
case ACTION_SYNC_ACTIONS:
|
||||||
|
syncActions = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e(TAG, "Received invalid intent: action argument is invalid");
|
||||||
|
}
|
||||||
|
if(syncSubscriptions || syncActions) {
|
||||||
Log.d(TAG, String.format("Waiting %d milliseconds before uploading changes", WAIT_INTERVAL));
|
Log.d(TAG, String.format("Waiting %d milliseconds before uploading changes", WAIT_INTERVAL));
|
||||||
syncWaiterThread.restart();
|
syncWaiterThread.restart();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Received invalid intent: action argument is null or invalid");
|
Log.e(TAG, "Received invalid intent: action argument is null");
|
||||||
}
|
}
|
||||||
return START_FLAG_REDELIVERY;
|
return START_FLAG_REDELIVERY;
|
||||||
}
|
}
|
||||||
|
@ -91,8 +112,14 @@ public class GpodnetSyncService extends Service {
|
||||||
stopSelf();
|
stopSelf();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(syncSubscriptions) {
|
||||||
syncSubscriptionChanges();
|
syncSubscriptionChanges();
|
||||||
|
syncSubscriptions = false;
|
||||||
|
}
|
||||||
|
if(syncActions) {
|
||||||
syncEpisodeActions();
|
syncEpisodeActions();
|
||||||
|
syncActions = false;
|
||||||
|
}
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,37 +127,36 @@ public class GpodnetSyncService extends Service {
|
||||||
final long timestamp = GpodnetPreferences.getLastSubscriptionSyncTimestamp();
|
final long timestamp = GpodnetPreferences.getLastSubscriptionSyncTimestamp();
|
||||||
try {
|
try {
|
||||||
final List<String> localSubscriptions = DBReader.getFeedListDownloadUrls(this);
|
final List<String> localSubscriptions = DBReader.getFeedListDownloadUrls(this);
|
||||||
|
Collection<String> localAdded = GpodnetPreferences.getAddedFeedsCopy();
|
||||||
|
Collection<String> localRemoved = GpodnetPreferences.getRemovedFeedsCopy();
|
||||||
GpodnetService service = tryLogin();
|
GpodnetService service = tryLogin();
|
||||||
|
|
||||||
// first sync: download all subscriptions...
|
// first sync: download all subscriptions...
|
||||||
GpodnetSubscriptionChange subscriptionChanges = service.getSubscriptionChanges(GpodnetPreferences.getUsername(),
|
GpodnetSubscriptionChange subscriptionChanges = service.getSubscriptionChanges(GpodnetPreferences.getUsername(),
|
||||||
GpodnetPreferences.getDeviceID(), timestamp);
|
GpodnetPreferences.getDeviceID(), timestamp);
|
||||||
long lastUpdate = subscriptionChanges.getTimestamp();
|
long newTimeStamp = subscriptionChanges.getTimestamp();
|
||||||
|
|
||||||
Log.d(TAG, "Downloaded subscription changes: " + subscriptionChanges);
|
Log.d(TAG, "Downloaded subscription changes: " + subscriptionChanges);
|
||||||
processSubscriptionChanges(localSubscriptions, subscriptionChanges);
|
processSubscriptionChanges(localSubscriptions, localAdded, localRemoved, subscriptionChanges);
|
||||||
|
|
||||||
Collection<String> added;
|
if(timestamp == 0) {
|
||||||
Collection<String> removed;
|
// this is this apps first sync with gpodder:
|
||||||
if (timestamp == 0) {
|
// only submit changes gpodder has not just sent us
|
||||||
added = localSubscriptions;
|
localAdded = localSubscriptions;
|
||||||
GpodnetPreferences.removeRemovedFeeds(GpodnetPreferences.getRemovedFeedsCopy());
|
localAdded.removeAll(subscriptionChanges.getAdded());
|
||||||
removed = Collections.emptyList();
|
localRemoved.removeAll(subscriptionChanges.getRemoved());
|
||||||
} else {
|
|
||||||
added = GpodnetPreferences.getAddedFeedsCopy();
|
|
||||||
removed = GpodnetPreferences.getRemovedFeedsCopy();
|
|
||||||
}
|
}
|
||||||
if(added.size() > 0 || removed.size() > 0) {
|
if(localAdded.size() > 0 || localRemoved.size() > 0) {
|
||||||
Log.d(TAG, String.format("Uploading subscriptions, Added: %s\nRemoved: %s",
|
Log.d(TAG, String.format("Uploading subscriptions, Added: %s\nRemoved: %s",
|
||||||
added, removed));
|
localAdded, localRemoved));
|
||||||
GpodnetUploadChangesResponse uploadResponse = service.uploadChanges(GpodnetPreferences.getUsername(),
|
GpodnetUploadChangesResponse uploadResponse = service.uploadChanges(GpodnetPreferences.getUsername(),
|
||||||
GpodnetPreferences.getDeviceID(), added, removed);
|
GpodnetPreferences.getDeviceID(), localAdded, localRemoved);
|
||||||
lastUpdate = uploadResponse.timestamp;
|
newTimeStamp = uploadResponse.timestamp;
|
||||||
Log.d(TAG, "Upload changes response: " + uploadResponse);
|
Log.d(TAG, "Upload changes response: " + uploadResponse);
|
||||||
GpodnetPreferences.removeAddedFeeds(added);
|
GpodnetPreferences.removeAddedFeeds(localAdded);
|
||||||
GpodnetPreferences.removeRemovedFeeds(removed);
|
GpodnetPreferences.removeRemovedFeeds(localRemoved);
|
||||||
}
|
}
|
||||||
GpodnetPreferences.setLastSubscriptionSyncTimestamp(lastUpdate);
|
GpodnetPreferences.setLastSubscriptionSyncTimestamp(newTimeStamp);
|
||||||
clearErrorNotifications();
|
clearErrorNotifications();
|
||||||
} catch (GpodnetServiceException e) {
|
} catch (GpodnetServiceException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -140,6 +166,27 @@ public class GpodnetSyncService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void processSubscriptionChanges(List<String> localSubscriptions,
|
||||||
|
Collection<String> localAdded,
|
||||||
|
Collection<String> localRemoved,
|
||||||
|
GpodnetSubscriptionChange changes) throws DownloadRequestException {
|
||||||
|
// local changes are always superior to remote changes!
|
||||||
|
// add subscription if (1) not already subscribed and (2) not just unsubscribed
|
||||||
|
for (String downloadUrl : changes.getAdded()) {
|
||||||
|
if (false == localSubscriptions.contains(downloadUrl) &&
|
||||||
|
false == localRemoved.contains(downloadUrl)) {
|
||||||
|
Feed feed = new Feed(downloadUrl, new Date(0));
|
||||||
|
DownloadRequester.getInstance().downloadFeed(this, feed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove subscription if not just subscribed (again)
|
||||||
|
for (String downloadUrl : changes.getRemoved()) {
|
||||||
|
if(false == localAdded.contains(downloadUrl)) {
|
||||||
|
DBTasks.removeFeedWithDownloadUrl(GpodnetSyncService.this, downloadUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private synchronized void syncEpisodeActions() {
|
private synchronized void syncEpisodeActions() {
|
||||||
final long timestamp = GpodnetPreferences.getLastEpisodeActionsSyncTimestamp();
|
final long timestamp = GpodnetPreferences.getLastEpisodeActionsSyncTimestamp();
|
||||||
Log.d(TAG, "last episode actions sync timestamp: " + timestamp);
|
Log.d(TAG, "last episode actions sync timestamp: " + timestamp);
|
||||||
|
@ -173,25 +220,13 @@ public class GpodnetSyncService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void processSubscriptionChanges(List<String> localSubscriptions, GpodnetSubscriptionChange changes) throws DownloadRequestException {
|
|
||||||
for (String downloadUrl : changes.getAdded()) {
|
|
||||||
if (!localSubscriptions.contains(downloadUrl)) {
|
|
||||||
Feed feed = new Feed(downloadUrl, new Date(0));
|
|
||||||
DownloadRequester.getInstance().downloadFeed(this, feed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (String downloadUrl : changes.getRemoved()) {
|
|
||||||
DBTasks.removeFeedWithDownloadUrl(GpodnetSyncService.this, downloadUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void processEpisodeActions(List<GpodnetEpisodeAction> localActions, List<GpodnetEpisodeAction> remoteActions) throws DownloadRequestException {
|
private synchronized void processEpisodeActions(List<GpodnetEpisodeAction> localActions,
|
||||||
|
List<GpodnetEpisodeAction> remoteActions) throws DownloadRequestException {
|
||||||
if(remoteActions.size() == 0) {
|
if(remoteActions.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Map<Pair<String, String>, GpodnetEpisodeAction> localMostRecentPlayAction = new HashMap<Pair<String, String>, GpodnetEpisodeAction>();
|
Map<Pair<String, String>, GpodnetEpisodeAction> localMostRecentPlayAction = new HashMap<Pair<String, String>, GpodnetEpisodeAction>();
|
||||||
Map<Pair<String, String>, GpodnetEpisodeAction> remoteMostRecentPlayAction = new HashMap<Pair<String, String>, GpodnetEpisodeAction>();
|
|
||||||
// make sure more recent local actions are not overwritten by older remote actions
|
|
||||||
for(GpodnetEpisodeAction action : localActions) {
|
for(GpodnetEpisodeAction action : localActions) {
|
||||||
Pair key = new Pair(action.getPodcast(), action.getEpisode());
|
Pair key = new Pair(action.getPodcast(), action.getEpisode());
|
||||||
GpodnetEpisodeAction mostRecent = localMostRecentPlayAction.get(key);
|
GpodnetEpisodeAction mostRecent = localMostRecentPlayAction.get(key);
|
||||||
|
@ -201,6 +236,9 @@ public class GpodnetSyncService extends Service {
|
||||||
localMostRecentPlayAction.put(key, action);
|
localMostRecentPlayAction.put(key, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure more recent local actions are not overwritten by older remote actions
|
||||||
|
Map<Pair<String, String>, GpodnetEpisodeAction> mostRecentPlayAction = new HashMap<Pair<String, String>, GpodnetEpisodeAction>();
|
||||||
for (GpodnetEpisodeAction action : remoteActions) {
|
for (GpodnetEpisodeAction action : remoteActions) {
|
||||||
switch (action.getAction()) {
|
switch (action.getAction()) {
|
||||||
case NEW:
|
case NEW:
|
||||||
|
@ -218,11 +256,11 @@ public class GpodnetSyncService extends Service {
|
||||||
GpodnetEpisodeAction localMostRecent = localMostRecentPlayAction.get(key);
|
GpodnetEpisodeAction localMostRecent = localMostRecentPlayAction.get(key);
|
||||||
if(localMostRecent == null ||
|
if(localMostRecent == null ||
|
||||||
localMostRecent.getTimestamp().before(action.getTimestamp())) {
|
localMostRecent.getTimestamp().before(action.getTimestamp())) {
|
||||||
GpodnetEpisodeAction mostRecent = remoteMostRecentPlayAction.get(key);
|
GpodnetEpisodeAction mostRecent = mostRecentPlayAction.get(key);
|
||||||
if (mostRecent == null) {
|
if (mostRecent == null) {
|
||||||
remoteMostRecentPlayAction.put(key, action);
|
mostRecentPlayAction.put(key, action);
|
||||||
} else if (mostRecent.getTimestamp().before(action.getTimestamp())) {
|
} else if (mostRecent.getTimestamp().before(action.getTimestamp())) {
|
||||||
remoteMostRecentPlayAction.put(key, action);
|
mostRecentPlayAction.put(key, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -231,10 +269,12 @@ public class GpodnetSyncService extends Service {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (GpodnetEpisodeAction action : remoteMostRecentPlayAction.values()) {
|
for (GpodnetEpisodeAction action : mostRecentPlayAction.values()) {
|
||||||
FeedItem playItem = DBReader.getFeedItem(this, action.getPodcast(), action.getEpisode());
|
FeedItem playItem = DBReader.getFeedItem(this, action.getPodcast(), action.getEpisode());
|
||||||
if (playItem != null) {
|
if (playItem != null) {
|
||||||
playItem.getMedia().setPosition(action.getPosition() * 1000);
|
FeedMedia media = playItem.getMedia();
|
||||||
|
media.setPosition(action.getPosition() * 1000);
|
||||||
|
DBWriter.setFeedMedia(this, media);
|
||||||
if(playItem.getMedia().hasAlmostEnded()) {
|
if(playItem.getMedia().hasAlmostEnded()) {
|
||||||
DBWriter.markItemRead(this, playItem, true, true);
|
DBWriter.markItemRead(this, playItem, true, true);
|
||||||
DBWriter.addItemToPlaybackHistory(this, playItem.getMedia());
|
DBWriter.addItemToPlaybackHistory(this, playItem.getMedia());
|
||||||
|
@ -342,4 +382,20 @@ public class GpodnetSyncService extends Service {
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void sendSyncSubscriptionsIntent(Context context) {
|
||||||
|
if (GpodnetPreferences.loggedIn()) {
|
||||||
|
Intent intent = new Intent(context, GpodnetSyncService.class);
|
||||||
|
intent.putExtra(ARG_ACTION, ACTION_SYNC_SUBSCRIPTIONS);
|
||||||
|
context.startService(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendSyncActionsIntent(Context context) {
|
||||||
|
if (GpodnetPreferences.loggedIn()) {
|
||||||
|
Intent intent = new Intent(context, GpodnetSyncService.class);
|
||||||
|
intent.putExtra(ARG_ACTION, ACTION_SYNC_ACTIONS);
|
||||||
|
context.startService(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue