From 4a427c78dfa03a1dc161b15f85dcc307b457fbf7 Mon Sep 17 00:00:00 2001 From: razyalov Date: Mon, 11 Sep 2017 12:44:06 -0700 Subject: [PATCH] Update itunes module to iOS 11 podcasts spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apple released new guidlines for the itunes RSS spec for podcasts: http://podcasts.apple.com/resources/spec/ApplePodcastsSpecUpdatesiOS11.pdf The specific technical changes are the addition of the following attributes: Channel level: The following was added: itunes:type :: type of podcast 'episodic' (default)  or 'serial'. Item level: The following was added: itunes:season :: a non-zero integer number for a season identifier itunes:episode :: a non-zero integer episode number within the season itunes:episodeType :: one of 'full' (default) 'bonus' or 'trailer' All new values are optional. --- .../modules/itunes/EntryInformation.java | 22 ++++++++++ .../modules/itunes/EntryInformationImpl.java | 40 +++++++++++++++++++ .../modules/itunes/FeedInformation.java | 15 +++++++ .../modules/itunes/FeedInformationImpl.java | 20 ++++++++++ .../modules/itunes/io/ITunesGenerator.java | 13 ++++++ .../modules/itunes/io/ITunesParser.java | 25 ++++++++++++ .../modules/itunes/ITunesGeneratorTest.java | 1 + .../src/test/resources/itunes/leshow.xml | 16 ++++++-- .../src/test/resources/xml/leshow.xml | 13 +++++- 9 files changed, 160 insertions(+), 5 deletions(-) diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformation.java b/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformation.java index cd2b320e5..8af243cd7 100644 --- a/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformation.java +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformation.java @@ -45,4 +45,26 @@ public interface EntryInformation extends ITunes { public Integer getOrder(); public void setOrder(Integer order); + + /** + * Get the episode type + * @see #setEpisodeType(String) setEpisodeType(episodeType) for details + */ + public String getEpisodeType(); + + /** + * Set the episode type to one of full (default), trailer or bonus. See the new spec by Apple for details. + * @param episodeType + */ + public void setEpisodeType(String episodeType); + + public Integer getSeason(); + + public void setSeason(Integer season); + + public Integer getEpisode(); + + public void setEpisode(Integer episode); + + } diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformationImpl.java b/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformationImpl.java index 62abba185..3fe3da9f9 100644 --- a/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformationImpl.java +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/EntryInformationImpl.java @@ -37,6 +37,9 @@ public class EntryInformationImpl extends AbstractITunesObject implements EntryI private Duration duration; private boolean closedCaptioned; private Integer order; + private String episodeType; + private Integer season; + private Integer episode; public EntryInformationImpl() { } @@ -81,6 +84,34 @@ public void setOrder(Integer order) { this.order = order; } + /** + * Get the episode type + * + * @see #setEpisodeType(String) setEpisodeType(episodeType) for details + */ + @Override + public String getEpisodeType() { return episodeType; } + + /** + * Set the episode type to one of full (default), trailer or bonus. See see the new spec by Apple for details. + * + * @param episodeType + */ + @Override + public void setEpisodeType(String episodeType) { this.episodeType = episodeType; } + + @Override + public Integer getSeason() { return season; } + + @Override + public void setSeason(Integer season) { this.season = season; } + + @Override + public Integer getEpisode() { return episode; } + + @Override + public void setEpisode(Integer episode) { this.episode = episode; } + /** * Defined by the ROME module API * @@ -114,6 +145,9 @@ public void copyFrom(final CopyFrom obj) { setSummary(info.getSummary()); setClosedCaptioned(info.getClosedCaptioned()); setOrder(info.getOrder()); + setEpisodeType(info.getEpisodeType()); + setSeason(info.getSeason()); + setEpisode(info.getEpisode()); } /** @@ -138,6 +172,12 @@ public String toString() { sb.append(getClosedCaptioned()); sb.append(" order: "); sb.append(getOrder()); + sb.append(" season: "); + sb.append(getSeason()); + sb.append(" episode: "); + sb.append(getEpisode()); + sb.append(" episodeType: "); + sb.append(getEpisodeType()); sb.append("]"); sb.append(super.toString()); diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformation.java b/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformation.java index 5db8281ac..537abbc49 100644 --- a/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformation.java +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformation.java @@ -75,4 +75,19 @@ public interface FeedInformation extends ITunes { * @return Returns the owner name for the feed */ public String getOwnerName(); + + /** + * Set the type of podcast to either Episodic (original type of podcasts) or Serial (should be consumed from oldest to newest) + * @see #getType() getType() for more details + * @param type the type (Either 'serial' or 'episodic') + */ + public void setType(String type); + + /** + * Return the type of podcast (either Episodic or Serial) as introduced in the new Apple Podcast spec for iOS 11. + * For more information see the new spec by Apple + * @return either 'episodic' (old school podcasts) or 'serial' (should be listened to from oldest to newest) + */ + public String getType(); + } diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformationImpl.java b/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformationImpl.java index 851832a27..5d213c235 100644 --- a/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformationImpl.java +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/FeedInformationImpl.java @@ -41,6 +41,7 @@ public class FeedInformationImpl extends AbstractITunesObject implements FeedInf private List categories; private boolean complete; private String newFeedUrl; + private String type; public FeedInformationImpl() { } @@ -125,6 +126,22 @@ public void setOwnerEmailAddress(final String ownerEmailAddress) { this.ownerEmailAddress = ownerEmailAddress; } + /** + * Set the type of podcast to either Episodic (original type of podcasts) or Serial (should be consumed from oldest to newest) + * @see #getType() getType() for more details + * @param type the type (Either 'serial' or 'episodic') + */ + @Override + public void setType(final String type) { this.type = type; } + + /** + * Return the type of podcast (either Episodic or Serial) as introduced in the new Apple Podcast spec for iOS 11. + * For more information see the new spec by Apple + * @return either 'episodic' (old school podcasts) or 'serial' (should be listened to from oldest to newest) + */ + @Override + public String getType() { return type; } + /** * Required by the ROME API * @@ -161,6 +178,7 @@ public void copyFrom(final CopyFrom obj) { setOwnerName(info.getOwnerName()); setSubtitle(info.getSubtitle()); setSummary(info.getSummary()); + setType(info.getType()); } /** @@ -189,6 +207,8 @@ public String toString() { sb.append(getComplete()); sb.append(" newFeedUrl: "); sb.append(getNewFeedUrl()); + sb.append(" type: "); + sb.append(getType()); sb.append("]"); sb.append(super.toString()); diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesGenerator.java b/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesGenerator.java index f32042fcc..05efa10f1 100644 --- a/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesGenerator.java +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesGenerator.java @@ -84,6 +84,10 @@ public void generate(final Module module, final Element element) { element.addContent(category); } + if (info.getType() != null) { + element.addContent(generateSimpleElement("type",info.getType())); + } + if (info.getComplete()) { element.addContent(generateSimpleElement("complete", "yes")); } @@ -104,6 +108,15 @@ public void generate(final Module module, final Element element) { if (info.getOrder() != null) { element.addContent(generateSimpleElement("order", info.getOrder().toString())); } + if (info.getEpisodeType() != null) { + element.addContent(generateSimpleElement("episodeType", info.getEpisodeType())); + } + if (info.getSeason() != null && info.getSeason() > 0) { + element.addContent(generateSimpleElement("season", info.getSeason().toString())); + } + if (info.getEpisode() != null && info.getEpisode() > 0) { + element.addContent(generateSimpleElement("episode", info.getEpisode().toString())); + } } if (itunes.getAuthor() != null) { diff --git a/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesParser.java b/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesParser.java index 1c002fdf2..d8a66abde 100644 --- a/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesParser.java +++ b/rome-modules/src/main/java/com/rometools/modules/itunes/io/ITunesParser.java @@ -109,6 +109,11 @@ public com.rometools.rome.feed.module.Module parse(final Element element, final feedInfo.setNewFeedUrl(newFeedUrl.getTextTrim()); } + final Element type = element.getChild("type", ns); + if (type != null) { + feedInfo.setType(type.getTextTrim()); + } + } else if (element.getName().equals("item")) { final EntryInformationImpl entryInfo = new EntryInformationImpl(); module = entryInfo; @@ -138,6 +143,26 @@ public com.rometools.rome.feed.module.Module parse(final Element element, final final Integer o = Integer.valueOf(order.getValue().trim()); entryInfo.setOrder(o); } + + final Element season = element.getChild("season", ns); + + if (season != null && season.getValue() != null) { + final Integer o = Integer.valueOf(season.getValue().trim()); + entryInfo.setSeason(o); + } + + final Element episode = element.getChild("episode", ns); + + if (episode != null && episode.getValue() != null) { + final Integer o = Integer.valueOf(episode.getValue().trim()); + entryInfo.setEpisode(o); + } + + final Element episodeType = element.getChild("episodeType", ns); + + if (episodeType != null && episodeType.getValue() != null) { + entryInfo.setEpisodeType(episodeType.getTextTrim()); + } } if (module != null) { // All these are common to both Channel and Item diff --git a/rome-modules/src/test/java/com/rometools/modules/itunes/ITunesGeneratorTest.java b/rome-modules/src/test/java/com/rometools/modules/itunes/ITunesGeneratorTest.java index 569ec081d..cb2513053 100644 --- a/rome-modules/src/test/java/com/rometools/modules/itunes/ITunesGeneratorTest.java +++ b/rome-modules/src/test/java/com/rometools/modules/itunes/ITunesGeneratorTest.java @@ -107,6 +107,7 @@ public void testCreate() throws Exception { fi.setOwnerName("sales.com"); fi.getCategories().add(new Category("Shopping")); fi.setOwnerEmailAddress("patti@sales.com"); + fi.setType("serial"); feed.getModules().add(fi); final SyndFeedOutput output = new SyndFeedOutput(); diff --git a/rome-modules/src/test/resources/itunes/leshow.xml b/rome-modules/src/test/resources/itunes/leshow.xml index c5044de30..961909705 100644 --- a/rome-modules/src/test/resources/itunes/leshow.xml +++ b/rome-modules/src/test/resources/itunes/leshow.xml @@ -7,6 +7,7 @@ A weekly, hour-long romp through the worlds of media, politics, sports and show business, leavened with an eclectic mix of mysterious music, hosted by Harry Shearer. An hour's worth of Harry Shearer A weekly, hour-long romp through the worlds of media, politics, sports and show business, leavened with an eclectic mix of mysterious music, hosted by Harry Shearer. + serial en KCRW 2005 @@ -65,7 +66,10 @@ 46:34 - + + 1 + 1 + full @@ -103,7 +107,10 @@ 44:00 - + + 1 + 2 + trailer @@ -141,7 +148,10 @@ 48:33 - + + 1 + 2 + bonus diff --git a/rome-modules/src/test/resources/xml/leshow.xml b/rome-modules/src/test/resources/xml/leshow.xml index f6855fc7c..5575ddb6c 100644 --- a/rome-modules/src/test/resources/xml/leshow.xml +++ b/rome-modules/src/test/resources/xml/leshow.xml @@ -9,6 +9,7 @@ A weekly, hour-long romp through the worlds of media, politics, sports and show business, leavened with an eclectic mix of mysterious music, hosted by Harry Shearer. yes http://example.org + serial en KCRW 2005 @@ -71,10 +72,12 @@ yes 2 + 1 + 1 + full - - + le Show Harry Shearer @@ -109,6 +112,9 @@ 44:00 + 1 + 2 + trailer @@ -147,6 +153,9 @@ 48:33 + 1 + 2 + bonus