mirror of
https://github.com/AntennaPod/AntennaPod.git
synced 2025-01-20 12:49:53 +01:00
Added podcastindex.org search (#4435)
This commit is contained in:
parent
e31a833361
commit
61ed58074e
@ -30,6 +30,8 @@ android {
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
buildConfigField "String", "COMMIT_HASH", ('"' + commit + '"')
|
||||
buildConfigField "String", "PODCASTINDEX_API_KEY", '"JRJPPWC6ZA7DKKTSU2R3"'
|
||||
buildConfigField "String", "PODCASTINDEX_API_SECRET", '"7$$67JtrfkSYtAncGBEaJp$v$Y9$ZJUzYVy8GuBm"'
|
||||
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
|
@ -0,0 +1,126 @@
|
||||
package de.danoeh.antennapod.discovery;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import de.danoeh.antennapod.BuildConfig;
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
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 okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class PodcastIndexPodcastSearcher implements PodcastSearcher {
|
||||
private static final String PODCASTINDEX_API_URL = "https://api.podcastindex.org/api/1.0/search/byterm?q=%s";
|
||||
|
||||
public PodcastIndexPodcastSearcher() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<List<PodcastSearchResult>> search(String query) {
|
||||
return Single.create((SingleOnSubscribe<List<PodcastSearchResult>>) subscriber -> {
|
||||
|
||||
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
calendar.clear();
|
||||
Date now = new Date();
|
||||
calendar.setTime(now);
|
||||
long secondsSinceEpoch = calendar.getTimeInMillis() / 1000L;
|
||||
String apiHeaderTime = String.valueOf(secondsSinceEpoch);
|
||||
String data4Hash = BuildConfig.PODCASTINDEX_API_KEY + BuildConfig.PODCASTINDEX_API_SECRET + apiHeaderTime;
|
||||
String hashString = sha1(data4Hash);
|
||||
|
||||
String encodedQuery;
|
||||
try {
|
||||
encodedQuery = URLEncoder.encode(query, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// this won't ever be thrown
|
||||
encodedQuery = query;
|
||||
}
|
||||
|
||||
String formattedUrl = String.format(PODCASTINDEX_API_URL, encodedQuery);
|
||||
|
||||
OkHttpClient client = AntennapodHttpClient.getHttpClient();
|
||||
Request.Builder httpReq = new Request.Builder()
|
||||
.addHeader("X-Auth-Date", apiHeaderTime)
|
||||
.addHeader("X-Auth-Key", BuildConfig.PODCASTINDEX_API_KEY)
|
||||
.addHeader("Authorization", hashString)
|
||||
.addHeader("User-Agent", ClientConfig.USER_AGENT)
|
||||
.url(formattedUrl);
|
||||
List<PodcastSearchResult> podcasts = new ArrayList<>();
|
||||
try {
|
||||
Response response = client.newCall(httpReq.build()).execute();
|
||||
|
||||
if (response.isSuccessful()) {
|
||||
String resultString = response.body().string();
|
||||
JSONObject result = new JSONObject(resultString);
|
||||
JSONArray j = result.getJSONArray("feeds");
|
||||
|
||||
for (int i = 0; i < j.length(); i++) {
|
||||
JSONObject podcastJson = j.getJSONObject(i);
|
||||
PodcastSearchResult podcast = PodcastSearchResult.fromPodcastIndex(podcastJson);
|
||||
if (podcast.feedUrl != null) {
|
||||
podcasts.add(podcast);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
subscriber.onError(new IOException(response.toString()));
|
||||
}
|
||||
} catch (IOException | JSONException e) {
|
||||
subscriber.onError(e);
|
||||
}
|
||||
subscriber.onSuccess(podcasts);
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<String> lookupUrl(String url) {
|
||||
return Single.just(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean urlNeedsLookup(String url) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Podcastindex.org";
|
||||
}
|
||||
|
||||
private static String sha1(String clearString) {
|
||||
try {
|
||||
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
|
||||
messageDigest.update(clearString.getBytes("UTF-8"));
|
||||
return toHex(messageDigest.digest());
|
||||
} catch (Exception ignored) {
|
||||
ignored.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String toHex(byte[] bytes) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
buffer.append(String.format(Locale.getDefault(), "%02x", b));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
@ -103,4 +103,12 @@ public class PodcastSearchResult {
|
||||
searchHit.getUrl(),
|
||||
searchHit.getAuthor());
|
||||
}
|
||||
|
||||
public static PodcastSearchResult fromPodcastIndex(JSONObject json) {
|
||||
String title = json.optString("title", "");
|
||||
String imageUrl = json.optString("image", null);
|
||||
String feedUrl = json.optString("url", null);
|
||||
String author = json.optString("author", null);
|
||||
return new PodcastSearchResult(title, imageUrl, feedUrl, author);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ public class PodcastSearcherRegistry {
|
||||
searchProviders.add(new SearcherInfo(new ItunesPodcastSearcher(), 1.f));
|
||||
searchProviders.add(new SearcherInfo(new FyydPodcastSearcher(), 1.f));
|
||||
searchProviders.add(new SearcherInfo(new GpodnetPodcastSearcher(), 0.0f));
|
||||
searchProviders.add(new SearcherInfo(new PodcastIndexPodcastSearcher(), 0.0f));
|
||||
}
|
||||
return searchProviders;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import de.danoeh.antennapod.activity.OpmlImportActivity;
|
||||
import de.danoeh.antennapod.discovery.CombinedSearcher;
|
||||
import de.danoeh.antennapod.discovery.FyydPodcastSearcher;
|
||||
import de.danoeh.antennapod.discovery.ItunesPodcastSearcher;
|
||||
import de.danoeh.antennapod.discovery.PodcastIndexPodcastSearcher;
|
||||
import de.danoeh.antennapod.fragment.gpodnet.GpodnetMainFragment;
|
||||
|
||||
/**
|
||||
@ -55,6 +56,8 @@ public class AddFeedFragment extends Fragment {
|
||||
-> activity.loadChildFragment(OnlineSearchFragment.newInstance(FyydPodcastSearcher.class)));
|
||||
root.findViewById(R.id.btn_search_gpodder).setOnClickListener(v
|
||||
-> activity.loadChildFragment(new GpodnetMainFragment()));
|
||||
root.findViewById(R.id.btn_search_podcastindex).setOnClickListener(v
|
||||
-> activity.loadChildFragment(OnlineSearchFragment.newInstance(PodcastIndexPodcastSearcher.class)));
|
||||
|
||||
combinedFeedSearchBox = root.findViewById(R.id.combinedFeedSearchBox);
|
||||
combinedFeedSearchBox.setOnEditorActionListener((v, actionId, event) -> {
|
||||
|
@ -142,6 +142,20 @@
|
||||
android:clickable="true"
|
||||
android:text="@string/browse_gpoddernet_label"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn_search_podcastindex"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="8dp"
|
||||
app:drawableStartCompat="?attr/action_search"
|
||||
app:drawableLeftCompat="?attr/action_search"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:clickable="true"
|
||||
android:text="@string/search_podcastindex_label"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn_opml_import"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -714,6 +714,7 @@
|
||||
<!-- Add podcast fragment -->
|
||||
<string name="search_podcast_hint">Search podcast…</string>
|
||||
<string name="search_itunes_label">Search iTunes</string>
|
||||
<string name="search_podcastindex_label">Search Podcastindex.org</string>
|
||||
<string name="search_fyyd_label">Search fyyd</string>
|
||||
<string name="advanced">Advanced</string>
|
||||
<string name="add_podcast_by_url">Add Podcast by RSS address</string>
|
||||
|
Loading…
Reference in New Issue
Block a user