From e30533a810efa59bba6c101dd1405e776e1b451e Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 24 Apr 2021 16:18:02 +0200 Subject: Moved synchronization to its own module --- core/build.gradle | 2 + .../core/preferences/GpodnetPreferences.java | 2 +- .../download/handler/MediaDownloadedHandler.java | 2 +- .../danoeh/antennapod/core/storage/DBWriter.java | 2 +- .../danoeh/antennapod/core/sync/SyncService.java | 18 +- .../core/sync/gpoddernet/GpodnetService.java | 826 --------------------- .../GpodnetServiceAuthenticationException.java | 9 - .../GpodnetServiceBadStatusCodeException.java | 12 - .../sync/gpoddernet/GpodnetServiceException.java | 15 - .../core/sync/gpoddernet/model/GpodnetDevice.java | 73 -- .../model/GpodnetEpisodeActionPostResponse.java | 49 -- .../core/sync/gpoddernet/model/GpodnetPodcast.java | 72 -- .../core/sync/gpoddernet/model/GpodnetTag.java | 66 -- .../model/GpodnetUploadChangesResponse.java | 53 -- .../antennapod/core/sync/model/EpisodeAction.java | 260 ------- .../core/sync/model/EpisodeActionChanges.java | 34 - .../antennapod/core/sync/model/ISyncService.java | 20 - .../core/sync/model/SubscriptionChanges.java | 39 - .../core/sync/model/SyncServiceException.java | 13 - .../core/sync/model/UploadChangesResponse.java | 13 - 20 files changed, 15 insertions(+), 1565 deletions(-) delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceAuthenticationException.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceBadStatusCodeException.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceException.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetDevice.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetEpisodeActionPostResponse.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetPodcast.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetTag.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetUploadChangesResponse.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/model/ISyncService.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/model/SubscriptionChanges.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/model/SyncServiceException.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/sync/model/UploadChangesResponse.java (limited to 'core') diff --git a/core/build.gradle b/core/build.gradle index e5ab13bcd..f9c09c7bc 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -75,6 +75,8 @@ android { dependencies { implementation project(':model') implementation project(':net:ssl') + implementation project(':net:sync:gpoddernet') + implementation project(':net:sync:model') implementation project(':ui:app-start-intent') implementation project(':ui:common') implementation project(':ui:png-icons') diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java index 209558b19..e338e0d01 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java @@ -6,7 +6,7 @@ import android.util.Log; import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.sync.SyncService; -import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService; +import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService; /** * Manages preferences for accessing gpodder.net service diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java index 2d0efd22a..8c9035621 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/MediaDownloadedHandler.java @@ -19,7 +19,7 @@ import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.util.ChapterUtils; import de.danoeh.antennapod.core.util.DownloadError; import de.danoeh.antennapod.core.sync.SyncService; -import de.danoeh.antennapod.core.sync.model.EpisodeAction; +import de.danoeh.antennapod.net.sync.model.EpisodeAction; import org.greenrobot.eventbus.EventBus; /** diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java index cf3983910..3231c3779 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java @@ -8,7 +8,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import de.danoeh.antennapod.core.sync.SyncService; -import de.danoeh.antennapod.core.sync.model.EpisodeAction; +import de.danoeh.antennapod.net.sync.model.EpisodeAction; import org.greenrobot.eventbus.EventBus; import java.io.File; diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java index 21b217e66..4736a2c33 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java @@ -32,17 +32,17 @@ import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; -import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService; -import de.danoeh.antennapod.core.sync.model.EpisodeAction; -import de.danoeh.antennapod.core.sync.model.EpisodeActionChanges; -import de.danoeh.antennapod.core.sync.model.ISyncService; -import de.danoeh.antennapod.core.sync.model.SubscriptionChanges; -import de.danoeh.antennapod.core.sync.model.SyncServiceException; -import de.danoeh.antennapod.core.sync.model.UploadChangesResponse; import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.URLChecker; import de.danoeh.antennapod.core.util.gui.NotificationUtils; +import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService; +import de.danoeh.antennapod.net.sync.model.EpisodeAction; +import de.danoeh.antennapod.net.sync.model.EpisodeActionChanges; +import de.danoeh.antennapod.net.sync.model.ISyncService; +import de.danoeh.antennapod.net.sync.model.SubscriptionChanges; +import de.danoeh.antennapod.net.sync.model.SyncServiceException; +import de.danoeh.antennapod.net.sync.model.UploadChangesResponse; import io.reactivex.Completable; import io.reactivex.schedulers.Schedulers; import org.apache.commons.lang3.StringUtils; @@ -81,7 +81,9 @@ public class SyncService extends Worker { if (!GpodnetPreferences.loggedIn()) { return Result.success(); } - syncServiceImpl = new GpodnetService(AntennapodHttpClient.getHttpClient(), GpodnetPreferences.getHosturl()); + syncServiceImpl = new GpodnetService(AntennapodHttpClient.getHttpClient(), + GpodnetPreferences.getHosturl(), GpodnetPreferences.getDeviceID(), + GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword()); SharedPreferences.Editor prefs = getApplicationContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) .edit(); prefs.putLong(PREF_LAST_SYNC_ATTEMPT_TIMESTAMP, System.currentTimeMillis()).apply(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java deleted file mode 100644 index cd0fc93ea..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java +++ /dev/null @@ -1,826 +0,0 @@ -package de.danoeh.antennapod.core.sync.gpoddernet; - -import android.util.Log; -import androidx.annotation.NonNull; -import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.core.preferences.GpodnetPreferences; -import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetDevice; -import de.danoeh.antennapod.core.sync.model.EpisodeAction; -import de.danoeh.antennapod.core.sync.model.EpisodeActionChanges; -import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetEpisodeActionPostResponse; -import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetPodcast; -import de.danoeh.antennapod.core.sync.model.ISyncService; -import de.danoeh.antennapod.core.sync.model.SubscriptionChanges; -import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetTag; -import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetUploadChangesResponse; -import de.danoeh.antennapod.core.sync.model.SyncServiceException; -import de.danoeh.antennapod.core.sync.model.UploadChangesResponse; -import okhttp3.Credentials; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Communicates with the gpodder.net service. - */ -public class GpodnetService implements ISyncService { - public static final String TAG = "GpodnetService"; - public static final String DEFAULT_BASE_HOST = "gpodder.net"; - private static final int UPLOAD_BULK_SIZE = 30; - private static final MediaType TEXT = MediaType.parse("plain/text; charset=utf-8"); - private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - private String baseScheme; - private String baseHost; - private int basePort; - - private final OkHttpClient httpClient; - private String username = null; - - // split into schema, host and port - missing parts are null - private static Pattern urlsplit_regex = Pattern.compile("(?:(https?)://)?([^:]+)(?::(\\d+))?"); - - public GpodnetService(OkHttpClient httpClient, String baseHosturl) { - this.httpClient = httpClient; - - Matcher m = urlsplit_regex.matcher(baseHosturl); - if (m.matches()) { - this.baseScheme = m.group(1); - this.baseHost = m.group(2); - if (m.group(3) == null) { - this.basePort = -1; - } else { - this.basePort = Integer.parseInt(m.group(3)); // regex -> can only be digits - } - } else { - // URL does not match regex: use it anyway -> this will cause an exception on connect - this.baseScheme = "https"; - this.baseHost = baseHosturl; - this.basePort = 443; - } - - if (this.baseScheme == null) { // assume https - this.baseScheme = "https"; - } - - if (this.baseScheme.equals("https") && this.basePort == -1) { - this.basePort = 443; - } - - if (this.baseScheme.equals("http") && this.basePort == -1) { - this.basePort = 80; - } - } - - private void requireLoggedIn() { - if (username == null) { - throw new IllegalStateException("Not logged in"); - } - } - - /** - * Returns the [count] most used tags. - */ - public List getTopTags(int count) throws GpodnetServiceException { - URL url; - try { - url = new URI(baseScheme, null, baseHost, basePort, - String.format(Locale.US, "/api/2/tags/%d.json", count), null, null).toURL(); - } catch (MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - - Request.Builder request = new Request.Builder().url(url); - String response = executeRequest(request); - try { - JSONArray jsonTagList = new JSONArray(response); - List tagList = new ArrayList<>(jsonTagList.length()); - for (int i = 0; i < jsonTagList.length(); i++) { - JSONObject jsonObject = jsonTagList.getJSONObject(i); - String title = jsonObject.getString("title"); - String tag = jsonObject.getString("tag"); - int usage = jsonObject.getInt("usage"); - tagList.add(new GpodnetTag(title, tag, usage)); - } - return tagList; - } catch (JSONException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - /** - * Returns the [count] most subscribed podcasts for the given tag. - * - * @throws IllegalArgumentException if tag is null - */ - public List getPodcastsForTag(@NonNull GpodnetTag tag, int count) - throws GpodnetServiceException { - try { - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format(Locale.US, "/api/2/tag/%s/%d.json", tag.getTag(), count), null, null).toURL(); - Request.Builder request = new Request.Builder().url(url); - String response = executeRequest(request); - - JSONArray jsonArray = new JSONArray(response); - return readPodcastListFromJsonArray(jsonArray); - - } catch (JSONException | MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - /** - * Returns the toplist of podcast. - * - * @param count of elements that should be returned. Must be in range 1..100. - * @throws IllegalArgumentException if count is out of range. - */ - public List getPodcastToplist(int count) throws GpodnetServiceException { - if (count < 1 || count > 100) { - throw new IllegalArgumentException("Count must be in range 1..100"); - } - - try { - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format(Locale.US, "/toplist/%d.json", count), null, null).toURL(); - Request.Builder request = new Request.Builder().url(url); - String response = executeRequest(request); - - JSONArray jsonArray = new JSONArray(response); - return readPodcastListFromJsonArray(jsonArray); - - } catch (JSONException | MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - /** - * Returns a list of suggested podcasts for the user that is currently - * logged in. - *

- * This method requires authentication. - * - * @param count The - * number of elements that should be returned. Must be in range - * 1..100. - * @throws IllegalArgumentException if count is out of range. - * @throws GpodnetServiceAuthenticationException If there is an authentication error. - */ - public List getSuggestions(int count) throws GpodnetServiceException { - if (count < 1 || count > 100) { - throw new IllegalArgumentException("Count must be in range 1..100"); - } - - try { - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format(Locale.US, "/suggestions/%d.json", count), null, null).toURL(); - Request.Builder request = new Request.Builder().url(url); - String response = executeRequest(request); - - JSONArray jsonArray = new JSONArray(response); - return readPodcastListFromJsonArray(jsonArray); - } catch (JSONException | MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - /** - * Searches the podcast directory for a given string. - * - * @param query The search query - * @param scaledLogoSize The size of the logos that are returned by the search query. - * Must be in range 1..256. If the value is out of range, the - * default value defined by the gpodder.net API will be used. - */ - public List searchPodcasts(String query, int scaledLogoSize) throws GpodnetServiceException { - String parameters = (scaledLogoSize > 0 && scaledLogoSize <= 256) ? String - .format(Locale.US, "q=%s&scale_logo=%d", query, scaledLogoSize) : String - .format("q=%s", query); - try { - URL url = new URI(baseScheme, null, baseHost, basePort, "/search.json", - parameters, null).toURL(); - Request.Builder request = new Request.Builder().url(url); - String response = executeRequest(request); - - JSONArray jsonArray = new JSONArray(response); - return readPodcastListFromJsonArray(jsonArray); - - } catch (JSONException | MalformedURLException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } catch (URISyntaxException e) { - e.printStackTrace(); - throw new IllegalStateException(e); - } - } - - /** - * Returns all devices of a given user. - *

- * This method requires authentication. - * - * @throws GpodnetServiceAuthenticationException If there is an authentication error. - */ - public List getDevices() throws GpodnetServiceException { - requireLoggedIn(); - try { - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format("/api/2/devices/%s.json", username), null, null).toURL(); - Request.Builder request = new Request.Builder().url(url); - String response = executeRequest(request); - JSONArray devicesArray = new JSONArray(response); - return readDeviceListFromJsonArray(devicesArray); - } catch (JSONException | MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - /** - * Returns synchronization status of devices. - *

- * This method requires authentication. - * - * @throws GpodnetServiceAuthenticationException If there is an authentication error. - */ - public List> getSynchronizedDevices() throws GpodnetServiceException { - requireLoggedIn(); - try { - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format("/api/2/sync-devices/%s.json", username), null, null).toURL(); - Request.Builder request = new Request.Builder().url(url); - String response = executeRequest(request); - JSONObject syncStatus = new JSONObject(response); - List> result = new ArrayList<>(); - - JSONArray synchronizedDevices = syncStatus.getJSONArray("synchronized"); - for (int i = 0; i < synchronizedDevices.length(); i++) { - JSONArray groupDevices = synchronizedDevices.getJSONArray(i); - List group = new ArrayList<>(); - for (int j = 0; j < groupDevices.length(); j++) { - group.add(groupDevices.getString(j)); - } - result.add(group); - } - - JSONArray notSynchronizedDevices = syncStatus.getJSONArray("not-synchronized"); - for (int i = 0; i < notSynchronizedDevices.length(); i++) { - result.add(Collections.singletonList(notSynchronizedDevices.getString(i))); - } - - return result; - } catch (JSONException | MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - /** - * Configures the device of a given user. - *

- * This method requires authentication. - * - * @param deviceId The ID of the device that should be configured. - * @throws GpodnetServiceAuthenticationException If there is an authentication error. - */ - public void configureDevice(@NonNull String deviceId, String caption, GpodnetDevice.DeviceType type) - throws GpodnetServiceException { - requireLoggedIn(); - try { - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format("/api/2/devices/%s/%s.json", username, deviceId), null, null).toURL(); - String content; - if (caption != null || type != null) { - JSONObject jsonContent = new JSONObject(); - if (caption != null) { - jsonContent.put("caption", caption); - } - if (type != null) { - jsonContent.put("type", type.toString()); - } - content = jsonContent.toString(); - } else { - content = ""; - } - RequestBody body = RequestBody.create(JSON, content); - Request.Builder request = new Request.Builder().post(body).url(url); - executeRequest(request); - } catch (JSONException | MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - /** - * Links devices for synchronization. - *

- * This method requires authentication. - * - * @throws GpodnetServiceAuthenticationException If there is an authentication error. - */ - public void linkDevices(@NonNull List deviceIds) throws GpodnetServiceException { - requireLoggedIn(); - try { - final URL url = new URI(baseScheme, null, baseHost, basePort, - String.format("/api/2/sync-devices/%s.json", username), null, null).toURL(); - JSONObject jsonContent = new JSONObject(); - JSONArray group = new JSONArray(); - for (String deviceId : deviceIds) { - group.put(deviceId); - } - - JSONArray synchronizedGroups = new JSONArray(); - synchronizedGroups.put(group); - jsonContent.put("synchronize", synchronizedGroups); - jsonContent.put("stop-synchronize", new JSONArray()); - - Log.d("aaaa", jsonContent.toString()); - RequestBody body = RequestBody.create(JSON, jsonContent.toString()); - Request.Builder request = new Request.Builder().post(body).url(url); - executeRequest(request); - } catch (JSONException | MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - /** - * Returns the subscriptions of a specific device. - *

- * This method requires authentication. - * - * @param deviceId The ID of the device whose subscriptions should be returned. - * @return A list of subscriptions in OPML format. - * @throws GpodnetServiceAuthenticationException If there is an authentication error. - */ - public String getSubscriptionsOfDevice(@NonNull String deviceId) throws GpodnetServiceException { - requireLoggedIn(); - try { - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format("/subscriptions/%s/%s.opml", username, deviceId), null, null).toURL(); - Request.Builder request = new Request.Builder().url(url); - return executeRequest(request); - } catch (MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - /** - * Returns all subscriptions of a specific user. - *

- * This method requires authentication. - * - * @return A list of subscriptions in OPML format. - * @throws IllegalArgumentException If username is null. - * @throws GpodnetServiceAuthenticationException If there is an authentication error. - */ - public String getSubscriptionsOfUser() throws GpodnetServiceException { - requireLoggedIn(); - try { - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format("/subscriptions/%s.opml", username), null, null).toURL(); - Request.Builder request = new Request.Builder().url(url); - return executeRequest(request); - } catch (MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - /** - * Uploads the subscriptions of a specific device. - *

- * This method requires authentication. - * - * @param deviceId The ID of the device whose subscriptions should be updated. - * @param subscriptions A list of feed URLs containing all subscriptions of the - * device. - * @throws IllegalArgumentException If username, deviceId or subscriptions is null. - * @throws GpodnetServiceAuthenticationException If there is an authentication error. - */ - public void uploadSubscriptions(@NonNull String deviceId, @NonNull List subscriptions) - throws GpodnetServiceException { - requireLoggedIn(); - try { - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format("/subscriptions/%s/%s.txt", username, deviceId), null, null).toURL(); - StringBuilder builder = new StringBuilder(); - for (String s : subscriptions) { - builder.append(s); - builder.append("\n"); - } - RequestBody body = RequestBody.create(TEXT, builder.toString()); - Request.Builder request = new Request.Builder().put(body).url(url); - executeRequest(request); - } catch (MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - - } - - /** - * Updates the subscription list of a specific device. - *

- * This method requires authentication. - * - * @param deviceId The ID of the device whose subscriptions should be updated. - * @param added Collection of feed URLs of added feeds. This Collection MUST NOT contain any duplicates - * @param removed Collection of feed URLs of removed feeds. This Collection MUST NOT contain any duplicates - * @return a GpodnetUploadChangesResponse. See {@link GpodnetUploadChangesResponse} - * for details. - * @throws GpodnetServiceException if added or removed contain duplicates or if there - * is an authentication error. - */ - public GpodnetUploadChangesResponse uploadChanges(@NonNull String deviceId, @NonNull Collection added, - @NonNull Collection removed) throws GpodnetServiceException { - requireLoggedIn(); - try { - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format("/api/2/subscriptions/%s/%s.json", username, deviceId), null, null).toURL(); - - final JSONObject requestObject = new JSONObject(); - requestObject.put("add", new JSONArray(added)); - requestObject.put("remove", new JSONArray(removed)); - - RequestBody body = RequestBody.create(JSON, requestObject.toString()); - Request.Builder request = new Request.Builder().post(body).url(url); - - final String response = executeRequest(request); - return GpodnetUploadChangesResponse.fromJSONObject(response); - } catch (JSONException | MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - - } - - /** - * Returns all subscription changes of a specific device. - *

- * This method requires authentication. - * - * @param deviceId The ID of the device whose subscription changes should be - * downloaded. - * @param timestamp A timestamp that can be used to receive all changes since a - * specific point in time. - * @throws GpodnetServiceAuthenticationException If there is an authentication error. - */ - public SubscriptionChanges getSubscriptionChanges(@NonNull String deviceId, long timestamp) - throws GpodnetServiceException { - requireLoggedIn(); - String params = String.format(Locale.US, "since=%d", timestamp); - String path = String.format("/api/2/subscriptions/%s/%s.json", username, deviceId); - try { - URL url = new URI(baseScheme, null, baseHost, basePort, path, params, null).toURL(); - Request.Builder request = new Request.Builder().url(url); - - String response = executeRequest(request); - JSONObject changes = new JSONObject(response); - return readSubscriptionChangesFromJsonObject(changes); - } catch (URISyntaxException e) { - e.printStackTrace(); - throw new IllegalStateException(e); - } catch (JSONException | MalformedURLException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - - } - - /** - * Updates the episode actions - *

- * This method requires authentication. - * - * @param episodeActions Collection of episode actions. - * @return a GpodnetUploadChangesResponse. See {@link GpodnetUploadChangesResponse} - * for details. - * @throws GpodnetServiceException if added or removed contain duplicates or if there - * is an authentication error. - */ - @Override - public UploadChangesResponse uploadEpisodeActions(List episodeActions) throws SyncServiceException { - requireLoggedIn(); - UploadChangesResponse response = null; - for (int i = 0; i < episodeActions.size(); i += UPLOAD_BULK_SIZE) { - response = uploadEpisodeActionsPartial(episodeActions, - i, Math.min(episodeActions.size(), i + UPLOAD_BULK_SIZE)); - } - return response; - } - - private UploadChangesResponse uploadEpisodeActionsPartial(List episodeActions, int from, int to) - throws SyncServiceException { - try { - Log.d(TAG, "Uploading partial actions " + from + " to " + to + " of " + episodeActions.size()); - URL url = new URI(baseScheme, null, baseHost, basePort, - String.format("/api/2/episodes/%s.json", username), null, null).toURL(); - - final JSONArray list = new JSONArray(); - for (int i = from; i < to; i++) { - EpisodeAction episodeAction = episodeActions.get(i); - JSONObject obj = episodeAction.writeToJsonObject(); - if (obj != null) { - obj.put("device", GpodnetPreferences.getDeviceID()); - list.put(obj); - } - } - - RequestBody body = RequestBody.create(JSON, list.toString()); - Request.Builder request = new Request.Builder().post(body).url(url); - - final String response = executeRequest(request); - return GpodnetEpisodeActionPostResponse.fromJSONObject(response); - } catch (JSONException | MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new SyncServiceException(e); - } - } - - /** - * Returns all subscription changes of a specific device. - *

- * This method requires authentication. - * - * @param timestamp A timestamp that can be used to receive all changes since a - * specific point in time. - * @throws SyncServiceException If there is an authentication error. - */ - @Override - public EpisodeActionChanges getEpisodeActionChanges(long timestamp) throws SyncServiceException { - requireLoggedIn(); - String params = String.format(Locale.US, "since=%d", timestamp); - String path = String.format("/api/2/episodes/%s.json", username); - try { - URL url = new URI(baseScheme, null, baseHost, basePort, path, params, null).toURL(); - Request.Builder request = new Request.Builder().url(url); - - String response = executeRequest(request); - JSONObject json = new JSONObject(response); - return readEpisodeActionsFromJsonObject(json); - } catch (URISyntaxException e) { - e.printStackTrace(); - throw new IllegalStateException(e); - } catch (JSONException | MalformedURLException e) { - e.printStackTrace(); - throw new SyncServiceException(e); - } - - } - - - /** - * Logs in a specific user. This method must be called if any of the methods - * that require authentication is used. - * - * @throws IllegalArgumentException If username or password is null. - */ - public void authenticate(@NonNull String username, @NonNull String password) throws GpodnetServiceException { - URL url; - try { - url = new URI(baseScheme, null, baseHost, basePort, - String.format("/api/2/auth/%s/login.json", username), null, null).toURL(); - } catch (MalformedURLException | URISyntaxException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - RequestBody requestBody = RequestBody.create(TEXT, ""); - Request request = new Request.Builder().url(url).post(requestBody).build(); - try { - String credential = Credentials.basic(username, password, Charset.forName("UTF-8")); - Request authRequest = request.newBuilder().header("Authorization", credential).build(); - Response response = httpClient.newCall(authRequest).execute(); - checkStatusCode(response); - response.body().close(); - this.username = username; - } catch (Exception e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - private String executeRequest(@NonNull Request.Builder requestB) throws GpodnetServiceException { - Request request = requestB.build(); - String responseString; - Response response; - ResponseBody body = null; - try { - - response = httpClient.newCall(request).execute(); - checkStatusCode(response); - body = response.body(); - responseString = getStringFromResponseBody(body); - } catch (IOException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } finally { - if (body != null) { - body.close(); - } - } - return responseString; - } - - private String getStringFromResponseBody(@NonNull ResponseBody body) throws GpodnetServiceException { - ByteArrayOutputStream outputStream; - int contentLength = (int) body.contentLength(); - if (contentLength > 0) { - outputStream = new ByteArrayOutputStream(contentLength); - } else { - outputStream = new ByteArrayOutputStream(); - } - try { - byte[] buffer = new byte[8 * 1024]; - InputStream in = body.byteStream(); - int count; - while ((count = in.read(buffer)) > 0) { - outputStream.write(buffer, 0, count); - } - return outputStream.toString("UTF-8"); - } catch (IOException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } - } - - private void checkStatusCode(@NonNull Response response) throws GpodnetServiceException { - int responseCode = response.code(); - if (responseCode != HttpURLConnection.HTTP_OK) { - if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { - throw new GpodnetServiceAuthenticationException("Wrong username or password"); - } else { - if (BuildConfig.DEBUG) { - try { - Log.d(TAG, response.body().string()); - } catch (IOException e) { - e.printStackTrace(); - } - } - throw new GpodnetServiceBadStatusCodeException("Bad response code: " + responseCode, responseCode); - } - } - } - - private List readPodcastListFromJsonArray(@NonNull JSONArray array) throws JSONException { - List result = new ArrayList<>(array.length()); - for (int i = 0; i < array.length(); i++) { - result.add(readPodcastFromJsonObject(array.getJSONObject(i))); - } - return result; - } - - private GpodnetPodcast readPodcastFromJsonObject(JSONObject object) throws JSONException { - String url = object.getString("url"); - - String title; - Object titleObj = object.opt("title"); - if (titleObj instanceof String) { - title = (String) titleObj; - } else { - title = url; - } - - String description; - Object descriptionObj = object.opt("description"); - if (descriptionObj instanceof String) { - description = (String) descriptionObj; - } else { - description = ""; - } - - int subscribers = object.getInt("subscribers"); - - Object logoUrlObj = object.opt("logo_url"); - String logoUrl = (logoUrlObj instanceof String) ? (String) logoUrlObj : null; - if (logoUrl == null) { - Object scaledLogoUrl = object.opt("scaled_logo_url"); - if (scaledLogoUrl instanceof String) { - logoUrl = (String) scaledLogoUrl; - } - } - - String website = null; - Object websiteObj = object.opt("website"); - if (websiteObj instanceof String) { - website = (String) websiteObj; - } - String mygpoLink = object.getString("mygpo_link"); - - String author = null; - Object authorObj = object.opt("author"); - if (authorObj instanceof String) { - author = (String) authorObj; - } - return new GpodnetPodcast(url, title, description, subscribers, logoUrl, website, mygpoLink, author); - } - - private List readDeviceListFromJsonArray(@NonNull JSONArray array) throws JSONException { - List result = new ArrayList<>(array.length()); - for (int i = 0; i < array.length(); i++) { - result.add(readDeviceFromJsonObject(array.getJSONObject(i))); - } - return result; - } - - private GpodnetDevice readDeviceFromJsonObject(JSONObject object) throws JSONException { - String id = object.getString("id"); - String caption = object.getString("caption"); - String type = object.getString("type"); - int subscriptions = object.getInt("subscriptions"); - return new GpodnetDevice(id, caption, type, subscriptions); - } - - private SubscriptionChanges readSubscriptionChangesFromJsonObject(@NonNull JSONObject object) - throws JSONException { - - List added = new LinkedList<>(); - JSONArray jsonAdded = object.getJSONArray("add"); - for (int i = 0; i < jsonAdded.length(); i++) { - String addedUrl = jsonAdded.getString(i); - // gpodder escapes colons unnecessarily - addedUrl = addedUrl.replace("%3A", ":"); - added.add(addedUrl); - } - - List removed = new LinkedList<>(); - JSONArray jsonRemoved = object.getJSONArray("remove"); - for (int i = 0; i < jsonRemoved.length(); i++) { - String removedUrl = jsonRemoved.getString(i); - // gpodder escapes colons unnecessarily - removedUrl = removedUrl.replace("%3A", ":"); - removed.add(removedUrl); - } - - long timestamp = object.getLong("timestamp"); - return new SubscriptionChanges(added, removed, timestamp); - } - - private EpisodeActionChanges readEpisodeActionsFromJsonObject(@NonNull JSONObject object) - throws JSONException { - - List episodeActions = new ArrayList<>(); - - long timestamp = object.getLong("timestamp"); - JSONArray jsonActions = object.getJSONArray("actions"); - for (int i = 0; i < jsonActions.length(); i++) { - JSONObject jsonAction = jsonActions.getJSONObject(i); - EpisodeAction episodeAction = EpisodeAction.readFromJsonObject(jsonAction); - if (episodeAction != null) { - episodeActions.add(episodeAction); - } - } - return new EpisodeActionChanges(episodeActions, timestamp); - } - - @Override - public void login() throws GpodnetServiceException { - authenticate(GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword()); - } - - @Override - public SubscriptionChanges getSubscriptionChanges(long lastSync) throws GpodnetServiceException { - return getSubscriptionChanges(GpodnetPreferences.getDeviceID(), lastSync); - } - - @Override - public UploadChangesResponse uploadSubscriptionChanges(List addedFeeds, List removedFeeds) - throws GpodnetServiceException { - return uploadChanges(GpodnetPreferences.getDeviceID(), addedFeeds, removedFeeds); - } - - @Override - public void logout() { - - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceAuthenticationException.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceAuthenticationException.java deleted file mode 100644 index 0aec8e97e..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceAuthenticationException.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.danoeh.antennapod.core.sync.gpoddernet; - -public class GpodnetServiceAuthenticationException extends GpodnetServiceException { - private static final long serialVersionUID = 1L; - - public GpodnetServiceAuthenticationException(String message) { - super(message); - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceBadStatusCodeException.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceBadStatusCodeException.java deleted file mode 100644 index c24b5fc0a..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceBadStatusCodeException.java +++ /dev/null @@ -1,12 +0,0 @@ -package de.danoeh.antennapod.core.sync.gpoddernet; - -class GpodnetServiceBadStatusCodeException extends GpodnetServiceException { - private static final long serialVersionUID = 1L; - - private final int statusCode; - - public GpodnetServiceBadStatusCodeException(String message, int statusCode) { - super(message); - this.statusCode = statusCode; - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceException.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceException.java deleted file mode 100644 index 10c4fdc11..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetServiceException.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.danoeh.antennapod.core.sync.gpoddernet; - -import de.danoeh.antennapod.core.sync.model.SyncServiceException; - -public class GpodnetServiceException extends SyncServiceException { - private static final long serialVersionUID = 1L; - - public GpodnetServiceException(String message) { - super(message); - } - - public GpodnetServiceException(Throwable e) { - super(e); - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetDevice.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetDevice.java deleted file mode 100644 index 454b3301d..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetDevice.java +++ /dev/null @@ -1,73 +0,0 @@ -package de.danoeh.antennapod.core.sync.gpoddernet.model; - -import androidx.annotation.NonNull; - -public class GpodnetDevice { - - private final String id; - private final String caption; - private final DeviceType type; - private final int subscriptions; - - public GpodnetDevice(@NonNull String id, - String caption, - String type, - int subscriptions) { - this.id = id; - this.caption = caption; - this.type = DeviceType.fromString(type); - this.subscriptions = subscriptions; - } - - @Override - public String toString() { - return "GpodnetDevice [id=" + id + ", caption=" + caption + ", type=" - + type + ", subscriptions=" + subscriptions + "]"; - } - - public enum DeviceType { - DESKTOP, LAPTOP, MOBILE, SERVER, OTHER; - - static DeviceType fromString(String s) { - if (s == null) { - return OTHER; - } - - switch (s) { - case "desktop": - return DESKTOP; - case "laptop": - return LAPTOP; - case "mobile": - return MOBILE; - case "server": - return SERVER; - default: - return OTHER; - } - } - - @Override - public String toString() { - return super.toString().toLowerCase(); - } - - } - - public String getId() { - return id; - } - - public String getCaption() { - return caption; - } - - public DeviceType getType() { - return type; - } - - public int getSubscriptions() { - return subscriptions; - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetEpisodeActionPostResponse.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetEpisodeActionPostResponse.java deleted file mode 100644 index ae9ab9d70..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetEpisodeActionPostResponse.java +++ /dev/null @@ -1,49 +0,0 @@ -package de.danoeh.antennapod.core.sync.gpoddernet.model; - -import androidx.collection.ArrayMap; - -import de.danoeh.antennapod.core.sync.model.UploadChangesResponse; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.Map; - -public class GpodnetEpisodeActionPostResponse extends UploadChangesResponse { - /** - * URLs that should be updated. The key of the map is the original URL, the value of the map - * is the sanitized URL. - */ - private final Map updatedUrls; - - private GpodnetEpisodeActionPostResponse(long timestamp, Map updatedUrls) { - super(timestamp); - this.updatedUrls = updatedUrls; - } - - /** - * Creates a new GpodnetUploadChangesResponse-object from a JSON object that was - * returned by an uploadChanges call. - * - * @throws org.json.JSONException If the method could not parse the JSONObject. - */ - public static GpodnetEpisodeActionPostResponse fromJSONObject(String objectString) throws JSONException { - final JSONObject object = new JSONObject(objectString); - final long timestamp = object.getLong("timestamp"); - JSONArray urls = object.getJSONArray("update_urls"); - Map updatedUrls = new ArrayMap<>(urls.length()); - for (int i = 0; i < urls.length(); i++) { - JSONArray urlPair = urls.getJSONArray(i); - updatedUrls.put(urlPair.getString(0), urlPair.getString(1)); - } - return new GpodnetEpisodeActionPostResponse(timestamp, updatedUrls); - } - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); - } -} - diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetPodcast.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetPodcast.java deleted file mode 100644 index bc4969758..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetPodcast.java +++ /dev/null @@ -1,72 +0,0 @@ -package de.danoeh.antennapod.core.sync.gpoddernet.model; - -import androidx.annotation.NonNull; - -public class GpodnetPodcast { - private final String url; - private final String title; - private final String description; - private final int subscribers; - private final String logoUrl; - private final String website; - private final String mygpoLink; - private final String author; - - public GpodnetPodcast(@NonNull String url, - @NonNull String title, - @NonNull String description, - int subscribers, - String logoUrl, - String website, - String mygpoLink, - String author - ) { - this.url = url; - this.title = title; - this.description = description; - this.subscribers = subscribers; - this.logoUrl = logoUrl; - this.website = website; - this.mygpoLink = mygpoLink; - this.author = author; - } - - @Override - public String toString() { - return "GpodnetPodcast [url=" + url + ", title=" + title - + ", description=" + description + ", subscribers=" - + subscribers + ", logoUrl=" + logoUrl + ", website=" + website - + ", mygpoLink=" + mygpoLink + "]"; - } - - public String getUrl() { - return url; - } - - public String getTitle() { - return title; - } - - public String getDescription() { - return description; - } - - public int getSubscribers() { - return subscribers; - } - - public String getLogoUrl() { - return logoUrl; - } - - public String getWebsite() { - return website; - } - - public String getAuthor() { return author; } - - public String getMygpoLink() { - return mygpoLink; - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetTag.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetTag.java deleted file mode 100644 index 93abf4688..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetTag.java +++ /dev/null @@ -1,66 +0,0 @@ -package de.danoeh.antennapod.core.sync.gpoddernet.model; - -import android.os.Parcel; -import android.os.Parcelable; -import androidx.annotation.NonNull; - -public class GpodnetTag implements Parcelable { - - private final String title; - private final String tag; - private final int usage; - - public GpodnetTag(@NonNull String title, @NonNull String tag, int usage) { - this.title = title; - this.tag = tag; - this.usage = usage; - } - - private GpodnetTag(Parcel in) { - title = in.readString(); - tag = in.readString(); - usage = in.readInt(); - } - - @Override - public String toString() { - return "GpodnetTag [title="+title+", tag=" + tag + ", usage=" + usage + "]"; - } - - public String getTitle() { - return title; - } - - public String getTag() { - return tag; - } - - public int getUsage() { - return usage; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(title); - dest.writeString(tag); - dest.writeInt(usage); - } - - public static final Creator CREATOR = new Creator() { - @Override - public GpodnetTag createFromParcel(Parcel in) { - return new GpodnetTag(in); - } - - @Override - public GpodnetTag[] newArray(int size) { - return new GpodnetTag[size]; - } - }; - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetUploadChangesResponse.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetUploadChangesResponse.java deleted file mode 100644 index 790ba547f..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/model/GpodnetUploadChangesResponse.java +++ /dev/null @@ -1,53 +0,0 @@ -package de.danoeh.antennapod.core.sync.gpoddernet.model; - -import androidx.collection.ArrayMap; - -import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService; -import de.danoeh.antennapod.core.sync.model.UploadChangesResponse; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.Map; - -/** - * Object returned by {@link GpodnetService} in uploadChanges method. - */ -public class GpodnetUploadChangesResponse extends UploadChangesResponse { - /** - * URLs that should be updated. The key of the map is the original URL, the value of the map - * is the sanitized URL. - */ - public final Map updatedUrls; - - public GpodnetUploadChangesResponse(long timestamp, Map updatedUrls) { - super(timestamp); - this.updatedUrls = updatedUrls; - } - - /** - * Creates a new GpodnetUploadChangesResponse-object from a JSON object that was - * returned by an uploadChanges call. - * - * @throws org.json.JSONException If the method could not parse the JSONObject. - */ - public static GpodnetUploadChangesResponse fromJSONObject(String objectString) throws JSONException { - final JSONObject object = new JSONObject(objectString); - final long timestamp = object.getLong("timestamp"); - Map updatedUrls = new ArrayMap<>(); - JSONArray urls = object.getJSONArray("update_urls"); - for (int i = 0; i < urls.length(); i++) { - JSONArray urlPair = urls.getJSONArray(i); - updatedUrls.put(urlPair.getString(0), urlPair.getString(1)); - } - return new GpodnetUploadChangesResponse(timestamp, updatedUrls); - } - - @Override - public String toString() { - return "GpodnetUploadChangesResponse{" + - "timestamp=" + timestamp + - ", updatedUrls=" + updatedUrls + - '}'; - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java b/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java deleted file mode 100644 index 7a97b7755..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java +++ /dev/null @@ -1,260 +0,0 @@ -package de.danoeh.antennapod.core.sync.model; - -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.core.util.ObjectsCompat; -import de.danoeh.antennapod.model.feed.FeedItem; -import de.danoeh.antennapod.core.util.DateUtils; -import org.json.JSONException; -import org.json.JSONObject; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -public class EpisodeAction { - private static final String TAG = "EpisodeAction"; - 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 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.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()); - } catch (IllegalArgumentException e) { - return null; - } - EpisodeAction.Builder builder = new EpisodeAction.Builder(podcast, episode, action); - String utcTimestamp = object.optString("timestamp", null); - if (!TextUtils.isEmpty(utcTimestamp)) { - builder.timestamp(DateUtils.parse(utcTimestamp)); - } - 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 Action getAction() { - return this.action; - } - - private String getActionString() { - return this.action.name().toLowerCase(); - } - - 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 - && ObjectsCompat.equals(podcast, that.podcast) - && ObjectsCompat.equals(episode, that.episode) - && ObjectsCompat.equals(timestamp, that.timestamp); - } - - @Override - public int hashCode() { - int result = podcast != null ? podcast.hashCode() : 0; - result = 31 * result + (episode != null ? episode.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.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 + '\'' - + ", 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; - - public Builder(FeedItem item, Action action) { - this(item.getFeed().getDownload_url(), item.getMedia().getDownload_url(), action); - } - - 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 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); - } - - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java b/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java deleted file mode 100644 index 90af585af..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java +++ /dev/null @@ -1,34 +0,0 @@ -package de.danoeh.antennapod.core.sync.model; - - -import androidx.annotation.NonNull; - -import java.util.List; - -public class EpisodeActionChanges { - - private final List episodeActions; - private final long timestamp; - - public EpisodeActionChanges(@NonNull List episodeActions, long timestamp) { - this.episodeActions = episodeActions; - this.timestamp = timestamp; - } - - public List getEpisodeActions() { - return this.episodeActions; - } - - public long getTimestamp() { - return this.timestamp; - } - - @NonNull - @Override - public String toString() { - return "EpisodeActionGetResponse{" - + "episodeActions=" + episodeActions - + ", timestamp=" + timestamp - + '}'; - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/model/ISyncService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/model/ISyncService.java deleted file mode 100644 index 473072b97..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/model/ISyncService.java +++ /dev/null @@ -1,20 +0,0 @@ -package de.danoeh.antennapod.core.sync.model; - -import java.util.List; - -public interface ISyncService { - - void login() throws SyncServiceException; - - SubscriptionChanges getSubscriptionChanges(long lastSync) throws SyncServiceException; - - UploadChangesResponse uploadSubscriptionChanges( - List addedFeeds, List removedFeeds) throws SyncServiceException; - - EpisodeActionChanges getEpisodeActionChanges(long lastSync) throws SyncServiceException; - - UploadChangesResponse uploadEpisodeActions(List queuedEpisodeActions) - throws SyncServiceException; - - void logout() throws SyncServiceException; -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/model/SubscriptionChanges.java b/core/src/main/java/de/danoeh/antennapod/core/sync/model/SubscriptionChanges.java deleted file mode 100644 index 51f2ed10d..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/model/SubscriptionChanges.java +++ /dev/null @@ -1,39 +0,0 @@ -package de.danoeh.antennapod.core.sync.model; - -import androidx.annotation.NonNull; - -import java.util.List; - -public class SubscriptionChanges { - private final List added; - private final List removed; - private final long timestamp; - - public SubscriptionChanges(@NonNull List added, - @NonNull List removed, - long timestamp) { - this.added = added; - this.removed = removed; - this.timestamp = timestamp; - } - - @Override - public String toString() { - return "SubscriptionChange [added=" + added.toString() - + ", removed=" + removed.toString() + ", timestamp=" - + timestamp + "]"; - } - - public List getAdded() { - return added; - } - - public List getRemoved() { - return removed; - } - - public long getTimestamp() { - return timestamp; - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/model/SyncServiceException.java b/core/src/main/java/de/danoeh/antennapod/core/sync/model/SyncServiceException.java deleted file mode 100644 index d7e999b45..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/model/SyncServiceException.java +++ /dev/null @@ -1,13 +0,0 @@ -package de.danoeh.antennapod.core.sync.model; - -public class SyncServiceException extends Exception { - private static final long serialVersionUID = 1L; - - public SyncServiceException(String message) { - super(message); - } - - public SyncServiceException(Throwable cause) { - super(cause); - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/model/UploadChangesResponse.java b/core/src/main/java/de/danoeh/antennapod/core/sync/model/UploadChangesResponse.java deleted file mode 100644 index 44850bb03..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/model/UploadChangesResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package de.danoeh.antennapod.core.sync.model; - -public abstract class UploadChangesResponse { - - /** - * timestamp/ID that can be used for requesting changes since this upload. - */ - public final long timestamp; - - public UploadChangesResponse(long timestamp) { - this.timestamp = timestamp; - } -} -- cgit v1.2.3