Added support for podlove alternate feeds
http://podlove.org/alternate-feeds/
This commit is contained in:
parent
dbff918e3a
commit
8a2332f853
@ -49,19 +49,35 @@
|
||||
android:focusable="false"
|
||||
/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtvDescription"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/butSubscribe"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:attr/textColorTertiary"
|
||||
android:textSize="@dimen/text_size_micro"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:layout_margin="4dp"/>
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<Spinner
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/spinnerAlternateUrls"
|
||||
android:layout_margin="4dp"
|
||||
android:textSize="@dimen/text_size_micro"
|
||||
android:textColor="?android:attr/textColorPrimary"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtvDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:attr/textColorTertiary"
|
||||
android:textSize="@dimen/text_size_micro"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:layout_margin="4dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
@ -8,10 +8,7 @@ import android.support.v4.app.NavUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.*;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.adapter.FeedItemlistDescriptionAdapter;
|
||||
import de.danoeh.antennapod.asynctask.ImageDiskCache;
|
||||
@ -22,8 +19,10 @@ import de.danoeh.antennapod.storage.DBReader;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by daniel on 24.08.13.
|
||||
@ -33,6 +32,7 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
|
||||
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED | EventDistributor.FEED_LIST_UPDATE;
|
||||
private volatile List<Feed> feeds;
|
||||
private Feed feed;
|
||||
private String selectedDownloadUrl;
|
||||
|
||||
private Button subscribeButton;
|
||||
|
||||
@ -64,11 +64,12 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showFeedInformation(final Feed feed) {
|
||||
super.showFeedInformation(feed);
|
||||
protected void showFeedInformation(final Feed feed, final Map<String, String> alternateFeedUrls) {
|
||||
super.showFeedInformation(feed, alternateFeedUrls);
|
||||
setContentView(R.layout.listview_activity);
|
||||
|
||||
this.feed = feed;
|
||||
this.selectedDownloadUrl = feed.getDownload_url();
|
||||
EventDistributor.getInstance().register(listener);
|
||||
ListView listView = (ListView) findViewById(R.id.listview);
|
||||
LayoutInflater inflater = (LayoutInflater)
|
||||
@ -82,6 +83,8 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
|
||||
TextView title = (TextView) header.findViewById(R.id.txtvTitle);
|
||||
TextView author = (TextView) header.findViewById(R.id.txtvAuthor);
|
||||
TextView description = (TextView) header.findViewById(R.id.txtvDescription);
|
||||
Spinner spAlternateUrls = (Spinner) header.findViewById(R.id.spinnerAlternateUrls);
|
||||
|
||||
subscribeButton = (Button) header.findViewById(R.id.butSubscribe);
|
||||
|
||||
if (feed.getImage() != null) {
|
||||
@ -96,8 +99,10 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
try {
|
||||
Feed f = new Feed(feed.getDownload_url(), new Date(), feed.getTitle());
|
||||
Feed f = new Feed(selectedDownloadUrl, new Date(), feed.getTitle());
|
||||
f.setPreferences(feed.getPreferences());
|
||||
DefaultOnlineFeedViewActivity.this.feed = f;
|
||||
|
||||
DownloadRequester.getInstance().downloadFeed(
|
||||
DefaultOnlineFeedViewActivity.this,
|
||||
f);
|
||||
@ -109,6 +114,40 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
|
||||
setSubscribeButtonState(feed);
|
||||
}
|
||||
});
|
||||
|
||||
if (alternateFeedUrls.isEmpty()) {
|
||||
spAlternateUrls.setVisibility(View.GONE);
|
||||
} else {
|
||||
spAlternateUrls.setVisibility(View.VISIBLE);
|
||||
|
||||
final List<String> alternateUrlsList = new ArrayList<String>();
|
||||
final List<String> alternateUrlsTitleList = new ArrayList<String>();
|
||||
|
||||
alternateUrlsList.add(feed.getDownload_url());
|
||||
alternateUrlsTitleList.add(feed.getTitle());
|
||||
|
||||
|
||||
alternateUrlsList.addAll(alternateFeedUrls.keySet());
|
||||
for (String url : alternateFeedUrls.keySet()) {
|
||||
alternateUrlsTitleList.add(alternateFeedUrls.get(url));
|
||||
}
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, alternateUrlsTitleList);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spAlternateUrls.setAdapter(adapter);
|
||||
spAlternateUrls.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
selectedDownloadUrl = alternateUrlsList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
setSubscribeButtonState(feed);
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import de.danoeh.antennapod.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.service.download.Downloader;
|
||||
import de.danoeh.antennapod.service.download.HttpDownloader;
|
||||
import de.danoeh.antennapod.syndication.handler.FeedHandler;
|
||||
import de.danoeh.antennapod.syndication.handler.FeedHandlerResult;
|
||||
import de.danoeh.antennapod.syndication.handler.UnsupportedFeedtypeException;
|
||||
import de.danoeh.antennapod.util.DownloadError;
|
||||
import de.danoeh.antennapod.util.FileNameGenerator;
|
||||
@ -35,6 +36,7 @@ import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Downloads a feed from a feed URL and parses it. Subclasses can display the
|
||||
@ -56,6 +58,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
|
||||
public static final int RESULT_ERROR = 2;
|
||||
|
||||
private Feed feed;
|
||||
private Map<String, String> alternateFeedUrls;
|
||||
private Downloader downloader;
|
||||
|
||||
@Override
|
||||
@ -211,7 +214,9 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
|
||||
boolean successful = false;
|
||||
FeedHandler handler = new FeedHandler();
|
||||
try {
|
||||
handler.parseFeed(feed);
|
||||
FeedHandlerResult result = handler.parseFeed(feed);
|
||||
feed = result.feed;
|
||||
alternateFeedUrls = result.alternateFeedUrls;
|
||||
successful = true;
|
||||
} catch (SAXException e) {
|
||||
e.printStackTrace();
|
||||
@ -235,7 +240,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showFeedInformation(feed);
|
||||
showFeedInformation(feed, alternateFeedUrls);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -266,7 +271,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
|
||||
/**
|
||||
* Called when feed parsed successfully
|
||||
*/
|
||||
protected void showFeedInformation(Feed feed) {
|
||||
protected void showFeedInformation(Feed feed, Map<String, String> alternateFeedUrls) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -847,7 +847,7 @@ public class DownloadService extends Service {
|
||||
FeedHandler feedHandler = new FeedHandler();
|
||||
|
||||
try {
|
||||
feed = feedHandler.parseFeed(feed);
|
||||
feed = feedHandler.parseFeed(feed).feed;
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.d(TAG, feed.getTitle() + " parsed");
|
||||
if (checkFeedData(feed) == false) {
|
||||
|
@ -14,7 +14,7 @@ import java.io.Reader;
|
||||
|
||||
public class FeedHandler {
|
||||
|
||||
public Feed parseFeed(Feed feed) throws SAXException, IOException,
|
||||
public FeedHandlerResult parseFeed(Feed feed) throws SAXException, IOException,
|
||||
ParserConfigurationException, UnsupportedFeedtypeException {
|
||||
TypeGetter tg = new TypeGetter();
|
||||
TypeGetter.Type type = tg.getType(feed);
|
||||
@ -29,6 +29,6 @@ public class FeedHandler {
|
||||
|
||||
saxParser.parse(inputSource, handler);
|
||||
inputStreamReader.close();
|
||||
return handler.state.feed;
|
||||
return new FeedHandlerResult(handler.state.feed, handler.state.alternateUrls);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package de.danoeh.antennapod.syndication.handler;
|
||||
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Container for results returned by the Feed parser
|
||||
*/
|
||||
public class FeedHandlerResult {
|
||||
|
||||
public Feed feed;
|
||||
public Map<String, String> alternateFeedUrls;
|
||||
|
||||
public FeedHandlerResult(Feed feed, Map<String, String> alternateFeedUrls) {
|
||||
this.feed = feed;
|
||||
this.alternateFeedUrls = alternateFeedUrls;
|
||||
}
|
||||
}
|
@ -5,9 +5,7 @@ import de.danoeh.antennapod.feed.FeedItem;
|
||||
import de.danoeh.antennapod.syndication.namespace.Namespace;
|
||||
import de.danoeh.antennapod.syndication.namespace.SyndElement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Stack;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Contains all relevant information to describe the current state of a
|
||||
@ -15,70 +13,86 @@ import java.util.Stack;
|
||||
*/
|
||||
public class HandlerState {
|
||||
|
||||
/** Feed that the Handler is currently processing. */
|
||||
protected Feed feed;
|
||||
protected ArrayList<FeedItem> items;
|
||||
protected FeedItem currentItem;
|
||||
protected Stack<SyndElement> tagstack;
|
||||
/** Namespaces that have been defined so far. */
|
||||
protected HashMap<String, Namespace> namespaces;
|
||||
protected Stack<Namespace> defaultNamespaces;
|
||||
/** Buffer for saving characters. */
|
||||
protected StringBuffer contentBuf;
|
||||
/**
|
||||
* Feed that the Handler is currently processing.
|
||||
*/
|
||||
protected Feed feed;
|
||||
/**
|
||||
* Contains links to related feeds, e.g. feeds with enclosures in other formats. The key of the map is the
|
||||
* URL of the feed, the value is the title
|
||||
*/
|
||||
protected Map<String, String> alternateUrls;
|
||||
protected ArrayList<FeedItem> items;
|
||||
protected FeedItem currentItem;
|
||||
protected Stack<SyndElement> tagstack;
|
||||
/**
|
||||
* Namespaces that have been defined so far.
|
||||
*/
|
||||
protected HashMap<String, Namespace> namespaces;
|
||||
protected Stack<Namespace> defaultNamespaces;
|
||||
/**
|
||||
* Buffer for saving characters.
|
||||
*/
|
||||
protected StringBuffer contentBuf;
|
||||
|
||||
public HandlerState(Feed feed) {
|
||||
this.feed = feed;
|
||||
items = new ArrayList<FeedItem>();
|
||||
tagstack = new Stack<SyndElement>();
|
||||
namespaces = new HashMap<String, Namespace>();
|
||||
defaultNamespaces = new Stack<Namespace>();
|
||||
}
|
||||
public HandlerState(Feed feed) {
|
||||
this.feed = feed;
|
||||
alternateUrls = new LinkedHashMap<String, String>();
|
||||
items = new ArrayList<FeedItem>();
|
||||
tagstack = new Stack<SyndElement>();
|
||||
namespaces = new HashMap<String, Namespace>();
|
||||
defaultNamespaces = new Stack<Namespace>();
|
||||
}
|
||||
|
||||
public Feed getFeed() {
|
||||
return feed;
|
||||
}
|
||||
public Feed getFeed() {
|
||||
return feed;
|
||||
}
|
||||
|
||||
public ArrayList<FeedItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
public ArrayList<FeedItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public FeedItem getCurrentItem() {
|
||||
return currentItem;
|
||||
}
|
||||
public FeedItem getCurrentItem() {
|
||||
return currentItem;
|
||||
}
|
||||
|
||||
public Stack<SyndElement> getTagstack() {
|
||||
return tagstack;
|
||||
}
|
||||
public Stack<SyndElement> getTagstack() {
|
||||
return tagstack;
|
||||
}
|
||||
|
||||
public void setFeed(Feed feed) {
|
||||
this.feed = feed;
|
||||
}
|
||||
public void setFeed(Feed feed) {
|
||||
this.feed = feed;
|
||||
}
|
||||
|
||||
public void setCurrentItem(FeedItem currentItem) {
|
||||
this.currentItem = currentItem;
|
||||
}
|
||||
public void setCurrentItem(FeedItem currentItem) {
|
||||
this.currentItem = currentItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SyndElement that comes after the top element of the tagstack.
|
||||
*/
|
||||
public SyndElement getSecondTag() {
|
||||
SyndElement top = tagstack.pop();
|
||||
SyndElement second = tagstack.peek();
|
||||
tagstack.push(top);
|
||||
return second;
|
||||
}
|
||||
/**
|
||||
* Returns the SyndElement that comes after the top element of the tagstack.
|
||||
*/
|
||||
public SyndElement getSecondTag() {
|
||||
SyndElement top = tagstack.pop();
|
||||
SyndElement second = tagstack.peek();
|
||||
tagstack.push(top);
|
||||
return second;
|
||||
}
|
||||
|
||||
public SyndElement getThirdTag() {
|
||||
SyndElement top = tagstack.pop();
|
||||
SyndElement second = tagstack.pop();
|
||||
SyndElement third = tagstack.peek();
|
||||
tagstack.push(second);
|
||||
tagstack.push(top);
|
||||
return third;
|
||||
}
|
||||
public SyndElement getThirdTag() {
|
||||
SyndElement top = tagstack.pop();
|
||||
SyndElement second = tagstack.pop();
|
||||
SyndElement third = tagstack.peek();
|
||||
tagstack.push(second);
|
||||
tagstack.push(top);
|
||||
return third;
|
||||
}
|
||||
|
||||
public StringBuffer getContentBuf() {
|
||||
return contentBuf;
|
||||
}
|
||||
public StringBuffer getContentBuf() {
|
||||
return contentBuf;
|
||||
}
|
||||
|
||||
public void addAlternateFeedUrl(String title, String url) {
|
||||
alternateUrls.put(url, title);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -92,7 +92,8 @@ public class NSAtom extends Namespace {
|
||||
.getValidMimeTypeFromUrl(href)) != null) {
|
||||
state.getCurrentItem().setMedia(
|
||||
new FeedMedia(state.getCurrentItem(), href,
|
||||
size, type));
|
||||
size, type)
|
||||
);
|
||||
}
|
||||
} else if (rel.equals(LINK_REL_PAYMENT)) {
|
||||
state.getCurrentItem().setPaymentLink(href);
|
||||
@ -101,13 +102,20 @@ public class NSAtom extends Namespace {
|
||||
if (rel == null || rel.equals(LINK_REL_ALTERNATE)) {
|
||||
String type = attributes.getValue(LINK_TYPE);
|
||||
/*
|
||||
* Use as link if a) no type-attribute is given and
|
||||
* Use as link if a) no type-attribute is given and
|
||||
* feed-object has no link yet b) type of link is
|
||||
* LINK_TYPE_HTML or LINK_TYPE_XHTML
|
||||
*/
|
||||
if ((type == null && state.getFeed().getLink() == null)
|
||||
|| (type != null && (type.equals(LINK_TYPE_HTML) || type.equals(LINK_TYPE_XHTML)))) {
|
||||
state.getFeed().setLink(href);
|
||||
} else if (type != null && (type.equals(LINK_TYPE_ATOM) || type.equals(LINK_TYPE_RSS))) {
|
||||
// treat as podlove alternate feed
|
||||
String title = attributes.getValue(LINK_TITLE);
|
||||
if (title == null) {
|
||||
title = href;
|
||||
}
|
||||
state.addAlternateFeedUrl(title, href);
|
||||
}
|
||||
} else if (rel.equals(LINK_REL_PAYMENT)) {
|
||||
state.getFeed().setPaymentLink(href);
|
||||
|
Loading…
x
Reference in New Issue
Block a user