Moved synchronization to its own module
This commit is contained in:
parent
7b5f29e090
commit
e30533a810
|
@ -164,6 +164,8 @@ android {
|
|||
dependencies {
|
||||
implementation project(":core")
|
||||
implementation project(':model')
|
||||
implementation project(':net:sync:gpoddernet')
|
||||
implementation project(':net:sync:model')
|
||||
implementation project(':ui:app-start-intent')
|
||||
implementation project(':ui:common')
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ import java.util.List;
|
|||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetDevice;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetTag;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetDevice;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetTag;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
@ -28,14 +28,16 @@ public class GPodnetServiceTest {
|
|||
|
||||
private static final String USER = "";
|
||||
private static final String PW = "";
|
||||
private static final String DEVICE_ID = "radio";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
service = new GpodnetService(AntennapodHttpClient.getHttpClient(), GpodnetService.DEFAULT_BASE_HOST);
|
||||
service = new GpodnetService(AntennapodHttpClient.getHttpClient(),
|
||||
GpodnetService.DEFAULT_BASE_HOST, DEVICE_ID, USER, PW);
|
||||
}
|
||||
|
||||
private void authenticate() throws GpodnetServiceException {
|
||||
service.authenticate(USER, PW);
|
||||
service.login();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -43,7 +45,7 @@ public class GPodnetServiceTest {
|
|||
authenticate();
|
||||
ArrayList<String> l = new ArrayList<>();
|
||||
l.add("http://bitsundso.de/feed");
|
||||
service.uploadSubscriptions("radio", l);
|
||||
service.uploadSubscriptions(DEVICE_ID, l);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -52,7 +54,7 @@ public class GPodnetServiceTest {
|
|||
ArrayList<String> l = new ArrayList<>();
|
||||
l.add("http://bitsundso.de/feed");
|
||||
l.add("http://gamesundso.de/feed");
|
||||
service.uploadSubscriptions("radio", l);
|
||||
service.uploadSubscriptions(DEVICE_ID, l);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -62,14 +64,14 @@ public class GPodnetServiceTest {
|
|||
List<String> subscriptions = Arrays.asList(URLS[0], URLS[1]);
|
||||
List<String> removed = singletonList(URLS[0]);
|
||||
List<String> added = Arrays.asList(URLS[2], URLS[3]);
|
||||
service.uploadSubscriptions("radio", subscriptions);
|
||||
service.uploadChanges("radio", added, removed);
|
||||
service.uploadSubscriptions(DEVICE_ID, subscriptions);
|
||||
service.uploadSubscriptionChanges(added, removed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSubscriptionChanges() throws GpodnetServiceException {
|
||||
authenticate();
|
||||
service.getSubscriptionChanges("radio", 1362322610L);
|
||||
service.getSubscriptionChanges(1362322610L);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -83,7 +85,7 @@ public class GPodnetServiceTest {
|
|||
public void testGetSubscriptionsOfDevice()
|
||||
throws GpodnetServiceException {
|
||||
authenticate();
|
||||
service.getSubscriptionsOfDevice("radio");
|
||||
service.getSubscriptionsOfDevice(DEVICE_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -13,7 +13,7 @@ import com.bumptech.glide.Glide;
|
|||
import com.bumptech.glide.load.resource.bitmap.FitCenter;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import android.widget.ArrayAdapter;
|
|||
import android.widget.TextView;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetTag;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetTag;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@ package de.danoeh.antennapod.discovery;
|
|||
|
||||
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.SingleOnSubscribe;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
|
@ -18,7 +18,8 @@ public class GpodnetPodcastSearcher implements PodcastSearcher {
|
|||
return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
|
||||
try {
|
||||
GpodnetService service = new GpodnetService(AntennapodHttpClient.getHttpClient(),
|
||||
GpodnetPreferences.getHosturl());
|
||||
GpodnetPreferences.getHosturl(), GpodnetPreferences.getDeviceID(),
|
||||
GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
|
||||
List<GpodnetPodcast> gpodnetPodcasts = service.searchPodcasts(query, 0);
|
||||
List<PodcastSearchResult> results = new ArrayList<>();
|
||||
for (GpodnetPodcast podcast : gpodnetPodcasts) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package de.danoeh.antennapod.discovery;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.mfietz.fyydlin.SearchHit;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
|
|
@ -17,9 +17,9 @@ import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
|
|||
import de.danoeh.antennapod.adapter.gpodnet.PodcastListAdapter;
|
||||
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
@ -76,7 +76,8 @@ public abstract class PodcastListFragment extends Fragment {
|
|||
disposable = Observable.fromCallable(
|
||||
() -> {
|
||||
GpodnetService service = new GpodnetService(AntennapodHttpClient.getHttpClient(),
|
||||
GpodnetPreferences.getHosturl());
|
||||
GpodnetPreferences.getHosturl(), GpodnetPreferences.getDeviceID(),
|
||||
GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
|
||||
return loadPodcastData(service);
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package de.danoeh.antennapod.fragment.gpodnet;
|
||||
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetPodcast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetPodcast;
|
||||
|
||||
/**
|
||||
* Displays suggestions from gpodder.net
|
||||
|
@ -17,7 +17,7 @@ public class SuggestionListFragment extends PodcastListFragment {
|
|||
@Override
|
||||
protected List<GpodnetPodcast> loadPodcastData(GpodnetService service) throws GpodnetServiceException {
|
||||
if (GpodnetPreferences.loggedIn()) {
|
||||
service.authenticate(GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
|
||||
service.login();
|
||||
return service.getSuggestions(SUGGESTIONS_COUNT);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
|
|
|
@ -5,10 +5,10 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetTag;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetServiceException;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetTag;
|
||||
|
||||
/**
|
||||
* Shows all podcasts from gpodder.net that belong to a specific tag.
|
||||
|
|
|
@ -10,8 +10,8 @@ import de.danoeh.antennapod.activity.MainActivity;
|
|||
import de.danoeh.antennapod.adapter.gpodnet.TagListAdapter;
|
||||
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetTag;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetTag;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
@ -51,7 +51,8 @@ public class TagListFragment extends ListFragment {
|
|||
disposable = Observable.fromCallable(
|
||||
() -> {
|
||||
GpodnetService service = new GpodnetService(AntennapodHttpClient.getHttpClient(),
|
||||
GpodnetPreferences.getHosturl());
|
||||
GpodnetPreferences.getHosturl(), GpodnetPreferences.getDeviceID(),
|
||||
GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
|
||||
return service.getTopTags(COUNT);
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
|
|
@ -25,8 +25,8 @@ import de.danoeh.antennapod.R;
|
|||
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.core.sync.SyncService;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetDevice;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetDevice;
|
||||
import de.danoeh.antennapod.core.util.FileNameGenerator;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import io.reactivex.Completable;
|
||||
|
@ -96,7 +96,9 @@ public class GpodderAuthenticationFragment extends DialogFragment {
|
|||
} else {
|
||||
GpodnetPreferences.setHosturl(GpodnetService.DEFAULT_BASE_HOST);
|
||||
}
|
||||
service = new GpodnetService(AntennapodHttpClient.getHttpClient(), GpodnetPreferences.getHosturl());
|
||||
service = new GpodnetService(AntennapodHttpClient.getHttpClient(),
|
||||
GpodnetPreferences.getHosturl(), GpodnetPreferences.getDeviceID(),
|
||||
GpodnetPreferences.getUsername(), GpodnetPreferences.getPassword());
|
||||
getDialog().setTitle(GpodnetPreferences.getHosturl());
|
||||
advance();
|
||||
});
|
||||
|
@ -138,7 +140,8 @@ public class GpodderAuthenticationFragment extends DialogFragment {
|
|||
inputManager.hideSoftInputFromWindow(login.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
|
||||
|
||||
Completable.fromAction(() -> {
|
||||
service.authenticate(usernameStr, passwordStr);
|
||||
service.setCredentials(usernameStr, passwordStr);
|
||||
service.login();
|
||||
devices = service.getDevices();
|
||||
GpodderAuthenticationFragment.this.username = usernameStr;
|
||||
GpodderAuthenticationFragment.this.password = passwordStr;
|
||||
|
|
|
@ -20,7 +20,7 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
|
|||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.sync.SyncService;
|
||||
import de.danoeh.antennapod.core.sync.model.EpisodeAction;
|
||||
import de.danoeh.antennapod.net.sync.model.EpisodeAction;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# :net:sync
|
||||
|
||||
This folder contains modules related to external services for synchronization. The module `model` provides the basic interfaces for implementing a synchronization backend. The other modules contains backends for specific synchronization services.
|
|
@ -0,0 +1,3 @@
|
|||
# :net:sync:gpoddernet
|
||||
|
||||
This module contains the sync backend for the open-source podcast synchronization service "Gpodder.net".
|
|
@ -0,0 +1,57 @@
|
|||
apply plugin: "com.android.library"
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
|
||||
multiDexEnabled false
|
||||
|
||||
testApplicationId "de.danoeh.antennapod.core.tests"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt")
|
||||
}
|
||||
debug {
|
||||
// debug build has method count over 64k single-dex threshold.
|
||||
// For building debug build to use on Android < 21 (pre-Android 5) devices,
|
||||
// you need to manually change class
|
||||
// de.danoeh.antennapod.PodcastApp to extend MultiDexApplication .
|
||||
// See Issue #2813
|
||||
multiDexEnabled true
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
includeAndroidResources = true
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'GradleDependency'
|
||||
checkDependencies true
|
||||
warningsAsErrors true
|
||||
abortOnError true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':net:sync:model')
|
||||
|
||||
annotationProcessor "androidx.annotation:annotation:$annotationVersion"
|
||||
implementation "androidx.appcompat:appcompat:$appcompatVersion"
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
||||
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<manifest package="de.danoeh.antennapod.net.sync.gpoddernet" />
|
|
@ -1,20 +1,18 @@
|
|||
package de.danoeh.antennapod.core.sync.gpoddernet;
|
||||
package de.danoeh.antennapod.net.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 de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetDevice;
|
||||
import de.danoeh.antennapod.net.sync.model.EpisodeAction;
|
||||
import de.danoeh.antennapod.net.sync.model.EpisodeActionChanges;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetEpisodeActionPostResponse;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetPodcast;
|
||||
import de.danoeh.antennapod.net.sync.model.ISyncService;
|
||||
import de.danoeh.antennapod.net.sync.model.SubscriptionChanges;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetTag;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetUploadChangesResponse;
|
||||
import de.danoeh.antennapod.net.sync.model.SyncServiceException;
|
||||
import de.danoeh.antennapod.net.sync.model.UploadChangesResponse;
|
||||
import okhttp3.Credentials;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
@ -36,7 +34,6 @@ 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;
|
||||
|
@ -55,17 +52,24 @@ public class GpodnetService implements ISyncService {
|
|||
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 String baseHost;
|
||||
private final String deviceId;
|
||||
private String username;
|
||||
private String password;
|
||||
private boolean loggedIn = false;
|
||||
|
||||
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) {
|
||||
public GpodnetService(OkHttpClient httpClient, String baseHosturl,
|
||||
String deviceId, String username, String password) {
|
||||
this.httpClient = httpClient;
|
||||
this.deviceId = deviceId;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
|
||||
Matcher m = urlsplit_regex.matcher(baseHosturl);
|
||||
if (m.matches()) {
|
||||
|
@ -97,7 +101,7 @@ public class GpodnetService implements ISyncService {
|
|||
}
|
||||
|
||||
private void requireLoggedIn() {
|
||||
if (username == null) {
|
||||
if (!loggedIn) {
|
||||
throw new IllegalStateException("Not logged in");
|
||||
}
|
||||
}
|
||||
|
@ -454,7 +458,6 @@ public class GpodnetService implements ISyncService {
|
|||
* <p/>
|
||||
* 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}
|
||||
|
@ -462,8 +465,9 @@ public class GpodnetService implements ISyncService {
|
|||
* @throws GpodnetServiceException if added or removed contain duplicates or if there
|
||||
* is an authentication error.
|
||||
*/
|
||||
public GpodnetUploadChangesResponse uploadChanges(@NonNull String deviceId, @NonNull Collection<String> added,
|
||||
@NonNull Collection<String> removed) throws GpodnetServiceException {
|
||||
@Override
|
||||
public UploadChangesResponse uploadSubscriptionChanges(List<String> added, List<String> removed)
|
||||
throws GpodnetServiceException {
|
||||
requireLoggedIn();
|
||||
try {
|
||||
URL url = new URI(baseScheme, null, baseHost, basePort,
|
||||
|
@ -490,14 +494,12 @@ public class GpodnetService implements ISyncService {
|
|||
* <p/>
|
||||
* 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 {
|
||||
@Override
|
||||
public SubscriptionChanges getSubscriptionChanges(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);
|
||||
|
@ -552,7 +554,7 @@ public class GpodnetService implements ISyncService {
|
|||
EpisodeAction episodeAction = episodeActions.get(i);
|
||||
JSONObject obj = episodeAction.writeToJsonObject();
|
||||
if (obj != null) {
|
||||
obj.put("device", GpodnetPreferences.getDeviceID());
|
||||
obj.put("device", deviceId);
|
||||
list.put(obj);
|
||||
}
|
||||
}
|
||||
|
@ -606,7 +608,8 @@ public class GpodnetService implements ISyncService {
|
|||
*
|
||||
* @throws IllegalArgumentException If username or password is null.
|
||||
*/
|
||||
public void authenticate(@NonNull String username, @NonNull String password) throws GpodnetServiceException {
|
||||
@Override
|
||||
public void login() throws GpodnetServiceException {
|
||||
URL url;
|
||||
try {
|
||||
url = new URI(baseScheme, null, baseHost, basePort,
|
||||
|
@ -623,7 +626,7 @@ public class GpodnetService implements ISyncService {
|
|||
Response response = httpClient.newCall(authRequest).execute();
|
||||
checkStatusCode(response);
|
||||
response.body().close();
|
||||
this.username = username;
|
||||
this.loggedIn = true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new GpodnetServiceException(e);
|
||||
|
@ -803,24 +806,13 @@ public class GpodnetService implements ISyncService {
|
|||
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<String> addedFeeds, List<String> removedFeeds)
|
||||
throws GpodnetServiceException {
|
||||
return uploadChanges(GpodnetPreferences.getDeviceID(), addedFeeds, removedFeeds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
|
||||
}
|
||||
|
||||
public void setCredentials(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.sync.gpoddernet;
|
||||
package de.danoeh.antennapod.net.sync.gpoddernet;
|
||||
|
||||
public class GpodnetServiceAuthenticationException extends GpodnetServiceException {
|
||||
private static final long serialVersionUID = 1L;
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.sync.gpoddernet;
|
||||
package de.danoeh.antennapod.net.sync.gpoddernet;
|
||||
|
||||
class GpodnetServiceBadStatusCodeException extends GpodnetServiceException {
|
||||
private static final long serialVersionUID = 1L;
|
|
@ -1,6 +1,6 @@
|
|||
package de.danoeh.antennapod.core.sync.gpoddernet;
|
||||
package de.danoeh.antennapod.net.sync.gpoddernet;
|
||||
|
||||
import de.danoeh.antennapod.core.sync.model.SyncServiceException;
|
||||
import de.danoeh.antennapod.net.sync.model.SyncServiceException;
|
||||
|
||||
public class GpodnetServiceException extends SyncServiceException {
|
||||
private static final long serialVersionUID = 1L;
|
|
@ -1,7 +1,9 @@
|
|||
package de.danoeh.antennapod.core.sync.gpoddernet.model;
|
||||
package de.danoeh.antennapod.net.sync.gpoddernet.model;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class GpodnetDevice {
|
||||
|
||||
private final String id;
|
||||
|
@ -49,7 +51,7 @@ public class GpodnetDevice {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString().toLowerCase();
|
||||
return super.toString().toLowerCase(Locale.US);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package de.danoeh.antennapod.core.sync.gpoddernet.model;
|
||||
package de.danoeh.antennapod.net.sync.gpoddernet.model;
|
||||
|
||||
import androidx.collection.ArrayMap;
|
||||
|
||||
import de.danoeh.antennapod.core.sync.model.UploadChangesResponse;
|
||||
import de.danoeh.antennapod.net.sync.model.UploadChangesResponse;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.json.JSONArray;
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.sync.gpoddernet.model;
|
||||
package de.danoeh.antennapod.net.sync.gpoddernet.model;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.sync.gpoddernet.model;
|
||||
package de.danoeh.antennapod.net.sync.gpoddernet.model;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
|
@ -1,9 +1,9 @@
|
|||
package de.danoeh.antennapod.core.sync.gpoddernet.model;
|
||||
package de.danoeh.antennapod.net.sync.gpoddernet.model;
|
||||
|
||||
import androidx.collection.ArrayMap;
|
||||
|
||||
import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.core.sync.model.UploadChangesResponse;
|
||||
import de.danoeh.antennapod.net.sync.gpoddernet.GpodnetService;
|
||||
import de.danoeh.antennapod.net.sync.model.UploadChangesResponse;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
|
@ -0,0 +1,3 @@
|
|||
# :net:sync:model
|
||||
|
||||
This module contains the basic interfaces for implementing a sync backend.
|
|
@ -0,0 +1,54 @@
|
|||
apply plugin: "com.android.library"
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
|
||||
multiDexEnabled false
|
||||
|
||||
testApplicationId "de.danoeh.antennapod.core.tests"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt")
|
||||
}
|
||||
debug {
|
||||
// debug build has method count over 64k single-dex threshold.
|
||||
// For building debug build to use on Android < 21 (pre-Android 5) devices,
|
||||
// you need to manually change class
|
||||
// de.danoeh.antennapod.PodcastApp to extend MultiDexApplication .
|
||||
// See Issue #2813
|
||||
multiDexEnabled true
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
includeAndroidResources = true
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'GradleDependency'
|
||||
checkDependencies true
|
||||
warningsAsErrors true
|
||||
abortOnError true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':model')
|
||||
|
||||
annotationProcessor "androidx.annotation:annotation:$annotationVersion"
|
||||
implementation "androidx.appcompat:appcompat:$appcompatVersion"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<manifest package="de.danoeh.antennapod.net.sync.model" />
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.sync.model;
|
||||
package de.danoeh.antennapod.net.sync.model;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
@ -6,10 +6,10 @@ 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.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
@ -17,6 +17,7 @@ import java.util.TimeZone;
|
|||
|
||||
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;
|
||||
|
@ -56,14 +57,20 @@ public class EpisodeAction {
|
|||
}
|
||||
EpisodeAction.Action action;
|
||||
try {
|
||||
action = EpisodeAction.Action.valueOf(actionString.toUpperCase());
|
||||
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)) {
|
||||
builder.timestamp(DateUtils.parse(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();
|
||||
}
|
||||
}
|
||||
if (action == EpisodeAction.Action.PLAY) {
|
||||
int started = object.optInt("started", -1);
|
||||
|
@ -92,7 +99,7 @@ public class EpisodeAction {
|
|||
}
|
||||
|
||||
private String getActionString() {
|
||||
return this.action.name().toLowerCase();
|
||||
return this.action.name().toLowerCase(Locale.US);
|
||||
}
|
||||
|
||||
public Date getTimestamp() {
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.sync.model;
|
||||
package de.danoeh.antennapod.net.sync.model;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.sync.model;
|
||||
package de.danoeh.antennapod.net.sync.model;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.sync.model;
|
||||
package de.danoeh.antennapod.net.sync.model;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.sync.model;
|
||||
package de.danoeh.antennapod.net.sync.model;
|
||||
|
||||
public class SyncServiceException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.sync.model;
|
||||
package de.danoeh.antennapod.net.sync.model;
|
||||
|
||||
public abstract class UploadChangesResponse {
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
include ':app'
|
||||
include ':core'
|
||||
include ':model'
|
||||
|
||||
include ':net:ssl'
|
||||
include ':net:sync:gpoddernet'
|
||||
include ':net:sync:model'
|
||||
|
||||
include ':ui:app-start-intent'
|
||||
include ':ui:common'
|
||||
include ':ui:png-icons'
|
||||
|
|
Loading…
Reference in New Issue