Remove subscribed podcasts from discover / suggestions (#6269)

This commit is contained in:
GitStart 2023-01-28 16:53:21 +05:00 committed by GitHub
parent 78bce635c4
commit 73a6ff1f60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 100 additions and 78 deletions

View File

@ -14,17 +14,25 @@ import android.widget.Button;
import android.widget.GridView; import android.widget.GridView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.MaterialAutoCompleteTextView; import com.google.android.material.textfield.MaterialAutoCompleteTextView;
import com.google.android.material.textfield.TextInputLayout; 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.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 org.greenrobot.eventbus.EventBus;
import java.util.ArrayList; import java.util.ArrayList;
@ -35,20 +43,13 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; 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. * Searches iTunes store for top podcasts and displays results in a list.
*/ */
public class DiscoveryFragment extends Fragment implements Toolbar.OnMenuItemClickListener { public class DiscoveryFragment extends Fragment implements Toolbar.OnMenuItemClickListener {
private static final String TAG = "ItunesSearchFragment"; private static final String TAG = "ItunesSearchFragment";
private static final int NUM_OF_TOP_PODCASTS = 25;
private SharedPreferences prefs; private SharedPreferences prefs;
/** /**
@ -188,7 +189,11 @@ public class DiscoveryFragment extends Fragment implements Toolbar.OnMenuItemCli
} }
ItunesTopListLoader loader = new ItunesTopListLoader(getContext()); ItunesTopListLoader loader = new ItunesTopListLoader(getContext());
disposable = loader.loadToplist(country, 25).subscribe( disposable = Observable.fromCallable(() ->
loader.loadToplist(country, NUM_OF_TOP_PODCASTS, DBReader.getFeedList()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
podcasts -> { podcasts -> {
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
topList = podcasts; topList = podcasts;

View File

@ -5,7 +5,6 @@ import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import androidx.fragment.app.Fragment;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -16,20 +15,23 @@ import android.widget.Button;
import android.widget.GridView; import android.widget.GridView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.fragment.app.Fragment;
import de.danoeh.antennapod.BuildConfig; 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.R;
import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity; import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.FeedDiscoverAdapter; import de.danoeh.antennapod.adapter.FeedDiscoverAdapter;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.event.DiscoveryDefaultUpdateEvent; 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.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.ArrayList;
import java.util.List; import java.util.List;
@ -138,7 +140,10 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
return; return;
} }
disposable = loader.loadToplist(countryCode, NUM_SUGGESTIONS) disposable = Observable.fromCallable(() ->
loader.loadToplist(countryCode, NUM_SUGGESTIONS, DBReader.getFeedList()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
podcasts -> { podcasts -> {
errorView.setVisibility(View.GONE); errorView.setVisibility(View.GONE);
@ -156,7 +161,7 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
errorView.setVisibility(View.VISIBLE); errorView.setVisibility(View.VISIBLE);
discoverGridLayout.setVisibility(View.INVISIBLE); discoverGridLayout.setVisibility(View.INVISIBLE);
errorRetry.setVisibility(View.VISIBLE); errorRetry.setVisibility(View.VISIBLE);
errorRetry.setOnClickListener((listener) -> loadToplist()); errorRetry.setOnClickListener(v -> loadToplist());
}); });
} }

View File

@ -2,12 +2,8 @@ package de.danoeh.antennapod.net.discovery;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import io.reactivex.Single; import de.danoeh.antennapod.model.feed.Feed;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.CacheControl; import okhttp3.CacheControl;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
@ -18,8 +14,10 @@ import org.json.JSONObject;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class ItunesTopListLoader { public class ItunesTopListLoader {
@ -30,13 +28,14 @@ public class ItunesTopListLoader {
public static final String PREF_KEY_NEEDS_CONFIRM = "needs_confirm"; public static final String PREF_KEY_NEEDS_CONFIRM = "needs_confirm";
public static final String PREFS = "CountryRegionPrefs"; public static final String PREFS = "CountryRegionPrefs";
public static final String COUNTRY_CODE_UNSET = "99"; public static final String COUNTRY_CODE_UNSET = "99";
private static final int NUM_LOADED = 25;
public ItunesTopListLoader(Context context) { public ItunesTopListLoader(Context context) {
this.context = context; this.context = context;
} }
public Single<List<PodcastSearchResult>> loadToplist(String country, int limit) { public List<PodcastSearchResult> loadToplist(String country, int limit, List<Feed> subscribed)
return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) emitter -> { throws JSONException, IOException {
OkHttpClient client = AntennapodHttpClient.getHttpClient(); OkHttpClient client = AntennapodHttpClient.getHttpClient();
String feedString; String feedString;
String loadCountry = country; String loadCountry = country;
@ -44,25 +43,38 @@ public class ItunesTopListLoader {
loadCountry = Locale.getDefault().getCountry(); loadCountry = Locale.getDefault().getCountry();
} }
try { try {
feedString = getTopListFeed(client, loadCountry, limit); feedString = getTopListFeed(client, loadCountry);
} catch (IOException e) { } catch (IOException e) {
if (COUNTRY_CODE_UNSET.equals(country)) { if (COUNTRY_CODE_UNSET.equals(country)) {
feedString = getTopListFeed(client, "US", limit); feedString = getTopListFeed(client, "US");
} else { } else {
emitter.onError(e); throw e;
return;
} }
} }
return removeSubscribed(parseFeed(feedString), subscribed, limit);
}
List<PodcastSearchResult> podcasts = parseFeed(feedString); private static List<PodcastSearchResult> removeSubscribed(
emitter.onSuccess(podcasts); List<PodcastSearchResult> suggestedPodcasts, List<Feed> subscribedFeeds, int limit) {
}) Set<String> subscribedPodcastsSet = new HashSet<>();
.subscribeOn(Schedulers.io()) for (Feed subscribedFeed : subscribedFeeds) {
.observeOn(AndroidSchedulers.mainThread()); 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, int limit) throws IOException { private String getTopListFeed(OkHttpClient client, String country) throws IOException {
String url = "https://itunes.apple.com/%s/rss/toppodcasts/limit=" + limit + "/explicit=true/json"; String url = "https://itunes.apple.com/%s/rss/toppodcasts/limit=" + NUM_LOADED + "/explicit=true/json";
Log.d(TAG, "Feed URL " + String.format(url, country)); Log.d(TAG, "Feed URL " + String.format(url, country));
Request.Builder httpReq = new Request.Builder() Request.Builder httpReq = new Request.Builder()
.cacheControl(new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build()) .cacheControl(new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build())