diff --git a/src/main/java/com/apptasticsoftware/rssreader/AbstractRssReader.java b/src/main/java/com/apptasticsoftware/rssreader/AbstractRssReader.java index 66160cb..da1dd19 100644 --- a/src/main/java/com/apptasticsoftware/rssreader/AbstractRssReader.java +++ b/src/main/java/com/apptasticsoftware/rssreader/AbstractRssReader.java @@ -189,7 +189,8 @@ protected void registerChannelTags() { channelTags.putIfAbsent("dc:language", (channel, value) -> Mapper.mapIfEmpty(value, channel::getLanguage, channel::setLanguage)); channelTags.putIfAbsent("dc:rights", (channel, value) -> Mapper.mapIfEmpty(value, channel::getCopyright, channel::setCopyright)); channelTags.putIfAbsent("dc:title", (channel, value) -> Mapper.mapIfEmpty(value, channel::getTitle, channel::setTitle)); - channelTags.putIfAbsent("dc:date", (channel, value) -> Mapper.mapIfEmpty(value, channel::getPubDate, channel::setPubDate)); + channelTags.putIfAbsent("sy:updatePeriod", (channel, value) -> channel.syUpdatePeriod = value); + channelTags.putIfAbsent("sy:updateFrequency", (channel, value) -> mapInteger(value, number -> channel.syUpdateFrequency = number)); } /** diff --git a/src/main/java/com/apptasticsoftware/rssreader/Channel.java b/src/main/java/com/apptasticsoftware/rssreader/Channel.java index e309e1e..f75baf4 100644 --- a/src/main/java/com/apptasticsoftware/rssreader/Channel.java +++ b/src/main/java/com/apptasticsoftware/rssreader/Channel.java @@ -23,6 +23,8 @@ */ package com.apptasticsoftware.rssreader; +import com.apptasticsoftware.rssreader.util.Util; + import java.time.ZonedDateTime; import java.util.*; @@ -46,6 +48,8 @@ public class Channel { private String docs; private String rating; private Image image; + protected String syUpdatePeriod; + protected int syUpdateFrequency = 1; private final DateTimeParser dateTimeParser; /** @@ -216,7 +220,11 @@ public void setGenerator(String generator) { * @return time to live */ public Optional getTtl() { - return Optional.ofNullable(ttl); + return Optional.ofNullable(ttl) + .or(() -> Optional.ofNullable(syUpdatePeriod) + .map(Util::toMinutes) + .map(minutes -> minutes / Math.max(syUpdateFrequency, 1)) + .map(String::valueOf)); } /** diff --git a/src/main/java/com/apptasticsoftware/rssreader/util/Util.java b/src/main/java/com/apptasticsoftware/rssreader/util/Util.java new file mode 100644 index 0000000..9fca8ed --- /dev/null +++ b/src/main/java/com/apptasticsoftware/rssreader/util/Util.java @@ -0,0 +1,30 @@ +package com.apptasticsoftware.rssreader.util; + +import java.util.Locale; + +/** + * Utility class for RSS reader. + */ +public class Util { + + private Util() { + + } + + /** + * Convert a time period string to hours. + * + * @param period the time period string (e.g., "daily", "weekly", "monthly", "yearly", "hourly") + * @return the number of hours in the given time period, or 1 if the period is not recognized + */ + public static int toMinutes(String period) { + switch (period.toLowerCase(Locale.ENGLISH)) { + case "daily": return 1440; + case "weekly": return 10080; + case "monthly": return 43800; + case "yearly": return 525600; + case "hourly": + default: return 60; + } + } +} diff --git a/src/test/java/com/apptasticsoftware/integrationtest/RssReaderIntegrationTest.java b/src/test/java/com/apptasticsoftware/integrationtest/RssReaderIntegrationTest.java index 4b536ab..740dab6 100644 --- a/src/test/java/com/apptasticsoftware/integrationtest/RssReaderIntegrationTest.java +++ b/src/test/java/com/apptasticsoftware/integrationtest/RssReaderIntegrationTest.java @@ -868,6 +868,15 @@ void readFromAMixOfUrlAndString() throws IOException, URISyntaxException { assertEquals(33, items.size()); } + @Test + void syUpdatePeriodAndSyUpdateFrequency() throws IOException, URISyntaxException { + var source = getFileUri("rss-feed.xml"); + + var items = new RssReader().read(source).collect(Collectors.toList()); + assertEquals(20, items.size()); + assertEquals("30", items.get(0).getChannel().getTtl().orElse("")); + } + private InputStream fromFile(String fileName) { return getClass().getClassLoader().getResourceAsStream(fileName); } diff --git a/src/test/java/com/apptasticsoftware/rssreader/RssReaderTest.java b/src/test/java/com/apptasticsoftware/rssreader/RssReaderTest.java index 2eeda6b..0fbcda4 100644 --- a/src/test/java/com/apptasticsoftware/rssreader/RssReaderTest.java +++ b/src/test/java/com/apptasticsoftware/rssreader/RssReaderTest.java @@ -507,7 +507,7 @@ void enclosureEqualsTest() { @Test void equalsContract() { - EqualsVerifier.simple().forClass(Channel.class).withIgnoredFields("dateTimeParser").withIgnoredFields("category").withNonnullFields("categories").verify(); + EqualsVerifier.simple().forClass(Channel.class).withIgnoredFields("dateTimeParser").withIgnoredFields("category").withIgnoredFields("syUpdatePeriod").withIgnoredFields("syUpdateFrequency").withNonnullFields("categories").verify(); EqualsVerifier.simple().forClass(Item.class).withIgnoredFields("defaultComparator").withIgnoredFields("dateTimeParser").withIgnoredFields("category").withNonnullFields("categories").withIgnoredFields("enclosure").withNonnullFields("enclosures").verify(); EqualsVerifier.simple().forClass(Enclosure.class).verify(); EqualsVerifier.simple().forClass(Image.class).verify(); diff --git a/src/test/java/com/apptasticsoftware/rssreader/module/itunes/ItunesRssReaderTest.java b/src/test/java/com/apptasticsoftware/rssreader/module/itunes/ItunesRssReaderTest.java index a87f98f..836a76a 100644 --- a/src/test/java/com/apptasticsoftware/rssreader/module/itunes/ItunesRssReaderTest.java +++ b/src/test/java/com/apptasticsoftware/rssreader/module/itunes/ItunesRssReaderTest.java @@ -32,7 +32,7 @@ void readItunesPodcastFeed2() throws IOException { @Test void equalsContract() { - EqualsVerifier.simple().forClass(ItunesChannel.class).withIgnoredFields("dateTimeParser").withIgnoredFields("category").withNonnullFields("categories").withNonnullFields("itunesCategories").verify(); + EqualsVerifier.simple().forClass(ItunesChannel.class).withIgnoredFields("dateTimeParser").withIgnoredFields("category").withNonnullFields("categories").withIgnoredFields("syUpdatePeriod").withIgnoredFields("syUpdateFrequency").withNonnullFields("itunesCategories").verify(); EqualsVerifier.simple().forClass(ItunesItem.class).withIgnoredFields("defaultComparator").withIgnoredFields("dateTimeParser").withIgnoredFields("category").withNonnullFields("categories").withIgnoredFields("enclosure").withNonnullFields("enclosures").verify(); EqualsVerifier.simple().forClass(ItunesOwner.class).verify(); } diff --git a/src/test/java/com/apptasticsoftware/rssreader/util/UtilTest.java b/src/test/java/com/apptasticsoftware/rssreader/util/UtilTest.java new file mode 100644 index 0000000..0c585ac --- /dev/null +++ b/src/test/java/com/apptasticsoftware/rssreader/util/UtilTest.java @@ -0,0 +1,29 @@ +package com.apptasticsoftware.rssreader.util; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class UtilTest { + + @ParameterizedTest(name = "{0} is expected to output {1}") + @MethodSource("periodToHoursTestData") + void periodToHours(String period, int expectedHours) { + assertEquals(expectedHours, Util.toMinutes(period)); + } + + private static Stream periodToHoursTestData() { + return Stream.of( + Arguments.of("daily", 1440), + Arguments.of("weekly", 10080), + Arguments.of("monthly", 43800), + Arguments.of("yearly", 525600), + Arguments.of("hourly", 60), + Arguments.of("unknown", 60) + ); + } +} diff --git a/src/test/resources/rss-feed.xml b/src/test/resources/rss-feed.xml index e9923ea..631a691 100644 --- a/src/test/resources/rss-feed.xml +++ b/src/test/resources/rss-feed.xml @@ -8,7 +8,7 @@ Fri, 23 Aug 2024 01:11:17 +0000 en-US hourly - 1 + 2 https://wordpress.org/?v=6.5.5 https://techcrunch.com/wp-content/uploads/2015/02/cropped-cropped-favicon-gradient.png?w=32