// Copyright 2009 Google Inc.
// Copyright 2011 NPR
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.npr.api;
import android.content.Context;
import android.util.Log;
import org.apache.http.client.ClientProtocolException;
import org.npr.android.util.NodeUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
public class Story extends ApiElement {
public static final String LOG_TAG = Story.class.getName();
private final String link;
private final String shortLink;
private final String title;
private final String subtitle;
private final String shortTitle;
private final String teaser;
private final String miniTeaser;
private final String slug;
private final String storyDate;
private final String pubDate;
private final String lastModifiedDate;
private final String keywords;
private final String priorityKeywords;
private final List<Byline> bylines;
private final List<Thumbnail> thumbnails;
private final List<Toenail> toenails;
private final List<Organization> organizations;
private final List<Audio> audios;
private final Map<String, Image> images;
private final List<RelatedLink> relatedLinks;
private final List<PullQuote> pullQuotes;
private final Text text;
private final TextWithHtml textWithHtml;
private final List<Parent> parents;
private final Layout layout;
public static class Thumbnail {
private final String medium;
public Thumbnail(String medium) {
this.medium = medium;
}
public String getMedium() {
return medium;
}
}
public static class Toenail {
@SuppressWarnings("unused")
private final String medium;
public Toenail(String medium) {
this.medium = medium;
}
}
public static class Organization {
private final String id;
private final String name;
private final String website;
public Organization(String id, String name, String website) {
this.id = id;
this.name = name;
this.website = website;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
@SuppressWarnings("unused")
public String getWebsite() {
return website;
}
}
public static class Audio {
private final String id;
private final String type;
private final String duration;
private final List<Format> formats;
public static class Format {
private final String mp3;
private final String wm;
private final String rm;
public Format(String mp3, String wm, String rm) {
this.mp3 = mp3;
this.wm = wm;
this.rm = rm;
}
public String getMp3() {
return mp3;
}
@SuppressWarnings("unused")
public String getWm() {
return wm;
}
@SuppressWarnings("unused")
public String getRm() {
return rm;
}
}
public Audio(String id, String primary, String duration, List<Format> formats) {
this.id = id;
this.type = primary;
this.duration = duration;
this.formats = formats;
}
public List<Format> getFormats() {
return formats;
}
public String getId() {
return id;
}
public String getType() {
return type;
}
public String getDuration() {
return duration;
}
}
public static class Image {
@SuppressWarnings("unused")
private final String id;
private final String type;
@SuppressWarnings("unused")
private final String width;
private final String src;
@SuppressWarnings("unused")
private final String hasBorder;
private final String caption;
@SuppressWarnings("unused")
private final String linkUrl;
private final String producer;
private final String provider;
@SuppressWarnings("unused")
private final String copyright;
public Image(String id, String type, String width, String src, String hasBorder,
String caption, String linkUrl, String producer, String provider,
String copyright) {
this.id = id;
this.type = type;
this.width = width;
this.src = src;
this.hasBorder = hasBorder;
this.caption = caption;
this.linkUrl = linkUrl;
this.producer = producer;
this.provider = provider;
this.copyright = copyright;
}
public String getSrc() {
return src;
}
public String getCaption() {
return caption;
}
public String getType() {
return type;
}
public String getAttribution() {
if (producer != null && producer.length() > 0) {
if (provider != null && provider.length() > 0) {
return producer + "/" + provider;
} else {
return producer;
}
} else if (provider != null && provider.length() > 0) {
return provider;
}
return "";
}
}
public static class RelatedLink {
@SuppressWarnings("unused")
private final String id;
@SuppressWarnings("unused")
private final String type;
@SuppressWarnings("unused")
private final String caption;
@SuppressWarnings("unused")
private final String link;
public RelatedLink(String id, String type, String caption, String link) {
this.id = id;
this.type = type;
this.caption = caption;
this.link = link;
}
}
public static class PullQuote {
@SuppressWarnings("unused")
private final String person;
@SuppressWarnings("unused")
private final String date;
public PullQuote(String person, String date) {
this.person = person;
this.date = date;
}
}
public static class Text {
private final Map<Integer, String> paragraphs;
public Text(Map<Integer, String> paragraphs) {
this.paragraphs = paragraphs;
}
@SuppressWarnings("unused")
public Map<Integer, String> getParagraphs() {
return paragraphs;
}
}
public static class TextWithHtml {
private final Map<Integer, String> paragraphs;
public TextWithHtml(Map<Integer, String> paragraphs) {
this.paragraphs = paragraphs;
}
public Map<Integer, String> getParagraphs() {
return paragraphs;
}
}
public static class Byline {
private final String name;
private final String htmlLink;
private final String apiLink;
public Byline(String name, String htmlLink, String apiLink) {
this.name = name;
this.htmlLink = htmlLink;
this.apiLink = apiLink;
}
public String getName() {
return name;
}
@SuppressWarnings("unused")
public String getHtmlLink() {
return htmlLink;
}
@SuppressWarnings("unused")
public String getApiLink() {
return apiLink;
}
}
public static class Parent {
private final String id;
private final String type;
private final boolean isPrimary;
private final String title;
@SuppressWarnings("unused")
private final String htmlLink;
private final String apiLink;
public Parent(String id, String type, boolean isPrimary, String title, String htmlLink,
String apiLink) {
this.id = id;
this.type = type;
this.isPrimary = isPrimary;
this.title = title;
this.htmlLink = htmlLink;
this.apiLink = apiLink;
}
public String getId() {
return id;
}
public String getType() {
return type;
}
public boolean isPrimary() {
return isPrimary;
}
public String getTitle() {
return title;
}
public String getApiLink() {
return apiLink;
}
}
public static class Layout {
public enum Type {text, image}
private final SortedMap<Integer, LayoutItem> items;
public Layout(SortedMap<Integer, LayoutItem> items) {
this.items = items;
}
public SortedMap<Integer, Layout.LayoutItem> getItems() {
return items;
}
public static class LayoutItem {
private final Type type;
private final String itemId;
public LayoutItem(Type type, String itemId) {
this.type = type;
this.itemId = itemId;
}
public Type getType() {
return type;
}
public String getItemId() {
return itemId;
}
}
}
public Story(String id, String link, String shortLink, String title, String subtitle,
String shortTitle, String teaser, String miniTeaser, String slug,
String storyDate, String pubDate, String lastModifiedDate, String keywords,
String priorityKeywords, List<Byline> bylines, List<Thumbnail> thumbnails,
List<Toenail> toenails, List<Organization> organizations, List<Audio> audios,
Map<String, Image> images, List<RelatedLink> relatedLinks,
List<PullQuote> pullQuotes, Text text, TextWithHtml textWithHtml,
List<Parent> parents, Layout layout) {
super(id);
this.link = link;
this.shortLink = shortLink;
this.title = title;
this.subtitle = subtitle;
this.shortTitle = shortTitle;
this.teaser = teaser;
this.miniTeaser = miniTeaser;
this.slug = slug;
this.storyDate = storyDate;
this.pubDate = pubDate;
this.lastModifiedDate = lastModifiedDate;
this.keywords = keywords;
this.priorityKeywords = priorityKeywords;
this.bylines = bylines;
this.thumbnails = thumbnails;
this.toenails = toenails;
this.organizations = organizations;
this.audios = audios;
this.images = images;
this.relatedLinks = relatedLinks;
this.pullQuotes = pullQuotes;
this.text = text;
this.textWithHtml = textWithHtml;
this.parents = parents;
this.layout = layout;
}
@SuppressWarnings("unused")
public String getLink() {
return link;
}
public String getShortLink() {
return shortLink;
}
public String getTitle() {
return title;
}
@SuppressWarnings("unused")
public String getSubtitle() {
return subtitle;
}
@SuppressWarnings("unused")
public String getShortTitle() {
return shortTitle;
}
public String getTeaser() {
return teaser;
}
@SuppressWarnings("unused")
public String getMiniTeaser() {
return miniTeaser;
}
public String getDuration() {
List<Audio> audios = getAudios();
if (audios.size() == 0) {
return null;
} else {
return audios.get(0).duration;
}
}
public String getSlug() {
return slug;
}
public String getStoryDate() {
return storyDate == null ? pubDate : storyDate;
}
@SuppressWarnings("unused")
public String getPubDate() {
return pubDate;
}
@SuppressWarnings("unused")
public String getLastModifiedDate() {
return lastModifiedDate;
}
@SuppressWarnings("unused")
public String getKeywords() {
return keywords;
}
@SuppressWarnings("unused")
public String getPriorityKeywords() {
return priorityKeywords;
}
public List<Byline> getBylines() {
return bylines;
}
public List<Thumbnail> getThumbnails() {
return thumbnails;
}
@SuppressWarnings("unused")
public List<Toenail> getToenails() {
return toenails;
}
public List<Organization> getOrganizations() {
return organizations;
}
public List<Audio> getAudios() {
return audios;
}
public Map<String, Image> getImages() {
return images;
}
@SuppressWarnings("unused")
public List<RelatedLink> getRelatedLinks() {
return relatedLinks;
}
@SuppressWarnings("unused")
public List<PullQuote> getPullQuotes() {
return pullQuotes;
}
public Text getText() {
return text;
}
public TextWithHtml getTextWithHtml() {
return textWithHtml;
}
@Override
public String toString() {
return title;
}
public List<Parent> getParents() {
return parents;
}
public Layout getLayout() {
return layout;
}
public static class StoryBuilder {
private final String id;
private String link;
private String shortLink;
private String title;
private String subtitle;
private String shortTitle;
private String teaser;
private String miniTeaser;
private String slug;
private String storyDate;
private String pubDate;
private String lastModifiedDate;
private String keywords;
private String priorityKeywords;
private final List<Byline> bylines = new ArrayList<Byline>();
private final List<Thumbnail> thumbnails = new ArrayList<Thumbnail>();
private final List<Toenail> toenails = new ArrayList<Toenail>();
private final List<Organization> organizations = new ArrayList<Organization>();
private final List<Audio> audios = new ArrayList<Audio>();
private final Map<String, Image> images = new HashMap<String, Image>();
private final List<RelatedLink> relatedLinks = new ArrayList<RelatedLink>();
private final List<PullQuote> pullQuotes = new ArrayList<PullQuote>();
private Text text;
private TextWithHtml textWithHtml;
private final List<Parent> parents = new ArrayList<Parent>();
private Layout layout;
public StoryBuilder(String id) {
this.id = id;
}
public StoryBuilder withLink(String link, String type) {
if (type.equals("html")) {
this.link = link;
} else if (type.equals("api")) {
} else if (type.equals("short")) {
this.shortLink = link;
}
return this;
}
public StoryBuilder withTitle(String title) {
this.title = title;
return this;
}
@SuppressWarnings("unused")
public StoryBuilder withSubtitle(String subtitle) {
this.subtitle = subtitle;
return this;
}
@SuppressWarnings("unused")
public StoryBuilder withShortTitle(String shortTitle) {
this.shortTitle = shortTitle;
return this;
}
public StoryBuilder withTeaser(String teaser) {
this.teaser = teaser;
return this;
}
public StoryBuilder withMiniTeaser(String miniTeaser) {
this.miniTeaser = miniTeaser;
return this;
}
public StoryBuilder withSlug(String slug) {
this.slug = slug;
return this;
}
public StoryBuilder withStoryDate(String storyDate) {
this.storyDate = storyDate;
return this;
}
public StoryBuilder withPubDate(String pubDate) {
this.pubDate = pubDate;
return this;
}
@SuppressWarnings("unused")
public StoryBuilder withLastModifiedDate(String lastModifiedDate) {
this.lastModifiedDate = lastModifiedDate;
return this;
}
@SuppressWarnings("unused")
public StoryBuilder withKeywords(String keywords) {
this.keywords = keywords;
return this;
}
@SuppressWarnings("unused")
public StoryBuilder withPriorityKeywords(String priorityKeywords) {
this.priorityKeywords = priorityKeywords;
return this;
}
public StoryBuilder withByline(Byline byline) {
this.bylines.add(byline);
return this;
}
@SuppressWarnings("unused")
public StoryBuilder withThumbnail(Thumbnail thumbnail) {
this.thumbnails.add(thumbnail);
return this;
}
@SuppressWarnings("unused")
public StoryBuilder withToenail(Toenail toenail) {
this.toenails.add(toenail);
return this;
}
public StoryBuilder withOrganization(Organization organization) {
this.organizations.add(organization);
return this;
}
public StoryBuilder withAudio(Audio audio) {
this.audios.add(audio);
return this;
}
public StoryBuilder withImage(String id, Image image) {
this.images.put(id, image);
return this;
}
@SuppressWarnings("unused")
public StoryBuilder withRelatedLink(RelatedLink relatedLink) {
this.relatedLinks.add(relatedLink);
return this;
}
@SuppressWarnings("unused")
public StoryBuilder withPullQuote(PullQuote pullQuote) {
this.pullQuotes.add(pullQuote);
return this;
}
public StoryBuilder withText(Text text) {
this.text = text;
return this;
}
public StoryBuilder withTextWithHtml(TextWithHtml textWithHtml) {
this.textWithHtml = textWithHtml;
return this;
}
public StoryBuilder withParent(Parent parent) {
this.parents.add(parent);
return this;
}
public StoryBuilder withLayout(Layout layout) {
this.layout = layout;
return this;
}
public Story build() {
return new Story(id, link, shortLink, title, subtitle, shortTitle,
teaser, miniTeaser, slug, storyDate, pubDate, lastModifiedDate,
keywords, priorityKeywords, bylines, thumbnails, toenails,
organizations, audios, images, relatedLinks, pullQuotes, text,
textWithHtml, parents, layout);
}
}
public static class StoryFactory {
public static List<Story> parseStories(Node rootNode) {
if (rootNode.getNodeName().equals("rss")) {
return parseRssStoryList(rootNode);
}
return parseNprmlStoryList(rootNode);
}
private static List<Story> parseRssStoryList(Node rootNode) {
List<Story> result = new ArrayList<Story>();
for (Node channelNode : new IterableNodeList(rootNode.getChildNodes())) {
if (channelNode.getNodeName().equals("channel")) {
for (Node childNode :
new IterableNodeList(channelNode.getChildNodes())) {
Story story = createRssStory(childNode);
if (story != null) {
result.add(story);
}
}
}
}
return result;
}
private static List<Story> parseNprmlStoryList(Node rootNode) {
LinkedList<Story> result = new LinkedList<Story>();
NodeList childNodes = rootNode.getChildNodes();
for (Node node : new IterableNodeList(childNodes)) {
if (node.getNodeName().equals("list")) {
for (Node storyNode : new IterableNodeList(node.getChildNodes())) {
Story story = createNprmlStory(storyNode);
if (story != null) {
result.add(story);
}
}
}
}
return result;
}
private static Story createRssStory(Node node) {
if (!node.getNodeName().equals("item") ||
!node.hasChildNodes()) {
return null;
}
StoryBuilder sb = new StoryBuilder(
// Create an ID because podcast items don't have any
Long.toHexString(new Date().getTime() * 1000 + (long) (Math.random()
* 1000))
);
try {
for (Node n : new IterableNodeList(node.getChildNodes())) {
String nodeName = n.getNodeName();
if (nodeName.equals("title")) {
sb.withTitle(NodeUtils.getTextContent(n));
} else if (nodeName.equals("link")) {
sb.withLink(NodeUtils.getTextContent(n), "html");
} else if (nodeName.equals("description")) {
sb.withTeaser(NodeUtils.getTextContent(n));
} else if (nodeName.equals("pubDate")) {
sb.withPubDate(NodeUtils.getTextContent(n));
} else if (nodeName.equals("enclosure")) {
sb.withAudio(parsePodcastEnclosure(n));
}
}
} catch (Exception e) {
Log.e(LOG_TAG, "", e);
return null;
}
return sb.build();
}
private static Story createNprmlStory(Node node) {
if (!node.getNodeName().equals("story") ||
!node.hasChildNodes()) {
return null;
}
StoryBuilder sb = new StoryBuilder(node.getAttributes().getNamedItem(
"id").getNodeValue());
try {
Log.d(LOG_TAG, "parsing story " + sb.id);
for (Node n : new IterableNodeList(node.getChildNodes())) {
String nodeName = n.getNodeName();
Node nodeChild = n.getChildNodes().item(0);
if (nodeChild == null) {
continue;
}
if (nodeName.equals("title")) {
sb.withTitle(NodeUtils.getTextContent(n));
} else if (nodeName.equals("link")) {
Attr typeAttr = (Attr) n.getAttributes().getNamedItem("type");
sb.withLink(NodeUtils.getTextContent(n), typeAttr.getValue());
} else if (nodeName.equals("teaser")) {
sb.withTeaser(NodeUtils.getTextContent(n));
} else if (nodeName.equals("miniTeaser")) {
sb.withMiniTeaser(NodeUtils.getTextContent(n));
} else if (nodeName.equals("slug")) {
sb.withSlug(NodeUtils.getTextContent(n));
} else if (nodeName.equals("storyDate")) {
sb.withStoryDate(NodeUtils.getTextContent(n));
} else if (nodeName.equals("pubDate")) {
sb.withPubDate(NodeUtils.getTextContent(n));
} else if (nodeName.equals("byline")) {
sb.withByline(parseByline(n));
} else if (nodeName.equals("textWithHtml")) {
sb.withTextWithHtml(new TextWithHtml(parseParagraphs(n)));
} else if (nodeName.equals("text")) {
sb.withText(new Text(parseParagraphs(n)));
} else if (nodeName.equals("audio")) {
sb.withAudio(parseAudio(n));
} else if (nodeName.equals("image")) {
Image image = parseImage(n);
sb.withImage(image.id, image);
} else if (nodeName.equals("organization")) {
sb.withOrganization(parseOrganization(n));
} else if (nodeName.equals("parent")) {
sb.withParent(parseParent(n));
} else if (nodeName.equals("layout")) {
sb.withLayout(new Layout(parseLayout(n)));
}
}
} catch (Exception e) {
Log.e(LOG_TAG, "", e);
return null;
}
return sb.build();
}
private static SortedMap<Integer, Layout.LayoutItem> parseLayout(Node node) {
SortedMap<Integer, Layout.LayoutItem> layout = new TreeMap<Integer, Layout.LayoutItem>();
for (Node layoutChild : new IterableNodeList(node.getChildNodes())) {
if (layoutChild.getNodeName().equals("storytext")) {
for (Node layoutNode : new IterableNodeList(layoutChild.getChildNodes())) {
String layoutType = layoutNode.getNodeName();
if (layoutType.equals("text")) {
Integer num = layout.size();
Attr numAttr = (Attr) layoutNode.getAttributes().getNamedItem("num");
if (numAttr != null) {
try {
num = Integer.parseInt(numAttr.getValue());
} catch (NumberFormatException e) {
// Leave as the last item if parse fails
}
}
String paragraphNum;
Attr paragraphNumAttr =
(Attr) layoutNode.getAttributes().getNamedItem("paragraphNum");
if (paragraphNumAttr != null) {
paragraphNum = paragraphNumAttr.getValue();
} else {
paragraphNum = num.toString();
}
Layout.LayoutItem item =
new Layout.LayoutItem(Layout.Type.text, paragraphNum);
layout.put(num, item);
} else if (layoutType.equals("image")) {
Integer num = layout.size();
Attr numAttr = (Attr) layoutNode.getAttributes().getNamedItem("num");
if (numAttr != null) {
try {
num = Integer.parseInt(numAttr.getValue());
} catch (NumberFormatException e) {
// Leave as the last item if parse fails
}
}
Attr refIdAttr = (Attr) layoutNode.getAttributes().getNamedItem("refId");
if (refIdAttr != null) {
Layout.LayoutItem item =
new Layout.LayoutItem(Layout.Type.image, refIdAttr.getValue());
layout.put(num, item);
}
}
}
}
}
return layout;
}
private static Parent parseParent(Node node) {
String id = null, type = null, title = null, apiLink = null;
boolean isPrimary = false;
Attr idAttr = (Attr) node.getAttributes().getNamedItem("id");
if (idAttr != null) {
id = idAttr.getValue();
}
Attr typeAttr = (Attr) node.getAttributes().getNamedItem("type");
if (typeAttr != null) {
type = typeAttr.getValue();
if (type.equals("primaryTopic")) {
isPrimary = true;
}
}
for (Node n : new IterableNodeList(node.getChildNodes())) {
String nodeName = n.getNodeName();
if (nodeName.equals("title")) {
title = NodeUtils.getTextContent(n);
} else if (nodeName.equals("link")) {
Attr childTypeAttr = (Attr) n.getAttributes().getNamedItem("type");
if (childTypeAttr != null && childTypeAttr.getValue().equals("api")) {
apiLink = NodeUtils.getTextContent(n);
}
}
}
return new Parent(id, type, isPrimary, title, null, apiLink);
}
private static Organization parseOrganization(Node node) {
String id = null, name = null, website = null;
Attr idAttr = (Attr) node.getAttributes().getNamedItem("id");
if (idAttr != null) {
id = idAttr.getValue();
}
for (Node n : new IterableNodeList(node.getChildNodes())) {
String nodeName = n.getNodeName();
if (nodeName.equals("name")) {
name = NodeUtils.getTextContent(n);
} else if (nodeName.equals("website")) {
website = NodeUtils.getTextContent(n);
}
}
return new Organization(id, name, website);
}
private static Byline parseByline(Node node) {
String name = null, htmlLink = null, apiLink = null;
for (Node n : new IterableNodeList(node.getChildNodes())) {
String nodeName = n.getNodeName();
if (nodeName.equals("name")) {
name = NodeUtils.getTextContent(n);
} else if (nodeName.equals("link")) {
Attr typeAttr = (Attr) n.getAttributes().getNamedItem("type");
if (typeAttr != null) {
String type = typeAttr.getValue();
if (type.equals("api")) {
apiLink = NodeUtils.getTextContent(n);
} else if (type.equals("html")) {
htmlLink = NodeUtils.getTextContent(n);
}
}
}
}
return new Byline(name, htmlLink, apiLink);
}
private static Image parseImage(Node node) {
// Attributes
String id = null, type = null, width = null, src = null, hasBorder = null;
// Sub-elements
String caption = null, linkUrl = null, producer = null, provider = null, copyright = null;
Attr idAttr = (Attr) node.getAttributes().getNamedItem("id");
if (idAttr != null) {
id = idAttr.getValue();
}
Attr typeAttr = (Attr) node.getAttributes().getNamedItem("type");
if (typeAttr != null) {
type = typeAttr.getValue();
}
for (Node n : new IterableNodeList(node.getChildNodes())) {
if (n.getNodeName().equals("crop")) {
Attr cropTypeAttr = (Attr) n.getAttributes().getNamedItem("type");
if (cropTypeAttr != null && cropTypeAttr.getValue().equals("square")) {
Attr srcAttr = (Attr) n.getAttributes().getNamedItem("src");
if (srcAttr != null) {
src = srcAttr.getValue();
break;
}
}
} else if (n.getNodeName().equals("caption")) {
caption = NodeUtils.getTextContent(n);
} else if (n.getNodeName().equals("producer")) {
producer = NodeUtils.getTextContent(n);
} else if (n.getNodeName().equals("provider")) {
provider = NodeUtils.getTextContent(n);
}
}
if (src == null) {
Attr srcAttr = (Attr) node.getAttributes().getNamedItem("src");
if (srcAttr != null) {
src = srcAttr.getValue();
}
}
try {
src = src.replaceAll("&s=[0-9]+", "");
src = src.concat("&s=13");
} catch (NullPointerException e) {
Log.e(LOG_TAG, "Error replacing size in story image parsing");
}
return new Image(id, type, width, src, hasBorder, caption, linkUrl, producer,
provider, copyright);
}
private static Map<Integer, String> parseParagraphs(Node node) {
// Presumably, the paragraphs will be in order. However, in the rare case
// that they are not, we can order them according to the number attribute.
SortedMap<Integer, String> paragraphMap = new TreeMap<Integer, String>();
for (Node n : new IterableNodeList(node.getChildNodes())) {
String nodeName = n.getNodeName();
Node nodeChild = n.getChildNodes().item(0);
if (nodeName.equals("paragraph")) {
String paragraph = nodeChild == null ? "" : NodeUtils.getTextContent(n);
Attr numAttr = (Attr) n.getAttributes().getNamedItem("num");
if (numAttr != null) {
int num = Integer.parseInt(numAttr.getValue());
paragraphMap.put(num, paragraph);
}
}
}
return paragraphMap;
}
private static Audio parseAudio(Node node) {
String id = null, primary = null, duration = null;
List<Audio.Format> formats = new ArrayList<Audio.Format>();
Attr typeAttr = (Attr) node.getAttributes().getNamedItem("type");
if (typeAttr != null) {
primary = typeAttr.getValue();
}
for (Node n : new IterableNodeList(node.getChildNodes())) {
String nodeName = n.getNodeName();
if (nodeName.equals("duration")) {
duration = NodeUtils.getTextContent(n);
} else if (nodeName.equals("format")) {
formats.add(parseFormat(n));
}
}
return new Audio(id, primary, duration, formats);
}
private static Audio parsePodcastEnclosure(Node node) {
String url = null, duration = null;
List<Audio.Format> formats = new ArrayList<Audio.Format>();
Attr urlAttr = (Attr) node.getAttributes().getNamedItem("url");
if (urlAttr != null) {
url = urlAttr.getValue();
}
Attr durationAttr = (Attr) node.getAttributes().getNamedItem("duration");
if (durationAttr != null) {
duration = durationAttr.getValue();
}
Attr typeAttr = (Attr) node.getAttributes().getNamedItem("type");
if (typeAttr != null && url != null) {
if (typeAttr.getValue().equals("audio/mpeg")) {
formats.add(new Audio.Format(url, null, null));
}
}
return new Audio(null, "primary", duration, formats);
}
private static Audio.Format parseFormat(Node node) {
String mp3 = null, wm = null, rm = null;
for (Node n : new IterableNodeList(node.getChildNodes())) {
String nodeName = n.getNodeName();
if (nodeName.equals("mp3")) {
mp3 = NodeUtils.getTextContent(n);
} else if (nodeName.equals("wm")) {
wm = NodeUtils.getTextContent(n);
} else if (nodeName.equals("rm")) {
rm = NodeUtils.getTextContent(n);
}
}
return new Audio.Format(mp3, wm, rm);
}
public static Story downloadStory(String storyId, Context context) {
Log.d(LOG_TAG, "downloading story: " + storyId);
Map<String, String> params = new HashMap<String, String>();
params.put(ApiConstants.PARAM_ID, storyId);
String url =
ApiConstants.instance().createUrl(ApiConstants.STORY_PATH, params);
Node stories = null;
try {
stories = new Client(url, context).execute();
} catch (ClientProtocolException e) {
Log.e(LOG_TAG, "", e);
} catch (IOException e) {
Log.e(LOG_TAG, "", e);
} catch (SAXException e) {
Log.e(LOG_TAG, "", e);
} catch (ParserConfigurationException e) {
Log.e(LOG_TAG, "", e);
}
if (stories == null) {
return null;
}
Log.d(LOG_TAG, "node " + stories.getNodeName() + " "
+ stories.getChildNodes().getLength());
List<Story> result = parseStories(stories);
return result.size() > 0 ? result.get(0) : null;
}
}
public Audio getPlayable() {
for (Audio a : getAudios()) {
if (a.getType().equals("primary")) {
return a;
}
}
return null;
}
public String getPlayableUrl() {
String url = null;
Story.Audio a = getPlayable();
if (a != null) {
for (Story.Audio.Format f : a.getFormats()) {
if ((url = f.getMp3()) != null) {
break;
}
}
}
return url;
}
}