Add support for direct feed urls
This commit is contained in:
parent
6a05cd6bbf
commit
ba4a0f0db0
@ -19,13 +19,18 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.readrops.app.utils.Utils;
|
import com.readrops.app.utils.Utils;
|
||||||
import com.readrops.readropslibrary.HtmlParser;
|
import com.readrops.app.utils.HtmlParser;
|
||||||
import com.readrops.readropslibrary.ParsingResult;
|
import com.readrops.readropslibrary.ParsingResult;
|
||||||
|
import com.readrops.readropslibrary.localfeed.RSSNetwork;
|
||||||
|
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
public class AddFeedDialog extends Dialog implements View.OnClickListener {
|
public class AddFeedDialog extends Dialog implements View.OnClickListener {
|
||||||
|
|
||||||
private int layoutId;
|
private int layoutId;
|
||||||
@ -96,12 +101,19 @@ public class AddFeedDialog extends Dialog implements View.OnClickListener {
|
|||||||
|
|
||||||
Executors.newSingleThreadExecutor().execute(() -> {
|
Executors.newSingleThreadExecutor().execute(() -> {
|
||||||
try {
|
try {
|
||||||
|
RSSNetwork rssApi = new RSSNetwork();
|
||||||
|
if (rssApi.isUrlFeedLink(finalUrl)) {
|
||||||
|
ParsingResult parsingResult = new ParsingResult(finalUrl, null);
|
||||||
|
handler.post(() -> ((MainActivity) getOwnerActivity()).insertNewFeed(parsingResult));
|
||||||
|
dismiss();
|
||||||
|
} else {
|
||||||
List<ParsingResult> results = HtmlParser.getFeedLink(finalUrl);
|
List<ParsingResult> results = HtmlParser.getFeedLink(finalUrl);
|
||||||
|
|
||||||
if (results.size() > 0)
|
if (results.size() > 0)
|
||||||
handler.post(() -> displayResults(results));
|
handler.post(() -> displayResults(results));
|
||||||
else
|
else
|
||||||
handler.post(() -> displayError(R.string.add_feed_no_result));
|
handler.post(() -> displayError(R.string.add_feed_no_result));
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e instanceof UnknownHostException)
|
if (e instanceof UnknownHostException)
|
||||||
handler.post(() -> displayError(R.string.add_feed_unknownhost_error));
|
handler.post(() -> displayError(R.string.add_feed_unknownhost_error));
|
||||||
|
@ -10,7 +10,7 @@ import com.readrops.app.database.ItemWithFeed;
|
|||||||
import com.readrops.app.database.entities.Feed;
|
import com.readrops.app.database.entities.Feed;
|
||||||
import com.readrops.app.database.entities.Item;
|
import com.readrops.app.database.entities.Item;
|
||||||
import com.readrops.app.utils.Utils;
|
import com.readrops.app.utils.Utils;
|
||||||
import com.readrops.readropslibrary.HtmlParser;
|
import com.readrops.app.utils.HtmlParser;
|
||||||
import com.readrops.readropslibrary.ParsingResult;
|
import com.readrops.readropslibrary.ParsingResult;
|
||||||
import com.readrops.readropslibrary.QueryCallback;
|
import com.readrops.readropslibrary.QueryCallback;
|
||||||
import com.readrops.readropslibrary.Utils.LibUtils;
|
import com.readrops.readropslibrary.Utils.LibUtils;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package com.readrops.readropslibrary;
|
package com.readrops.app.utils;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.readrops.readropslibrary.ParsingResult;
|
||||||
import com.readrops.readropslibrary.Utils.LibUtils;
|
import com.readrops.readropslibrary.Utils.LibUtils;
|
||||||
|
|
||||||
import org.jsoup.Connection;
|
import org.jsoup.Connection;
|
@ -13,7 +13,9 @@ import com.readrops.readropslibrary.localfeed.rss.RSSLink;
|
|||||||
import org.simpleframework.xml.Serializer;
|
import org.simpleframework.xml.Serializer;
|
||||||
import org.simpleframework.xml.core.Persister;
|
import org.simpleframework.xml.core.Persister;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -42,6 +44,40 @@ public class RSSNetwork {
|
|||||||
if (callback == null)
|
if (callback == null)
|
||||||
throw new NullPointerException("Callback can't be null");
|
throw new NullPointerException("Callback can't be null");
|
||||||
|
|
||||||
|
Response response = query(url, headers);
|
||||||
|
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
String header = response.header(LibUtils.CONTENT_TYPE_HEADER);
|
||||||
|
RSSType type = getRSSType(header);
|
||||||
|
|
||||||
|
if (type == null) {
|
||||||
|
callback.onSyncFailure(new IllegalArgumentException("bad content type : " + header + "for " + url));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseFeed(response.body().byteStream(), type, response);
|
||||||
|
} else if (response.code() == 304)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
callback.onSyncFailure(new Exception("Error " + response.code() + " when requesting url " + url));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUrlFeedLink(String url) throws IOException {
|
||||||
|
Response response = query(url, new HashMap<String, String>());
|
||||||
|
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
String header = response.header(LibUtils.CONTENT_TYPE_HEADER);
|
||||||
|
RSSType type = getRSSType(header);
|
||||||
|
|
||||||
|
if (type == RSSType.RSS_UNKNOWN) {
|
||||||
|
RSSType contentType = getContentRSSType(response.body().string());
|
||||||
|
return contentType != RSSType.RSS_UNKNOWN;
|
||||||
|
} else return type != null;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response query(String url, Map<String, String> headers) throws IOException {
|
||||||
OkHttpClient okHttpClient = new OkHttpClient();
|
OkHttpClient okHttpClient = new OkHttpClient();
|
||||||
|
|
||||||
Request.Builder builder = new Request.Builder().url(url);
|
Request.Builder builder = new Request.Builder().url(url);
|
||||||
@ -51,34 +87,44 @@ public class RSSNetwork {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Request request = builder.build();
|
Request request = builder.build();
|
||||||
Response response = okHttpClient.newCall(request).execute();
|
return okHttpClient.newCall(request).execute();
|
||||||
|
}
|
||||||
|
|
||||||
if (response.isSuccessful()) {
|
private RSSType getRSSType(String contentType) {
|
||||||
Pattern pattern = Pattern.compile(RSS_CONTENT_TYPE_REGEX);
|
Pattern pattern = Pattern.compile(RSS_CONTENT_TYPE_REGEX);
|
||||||
Matcher matcher = pattern.matcher(response.header(LibUtils.CONTENT_TYPE_HEADER));
|
Matcher matcher = pattern.matcher(contentType);
|
||||||
|
|
||||||
String header;
|
String header;
|
||||||
if (matcher.find())
|
if (matcher.find())
|
||||||
header = matcher.group(0);
|
header = matcher.group(0);
|
||||||
else
|
else
|
||||||
header = response.header(LibUtils.CONTENT_TYPE_HEADER);
|
header = contentType;
|
||||||
|
|
||||||
RSSType type = getRSSType(header);
|
switch (header) {
|
||||||
if (type == null) {
|
case LibUtils.RSS_DEFAULT_CONTENT_TYPE:
|
||||||
callback.onSyncFailure(new IllegalArgumentException("bad content type : " + header + "for " + url));
|
return RSSType.RSS_2;
|
||||||
return;
|
case LibUtils.RSS_TEXT_CONTENT_TYPE:
|
||||||
|
return RSSType.RSS_UNKNOWN;
|
||||||
|
case LibUtils.RSS_APPLICATION_CONTENT_TYPE:
|
||||||
|
return RSSType.RSS_UNKNOWN;
|
||||||
|
case LibUtils.ATOM_CONTENT_TYPE:
|
||||||
|
return RSSType.RSS_ATOM;
|
||||||
|
case LibUtils.JSON_CONTENT_TYPE:
|
||||||
|
return RSSType.RSS_JSON;
|
||||||
|
case LibUtils.HTML_CONTENT_TYPE:
|
||||||
|
return RSSType.RSS_UNKNOWN;
|
||||||
|
default:
|
||||||
|
Log.d(TAG, "bad content type : " + contentType);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
parseFeed(response.body().byteStream(), type, response);
|
|
||||||
} else if (response.code() == 304)
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
callback.onSyncFailure(new Exception("Error " + response.code() + " when requesting url " + url));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse input feed
|
* Parse input feed
|
||||||
* @param stream inputStream to parse
|
* @param stream source to parse
|
||||||
* @param type rss type, important to know the format
|
* @param type rss type, important to know the feed format
|
||||||
* @param response query response
|
* @param response query response
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@ -87,12 +133,9 @@ public class RSSNetwork {
|
|||||||
Serializer serializer = new Persister();
|
Serializer serializer = new Persister();
|
||||||
|
|
||||||
if (type == RSSType.RSS_UNKNOWN) {
|
if (type == RSSType.RSS_UNKNOWN) {
|
||||||
if (Pattern.compile(RSS_2_REGEX).matcher(xml).find())
|
RSSType contentType = getContentRSSType(xml);
|
||||||
type = RSSType.RSS_2;
|
if (contentType == RSSType.RSS_UNKNOWN) {
|
||||||
else if (xml.contains("<feed xmlns=\"http://www.w3.org/2005/Atom\""))
|
callback.onSyncFailure(new Exception("Unknown content format"));
|
||||||
type = RSSType.RSS_ATOM;
|
|
||||||
else {
|
|
||||||
callback.onSyncFailure(new Exception("Unknown xml format"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,7 +143,6 @@ public class RSSNetwork {
|
|||||||
String etag = response.header(LibUtils.ETAG_HEADER);
|
String etag = response.header(LibUtils.ETAG_HEADER);
|
||||||
String lastModified = response.header(LibUtils.LAST_MODIFIED_HEADER);
|
String lastModified = response.header(LibUtils.LAST_MODIFIED_HEADER);
|
||||||
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RSS_2:
|
case RSS_2:
|
||||||
RSSFeed rssFeed = serializer.read(RSSFeed.class, xml);
|
RSSFeed rssFeed = serializer.read(RSSFeed.class, xml);
|
||||||
@ -132,30 +174,17 @@ public class RSSNetwork {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private RSSType getContentRSSType(String content) {
|
||||||
* Get the rss type according to the content-type header
|
RSSType type;
|
||||||
* @param contentType content-type header
|
|
||||||
* @return rss type according to the content-type header
|
|
||||||
*/
|
|
||||||
private RSSType getRSSType(String contentType) {
|
|
||||||
switch (contentType) {
|
|
||||||
case LibUtils.RSS_DEFAULT_CONTENT_TYPE:
|
|
||||||
return RSSType.RSS_2;
|
|
||||||
case LibUtils.RSS_TEXT_CONTENT_TYPE:
|
|
||||||
return RSSType.RSS_UNKNOWN;
|
|
||||||
case LibUtils.RSS_APPLICATION_CONTENT_TYPE:
|
|
||||||
return RSSType.RSS_UNKNOWN;
|
|
||||||
case LibUtils.ATOM_CONTENT_TYPE:
|
|
||||||
return RSSType.RSS_ATOM;
|
|
||||||
case LibUtils.JSON_CONTENT_TYPE:
|
|
||||||
return RSSType.RSS_JSON;
|
|
||||||
case LibUtils.HTML_CONTENT_TYPE:
|
|
||||||
return RSSType.RSS_UNKNOWN;
|
|
||||||
default:
|
|
||||||
Log.d(TAG, "bad content type : " + contentType);
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
if (Pattern.compile(RSS_2_REGEX).matcher(content).find())
|
||||||
|
type = RSSType.RSS_2;
|
||||||
|
else if (content.contains("<feed xmlns=\"http://www.w3.org/2005/Atom\""))
|
||||||
|
type = RSSType.RSS_ATOM;
|
||||||
|
else
|
||||||
|
type = RSSType.RSS_UNKNOWN;
|
||||||
|
|
||||||
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCallback(QueryCallback callback) {
|
public void setCallback(QueryCallback callback) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user