Added support for podlove alternate feeds

http://podlove.org/alternate-feeds/
This commit is contained in:
daniel oeh 2014-05-25 16:45:54 +02:00
parent dbff918e3a
commit 8a2332f853
8 changed files with 186 additions and 85 deletions

View File

@ -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>

View File

@ -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);
}

View File

@ -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) {
}

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);