Remove subscribed podcasts from discover / suggestions (#6269)
This commit is contained in:
parent
78bce635c4
commit
73a6ff1f60
|
@ -14,17 +14,25 @@ import android.widget.Button;
|
|||
import android.widget.GridView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.textfield.MaterialAutoCompleteTextView;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
|
||||
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
|
||||
import de.danoeh.antennapod.core.BuildConfig;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.event.DiscoveryDefaultUpdateEvent;
|
||||
import de.danoeh.antennapod.net.discovery.ItunesTopListLoader;
|
||||
import de.danoeh.antennapod.net.discovery.PodcastSearchResult;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -35,20 +43,13 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
|
||||
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
|
||||
import de.danoeh.antennapod.event.DiscoveryDefaultUpdateEvent;
|
||||
import de.danoeh.antennapod.net.discovery.ItunesTopListLoader;
|
||||
import de.danoeh.antennapod.net.discovery.PodcastSearchResult;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* Searches iTunes store for top podcasts and displays results in a list.
|
||||
*/
|
||||
public class DiscoveryFragment extends Fragment implements Toolbar.OnMenuItemClickListener {
|
||||
|
||||
private static final String TAG = "ItunesSearchFragment";
|
||||
private static final int NUM_OF_TOP_PODCASTS = 25;
|
||||
private SharedPreferences prefs;
|
||||
|
||||
/**
|
||||
|
@ -188,19 +189,23 @@ public class DiscoveryFragment extends Fragment implements Toolbar.OnMenuItemCli
|
|||
}
|
||||
|
||||
ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
|
||||
disposable = loader.loadToplist(country, 25).subscribe(
|
||||
podcasts -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
topList = podcasts;
|
||||
updateData(topList);
|
||||
}, error -> {
|
||||
Log.e(TAG, Log.getStackTraceString(error));
|
||||
progressBar.setVisibility(View.GONE);
|
||||
txtvError.setText(error.getMessage());
|
||||
txtvError.setVisibility(View.VISIBLE);
|
||||
butRetry.setOnClickListener(v -> loadToplist(country));
|
||||
butRetry.setVisibility(View.VISIBLE);
|
||||
});
|
||||
disposable = Observable.fromCallable(() ->
|
||||
loader.loadToplist(country, NUM_OF_TOP_PODCASTS, DBReader.getFeedList()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
podcasts -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
topList = podcasts;
|
||||
updateData(topList);
|
||||
}, error -> {
|
||||
Log.e(TAG, Log.getStackTraceString(error));
|
||||
progressBar.setVisibility(View.GONE);
|
||||
txtvError.setText(error.getMessage());
|
||||
txtvError.setVisibility(View.VISIBLE);
|
||||
butRetry.setOnClickListener(v -> loadToplist(country));
|
||||
butRetry.setVisibility(View.VISIBLE);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.content.SharedPreferences;
|
|||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -16,20 +15,23 @@ import android.widget.Button;
|
|||
import android.widget.GridView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import de.danoeh.antennapod.BuildConfig;
|
||||
import de.danoeh.antennapod.net.discovery.ItunesTopListLoader;
|
||||
import de.danoeh.antennapod.net.discovery.PodcastSearchResult;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
|
||||
import de.danoeh.antennapod.adapter.FeedDiscoverAdapter;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.event.DiscoveryDefaultUpdateEvent;
|
||||
import de.danoeh.antennapod.net.discovery.ItunesTopListLoader;
|
||||
import de.danoeh.antennapod.net.discovery.PodcastSearchResult;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -138,26 +140,29 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
|
|||
return;
|
||||
}
|
||||
|
||||
disposable = loader.loadToplist(countryCode, NUM_SUGGESTIONS)
|
||||
disposable = Observable.fromCallable(() ->
|
||||
loader.loadToplist(countryCode, NUM_SUGGESTIONS, DBReader.getFeedList()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
podcasts -> {
|
||||
errorView.setVisibility(View.GONE);
|
||||
if (podcasts.size() == 0) {
|
||||
errorTextView.setText(getResources().getText(R.string.search_status_no_results));
|
||||
errorView.setVisibility(View.VISIBLE);
|
||||
discoverGridLayout.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
discoverGridLayout.setVisibility(View.VISIBLE);
|
||||
adapter.updateData(podcasts);
|
||||
}
|
||||
}, error -> {
|
||||
Log.e(TAG, Log.getStackTraceString(error));
|
||||
errorTextView.setText(error.getLocalizedMessage());
|
||||
podcasts -> {
|
||||
errorView.setVisibility(View.GONE);
|
||||
if (podcasts.size() == 0) {
|
||||
errorTextView.setText(getResources().getText(R.string.search_status_no_results));
|
||||
errorView.setVisibility(View.VISIBLE);
|
||||
discoverGridLayout.setVisibility(View.INVISIBLE);
|
||||
errorRetry.setVisibility(View.VISIBLE);
|
||||
errorRetry.setOnClickListener((listener) -> loadToplist());
|
||||
});
|
||||
} else {
|
||||
discoverGridLayout.setVisibility(View.VISIBLE);
|
||||
adapter.updateData(podcasts);
|
||||
}
|
||||
}, error -> {
|
||||
Log.e(TAG, Log.getStackTraceString(error));
|
||||
errorTextView.setText(error.getLocalizedMessage());
|
||||
errorView.setVisibility(View.VISIBLE);
|
||||
discoverGridLayout.setVisibility(View.INVISIBLE);
|
||||
errorRetry.setVisibility(View.VISIBLE);
|
||||
errorRetry.setOnClickListener(v -> loadToplist());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,12 +2,8 @@ package de.danoeh.antennapod.net.discovery;
|
|||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.SingleOnSubscribe;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import okhttp3.CacheControl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
|
@ -18,8 +14,10 @@ import org.json.JSONObject;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ItunesTopListLoader {
|
||||
|
@ -30,39 +28,53 @@ public class ItunesTopListLoader {
|
|||
public static final String PREF_KEY_NEEDS_CONFIRM = "needs_confirm";
|
||||
public static final String PREFS = "CountryRegionPrefs";
|
||||
public static final String COUNTRY_CODE_UNSET = "99";
|
||||
private static final int NUM_LOADED = 25;
|
||||
|
||||
public ItunesTopListLoader(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Single<List<PodcastSearchResult>> loadToplist(String country, int limit) {
|
||||
return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) emitter -> {
|
||||
OkHttpClient client = AntennapodHttpClient.getHttpClient();
|
||||
String feedString;
|
||||
String loadCountry = country;
|
||||
public List<PodcastSearchResult> loadToplist(String country, int limit, List<Feed> subscribed)
|
||||
throws JSONException, IOException {
|
||||
OkHttpClient client = AntennapodHttpClient.getHttpClient();
|
||||
String feedString;
|
||||
String loadCountry = country;
|
||||
if (COUNTRY_CODE_UNSET.equals(country)) {
|
||||
loadCountry = Locale.getDefault().getCountry();
|
||||
}
|
||||
try {
|
||||
feedString = getTopListFeed(client, loadCountry);
|
||||
} catch (IOException e) {
|
||||
if (COUNTRY_CODE_UNSET.equals(country)) {
|
||||
loadCountry = Locale.getDefault().getCountry();
|
||||
feedString = getTopListFeed(client, "US");
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
feedString = getTopListFeed(client, loadCountry, limit);
|
||||
} catch (IOException e) {
|
||||
if (COUNTRY_CODE_UNSET.equals(country)) {
|
||||
feedString = getTopListFeed(client, "US", limit);
|
||||
} else {
|
||||
emitter.onError(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
List<PodcastSearchResult> podcasts = parseFeed(feedString);
|
||||
emitter.onSuccess(podcasts);
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
return removeSubscribed(parseFeed(feedString), subscribed, limit);
|
||||
}
|
||||
|
||||
private String getTopListFeed(OkHttpClient client, String country, int limit) throws IOException {
|
||||
String url = "https://itunes.apple.com/%s/rss/toppodcasts/limit=" + limit + "/explicit=true/json";
|
||||
private static List<PodcastSearchResult> removeSubscribed(
|
||||
List<PodcastSearchResult> suggestedPodcasts, List<Feed> subscribedFeeds, int limit) {
|
||||
Set<String> subscribedPodcastsSet = new HashSet<>();
|
||||
for (Feed subscribedFeed : subscribedFeeds) {
|
||||
String subscribedTitle = subscribedFeed.getTitle().trim() + " - " + subscribedFeed.getAuthor().trim();
|
||||
subscribedPodcastsSet.add(subscribedTitle);
|
||||
}
|
||||
List<PodcastSearchResult> suggestedNotSubscribed = new ArrayList<>();
|
||||
for (PodcastSearchResult suggested : suggestedPodcasts) {
|
||||
if (!subscribedPodcastsSet.contains(suggested.title.trim())) {
|
||||
suggestedNotSubscribed.add(suggested);
|
||||
}
|
||||
if (suggestedNotSubscribed.size() == limit) {
|
||||
return suggestedNotSubscribed;
|
||||
}
|
||||
}
|
||||
return suggestedNotSubscribed;
|
||||
}
|
||||
|
||||
private String getTopListFeed(OkHttpClient client, String country) throws IOException {
|
||||
String url = "https://itunes.apple.com/%s/rss/toppodcasts/limit=" + NUM_LOADED + "/explicit=true/json";
|
||||
Log.d(TAG, "Feed URL " + String.format(url, country));
|
||||
Request.Builder httpReq = new Request.Builder()
|
||||
.cacheControl(new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build())
|
||||
|
|
Loading…
Reference in New Issue