mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-18 07:23:08 +00:00
DS-528 RSS feed to support iTunes Podcast
git-svn-id: http://scm.dspace.org/svn/repo/dspace/trunk@6531 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
@@ -272,6 +272,11 @@
|
||||
<artifactId>contiperf</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.rometools</groupId>
|
||||
<artifactId>rome-modules</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@@ -9,13 +9,16 @@ package org.dspace.app.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import org.dspace.content.Bitstream;
|
||||
@@ -25,6 +28,7 @@ import org.dspace.content.DCDate;
|
||||
import org.dspace.content.DCValue;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataSchema;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.handle.HandleManager;
|
||||
@@ -33,6 +37,8 @@ import com.sun.syndication.feed.synd.SyndFeed;
|
||||
import com.sun.syndication.feed.synd.SyndFeedImpl;
|
||||
import com.sun.syndication.feed.synd.SyndEntry;
|
||||
import com.sun.syndication.feed.synd.SyndEntryImpl;
|
||||
import com.sun.syndication.feed.synd.SyndEnclosure;
|
||||
import com.sun.syndication.feed.synd.SyndEnclosureImpl;
|
||||
import com.sun.syndication.feed.synd.SyndImage;
|
||||
import com.sun.syndication.feed.synd.SyndImageImpl;
|
||||
import com.sun.syndication.feed.synd.SyndPerson;
|
||||
@@ -42,10 +48,13 @@ import com.sun.syndication.feed.synd.SyndContentImpl;
|
||||
import com.sun.syndication.feed.module.DCModuleImpl;
|
||||
import com.sun.syndication.feed.module.DCModule;
|
||||
import com.sun.syndication.feed.module.Module;
|
||||
import com.sun.syndication.feed.module.itunes.*;
|
||||
import com.sun.syndication.feed.module.itunes.types.Duration;
|
||||
import com.sun.syndication.io.SyndFeedOutput;
|
||||
import com.sun.syndication.io.FeedException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.Bundle;
|
||||
|
||||
/**
|
||||
* Invoke ROME library to assemble a generic model of a syndication
|
||||
@@ -80,6 +89,7 @@ public class SyndicationFeed
|
||||
private static String defaultAuthorField = "dc.contributor.author";
|
||||
private static String defaultDateField = "dc.date.issued";
|
||||
private static String defaultDescriptionFields = "dc.description.abstract, dc.description, dc.title.alternative, dc.title";
|
||||
private static String defaultExternalMedia = "dc.source.uri";
|
||||
|
||||
// metadata field for Item title in entry:
|
||||
private static String titleField =
|
||||
@@ -96,6 +106,9 @@ public class SyndicationFeed
|
||||
private static String authorField =
|
||||
getDefaultedConfiguration("webui.feed.item.author", defaultAuthorField);
|
||||
|
||||
// metadata field for Item external media source url
|
||||
private static String sourceField = getDefaultedConfiguration("webui.feed.item.sourceuri", defaultExternalMedia);
|
||||
|
||||
// metadata field for Item dc:creator field in entry's DCModule (no default)
|
||||
private static String dcCreatorField = ConfigurationManager.getProperty("webui.feed.item.dc.creator");
|
||||
|
||||
@@ -115,6 +128,8 @@ public class SyndicationFeed
|
||||
// affects Bitstream retrieval URL and I18N keys
|
||||
private String uiType = null;
|
||||
|
||||
private HttpServletRequest request = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param ui either "xmlui" or "jspui"
|
||||
@@ -145,6 +160,8 @@ public class SyndicationFeed
|
||||
String logoURL = null;
|
||||
String objectURL = null;
|
||||
String defaultTitle = null;
|
||||
boolean podcastFeed = false;
|
||||
this.request = request;
|
||||
|
||||
// dso is null for the whole site, or a search without scope
|
||||
if (dso == null)
|
||||
@@ -163,6 +180,10 @@ public class SyndicationFeed
|
||||
defaultTitle = col.getMetadata("name");
|
||||
feed.setDescription(col.getMetadata("short_description"));
|
||||
logo = col.getLogo();
|
||||
String cols = ConfigurationManager.getProperty("webui.feed.podcast.collections");
|
||||
if(cols != null && cols.length() > 1 && cols.contains(col.getHandle()) ) {
|
||||
podcastFeed = true;
|
||||
}
|
||||
}
|
||||
else if (dso.getType() == Constants.COMMUNITY)
|
||||
{
|
||||
@@ -170,6 +191,10 @@ public class SyndicationFeed
|
||||
defaultTitle = comm.getMetadata("name");
|
||||
feed.setDescription(comm.getMetadata("short_description"));
|
||||
logo = comm.getLogo();
|
||||
String comms = ConfigurationManager.getProperty("webui.feed.podcast.communities");
|
||||
if(comms != null && comms.length() > 1 && comms.contains(comm.getHandle()) ){
|
||||
podcastFeed = true;
|
||||
}
|
||||
}
|
||||
objectURL = resolveURL(request, dso);
|
||||
if (logo != null)
|
||||
@@ -190,7 +215,11 @@ public class SyndicationFeed
|
||||
// be contained in the rdf. Not all RSS-viewers show this logo.
|
||||
SyndImage image = new SyndImageImpl();
|
||||
image.setLink(objectURL);
|
||||
image.setTitle(localize(labels, MSG_LOGO_TITLE));
|
||||
if (StringUtils.isNotBlank(feed.getTitle())) {
|
||||
image.setTitle(feed.getTitle());
|
||||
} else {
|
||||
image.setTitle(localize(labels, MSG_LOGO_TITLE));
|
||||
}
|
||||
image.setUrl(logoURL);
|
||||
feed.setImage(image);
|
||||
}
|
||||
@@ -328,6 +357,79 @@ public class SyndicationFeed
|
||||
}
|
||||
entry.getModules().add(dc);
|
||||
}
|
||||
|
||||
//iTunes Podcast Support - START
|
||||
if (podcastFeed)
|
||||
{
|
||||
// Add enclosure(s)
|
||||
List<SyndEnclosure> enclosures = new ArrayList();
|
||||
try {
|
||||
Bundle[] bunds = item.getBundles("ORIGINAL");
|
||||
if (bunds[0] != null) {
|
||||
Bitstream[] bits = bunds[0].getBitstreams();
|
||||
for (int i = 0; (i < bits.length); i++) {
|
||||
String mime = bits[i].getFormat().getMIMEType();
|
||||
if(mime.contains("audio/x-mpeg")) {
|
||||
SyndEnclosure enc = new SyndEnclosureImpl();
|
||||
enc.setType(bits[i].getFormat().getMIMEType());
|
||||
enc.setLength(bits[i].getSize());
|
||||
enc.setUrl(urlOfBitstream(request, bits[i]));
|
||||
enclosures.add(enc);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Also try to add an external value from dc.identifier.other
|
||||
// We are assuming that if this is set, then it is a media file
|
||||
DCValue[] externalMedia = item.getMetadata(sourceField);
|
||||
if(externalMedia.length > 0)
|
||||
{
|
||||
for(int i = 0; i< externalMedia.length; i++)
|
||||
{
|
||||
SyndEnclosure enc = new SyndEnclosureImpl();
|
||||
enc.setType("audio/x-mpeg");
|
||||
enc.setLength(1);
|
||||
enc.setUrl(externalMedia[i].value);
|
||||
enclosures.add(enc);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
entry.setEnclosures(enclosures);
|
||||
|
||||
// Get iTunes specific fields: author, subtitle, summary, duration, keywords
|
||||
EntryInformation itunes = new EntryInformationImpl();
|
||||
|
||||
String author = getOneDC(item, authorField);
|
||||
if (author != null && author.length() > 0) {
|
||||
itunes.setAuthor(author); // <itunes:author>
|
||||
}
|
||||
|
||||
itunes.setSubtitle(title == null ? localize(labels, MSG_UNTITLED) : title); // <itunes:subtitle>
|
||||
|
||||
if (db.length() > 0) {
|
||||
itunes.setSummary(db.toString()); // <itunes:summary>
|
||||
}
|
||||
|
||||
String extent = getOneDC(item, "dc.format.extent"); // assumed that user will enter this field with length of song in seconds
|
||||
if (extent != null && extent.length() > 0) {
|
||||
extent = extent.split(" ")[0];
|
||||
Integer duration = Integer.parseInt(extent);
|
||||
itunes.setDuration(new Duration(duration)); // <itunes:duration>
|
||||
}
|
||||
|
||||
String subject = getOneDC(item, "dc.subject");
|
||||
if (subject != null && subject.length() > 0) {
|
||||
String[] subjects = new String[1];
|
||||
subjects[0] = subject;
|
||||
itunes.setKeywords(subjects); // <itunes:keywords>
|
||||
}
|
||||
|
||||
entry.getModules().add(itunes);
|
||||
}
|
||||
}
|
||||
feed.setEntries(entries);
|
||||
}
|
||||
|
@@ -1388,6 +1388,20 @@ webui.feed.item.author = dc.contributor.author
|
||||
# Must be an absolute URL, e.g.
|
||||
## webui.feed.logo.url = ${dspace.url}/themes/mysite/images/mysite-logo.png
|
||||
|
||||
# iTunes Podcast Enhanced RSS Feed Properties
|
||||
# Add all the communities / collections, separated by commas (no spaces) that should
|
||||
# have the iTunes podcast metadata added to their RSS feed.
|
||||
# Default: Disabled, No collections or communities have iTunes Podcast enhanced metadata in their feed.
|
||||
# webui.feed.podcast.collections =123456789/2,123456789/3
|
||||
# webui.feed.podcast.communities =123456789/1
|
||||
|
||||
# For the iTunes Podcast Feed, if you would like to specify an external media file,
|
||||
# not on your DSpace server to be enclosed within the entry for each item,
|
||||
# specify which metadata field will hold the URI to the external media file.
|
||||
# This is useful if you store the metadata in DSpace, and a seperate streaming server to host the media.
|
||||
# Default: dc.source.uri
|
||||
#webui.feed.item.sourceuri = dc.source.uri
|
||||
|
||||
#### OpenSearch Settings ####
|
||||
# NB: for result data formatting, OpenSearch uses Syndication Feed Settings
|
||||
# so even if Syndication Feeds are not enabled, they must be configured
|
||||
|
Reference in New Issue
Block a user