From 24389d42e89037b205fff2bc681e4ad998895286 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 28 Aug 2021 00:12:48 +0200 Subject: [PATCH] Moved feed parser to its own module --- app/build.gradle | 1 + .../feedgenerator/Rss2Generator.java | 6 +- .../activity/OnlineFeedViewActivity.java | 6 +- .../FeedItemlistDescriptionAdapter.java | 4 +- .../PlaybackStatisticsListAdapter.java | 4 +- .../antennapod/fragment/CoverFragment.java | 4 +- .../antennapod/fragment/ItemFragment.java | 6 +- .../viewholder/EpisodeItemViewHolder.java | 6 +- core/build.gradle | 1 + .../core/export/opml/OpmlWriter.java | 4 +- .../core/feed/LocalFeedUpdater.java | 2 +- .../core/service/download/HttpDownloader.java | 2 +- .../download/handler/FeedParserTask.java | 6 +- .../download/handler/FeedSyncTask.java | 2 +- .../storage/mapper/ChapterCursorMapper.java | 2 +- .../core/syndication/handler/SyndHandler.java | 138 ----------------- .../core/syndication/handler/TypeGetter.java | 120 --------------- .../core/syndication/namespace/Namespace.java | 21 --- .../syndication/namespace/SyndElement.java | 22 --- .../antennapod/core/util/DateFormatter.java | 46 ++++++ .../antennapod/core/storage/DbTestUtils.java | 2 +- parser/README.md | 3 + parser/feed/README.md | 3 + parser/feed/build.gradle | 23 +++ parser/feed/src/main/AndroidManifest.xml | 1 + .../antennapod/parser/feed}/FeedHandler.java | 3 +- .../parser/feed}/FeedHandlerResult.java | 2 +- .../antennapod/parser/feed}/HandlerState.java | 19 ++- .../antennapod/parser/feed/SyndHandler.java | 139 ++++++++++++++++++ .../feed}/UnsupportedFeedtypeException.java | 5 +- .../parser/feed/element}/AtomText.java | 6 +- .../parser/feed/element}/SimpleChapter.java | 2 +- .../parser/feed/element/SyndElement.java | 22 +++ .../parser/feed/namespace/Atom.java | 28 ++-- .../parser/feed/namespace/Content.java | 9 +- .../parser/feed/namespace/DublinCore.java | 9 +- .../parser/feed/namespace/Itunes.java | 11 +- .../parser/feed/namespace/Media.java | 11 +- .../parser/feed/namespace/Namespace.java | 19 +++ .../parser/feed}/namespace/PodcastIndex.java | 5 +- .../parser/feed/namespace/Rss20.java | 23 +-- .../parser/feed/namespace/SimpleChapters.java | 11 +- .../parser/feed}/util/DateUtils.java | 51 +------ .../parser/feed/util}/DurationParser.java | 2 +- .../parser/feed}/util/SyndStringUtils.java | 2 +- .../parser/feed}/util/SyndTypeUtils.java | 2 +- .../parser/feed/util/TypeGetter.java | 121 +++++++++++++++ .../feed/element/element}/AtomTextTest.java | 6 +- .../element/namespace}/AtomParserTest.java | 4 +- .../namespace}/FeedParserTestHelper.java | 3 +- .../element/namespace}/RssParserTest.java | 2 +- .../feed/element}/util/DateUtilsTest.java | 3 +- .../element/util}/DurationParserTest.java | 3 +- .../resources/feed-atom-testAtomBasic.xml | 0 .../resources/feed-atom-testEmptyRelLinks.xml | 0 .../feed-atom-testLogoWithWhitespace.xml | 0 .../feed-rss-testImageWithWhitespace.xml | 0 .../feed-rss-testMediaContentMime.xml | 0 .../feed-rss-testMultipleFundingTags.xml | 0 .../test/resources/feed-rss-testRss2Basic.xml | 0 settings.gradle | 2 + 61 files changed, 505 insertions(+), 455 deletions(-) delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/Namespace.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/SyndElement.java create mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java create mode 100644 parser/README.md create mode 100644 parser/feed/README.md create mode 100644 parser/feed/build.gradle create mode 100644 parser/feed/src/main/AndroidManifest.xml rename {core/src/main/java/de/danoeh/antennapod/core/syndication/handler => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed}/FeedHandler.java (97%) rename {core/src/main/java/de/danoeh/antennapod/core/syndication/handler => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed}/FeedHandlerResult.java (88%) rename {core/src/main/java/de/danoeh/antennapod/core/syndication/handler => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed}/HandlerState.java (87%) create mode 100644 parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/SyndHandler.java rename {core/src/main/java/de/danoeh/antennapod/core/syndication/handler => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed}/UnsupportedFeedtypeException.java (86%) rename {core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element}/AtomText.java (80%) rename {core/src/main/java/de/danoeh/antennapod/core/feed => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element}/SimpleChapter.java (88%) create mode 100644 parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element/SyndElement.java rename core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java (91%) rename core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Content.java (77%) rename core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSDublinCore.java => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java (82%) rename core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Itunes.java (91%) rename core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Media.java (94%) create mode 100644 parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Namespace.java rename {core/src/main/java/de/danoeh/antennapod/core/syndication => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed}/namespace/PodcastIndex.java (89%) rename core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Rss20.java (91%) rename core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/SimpleChapters.java (84%) rename {core/src/main/java/de/danoeh/antennapod/core => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed}/util/DateUtils.java (76%) rename {core/src/main/java/de/danoeh/antennapod/core/syndication/parsers => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util}/DurationParser.java (95%) rename {core/src/main/java/de/danoeh/antennapod/core/syndication => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed}/util/SyndStringUtils.java (86%) rename {core/src/main/java/de/danoeh/antennapod/core/syndication => parser/feed/src/main/java/de/danoeh/antennapod/parser/feed}/util/SyndTypeUtils.java (95%) create mode 100644 parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/TypeGetter.java rename {core/src/test/java/de/danoeh/antennapod/core/syndication/namespace/atom => parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/element}/AtomTextTest.java (76%) rename {core/src/test/java/de/danoeh/antennapod/core/syndication/handler => parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace}/AtomParserTest.java (98%) rename {core/src/test/java/de/danoeh/antennapod/core/syndication/handler => parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace}/FeedParserTestHelper.java (89%) rename {core/src/test/java/de/danoeh/antennapod/core/syndication/handler => parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace}/RssParserTest.java (98%) rename {core/src/test/java/de/danoeh/antennapod/core => parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element}/util/DateUtilsTest.java (98%) rename {core/src/test/java/de/danoeh/antennapod/core/syndication/parsers => parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/util}/DurationParserTest.java (91%) rename {core => parser/feed}/src/test/resources/feed-atom-testAtomBasic.xml (100%) rename {core => parser/feed}/src/test/resources/feed-atom-testEmptyRelLinks.xml (100%) rename {core => parser/feed}/src/test/resources/feed-atom-testLogoWithWhitespace.xml (100%) rename {core => parser/feed}/src/test/resources/feed-rss-testImageWithWhitespace.xml (100%) rename {core => parser/feed}/src/test/resources/feed-rss-testMediaContentMime.xml (100%) rename {core => parser/feed}/src/test/resources/feed-rss-testMultipleFundingTags.xml (100%) rename {core => parser/feed}/src/test/resources/feed-rss-testRss2Basic.xml (100%) diff --git a/app/build.gradle b/app/build.gradle index b2d6a5600..0d710c4cf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -114,6 +114,7 @@ dependencies { implementation project(':model') implementation project(':net:sync:gpoddernet') implementation project(':net:sync:model') + implementation project(':parser:feed') implementation project(':ui:app-start-intent') implementation project(':ui:common') diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java index 9361c23df..6b294244a 100644 --- a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java +++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java @@ -11,8 +11,8 @@ import java.util.ArrayList; import de.danoeh.antennapod.model.feed.Feed; import de.danoeh.antennapod.model.feed.FeedFunding; import de.danoeh.antennapod.model.feed.FeedItem; -import de.danoeh.antennapod.core.syndication.namespace.PodcastIndex; -import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.parser.feed.namespace.PodcastIndex; +import de.danoeh.antennapod.core.util.DateFormatter; /** * Creates RSS 2.0 feeds. See FeedGenerator for more information. @@ -98,7 +98,7 @@ public class Rss2Generator implements FeedGenerator { } if (item.getPubDate() != null) { xml.startTag(null, "pubDate"); - xml.text(DateUtils.formatRFC822Date(item.getPubDate())); + xml.text(DateFormatter.formatRfc822Date(item.getPubDate())); xml.endTag(null, "pubDate"); } if ((flags & FEATURE_WRITE_GUID) != 0) { diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java index 575e94f8c..ec9e20dea 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -46,9 +46,8 @@ import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; -import de.danoeh.antennapod.core.syndication.handler.FeedHandler; -import de.danoeh.antennapod.core.syndication.handler.FeedHandlerResult; -import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeException; +import de.danoeh.antennapod.parser.feed.FeedHandler; +import de.danoeh.antennapod.parser.feed.FeedHandlerResult; import de.danoeh.antennapod.core.util.DownloadError; import de.danoeh.antennapod.core.util.FileNameGenerator; import de.danoeh.antennapod.core.util.IntentUtils; @@ -63,6 +62,7 @@ import de.danoeh.antennapod.model.feed.Feed; import de.danoeh.antennapod.model.feed.FeedPreferences; import de.danoeh.antennapod.model.feed.VolumeAdaptionSetting; import de.danoeh.antennapod.model.playback.RemoteMedia; +import de.danoeh.antennapod.parser.feed.UnsupportedFeedtypeException; import io.reactivex.Maybe; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java index 62a97e849..2ab96e84d 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java @@ -17,7 +17,7 @@ import de.danoeh.antennapod.core.util.NetworkUtils; import de.danoeh.antennapod.model.playback.RemoteMedia; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.core.service.playback.PlaybackService; -import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.core.util.DateFormatter; import de.danoeh.antennapod.model.playback.Playable; import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter; import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText; @@ -58,7 +58,7 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter { } holder.title.setText(item.getTitle()); - holder.pubDate.setText(DateUtils.formatAbbrev(getContext(), item.getPubDate())); + holder.pubDate.setText(DateFormatter.formatAbbrev(getContext(), item.getPubDate())); if (item.getDescription() != null) { String description = HtmlToPlainText.getPlainText(item.getDescription()) .replaceAll("\n", " ") diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java index a71595c55..5fec5f063 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java @@ -7,7 +7,7 @@ import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.StatisticsItem; import de.danoeh.antennapod.core.util.Converter; -import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.core.util.DateFormatter; import de.danoeh.antennapod.view.PieChartView; import java.util.Date; @@ -32,7 +32,7 @@ public class PlaybackStatisticsListAdapter extends StatisticsListAdapter { String getHeaderCaption() { long usageCounting = UserPreferences.getUsageCountingDateMillis(); if (usageCounting > 0) { - String date = DateUtils.formatAbbrev(context, new Date(usageCounting)); + String date = DateFormatter.formatAbbrev(context, new Date(usageCounting)); return context.getString(R.string.statistics_counting_since, date); } else { return context.getString(R.string.total_time_listened_to_podcasts); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java index 5dbadaefa..67d1757ac 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java @@ -50,7 +50,7 @@ import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.core.feed.util.ImageResourceUtils; import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.util.ChapterUtils; -import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.core.util.DateFormatter; import de.danoeh.antennapod.core.util.EmbeddedChapterImage; import de.danoeh.antennapod.core.util.playback.PlaybackController; import de.danoeh.antennapod.model.feed.Chapter; @@ -150,7 +150,7 @@ public class CoverFragment extends Fragment { } private void displayMediaInfo(@NonNull Playable media) { - String pubDateStr = DateUtils.formatAbbrev(getActivity(), media.getPubDate()); + String pubDateStr = DateFormatter.formatAbbrev(getActivity(), media.getPubDate()); txtvPodcastTitle.setText(StringUtils.stripToEmpty(media.getFeedTitle()) + "\u00A0" + "・" diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java index 5a2061a5f..31c6da8cd 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java @@ -55,7 +55,7 @@ import de.danoeh.antennapod.core.service.download.Downloader; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.Converter; -import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.core.util.DateFormatter; import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.ui.common.ThemeUtils; import de.danoeh.antennapod.core.util.playback.PlaybackController; @@ -291,9 +291,9 @@ public class ItemFragment extends Fragment { txtvTitle.setText(item.getTitle()); if (item.getPubDate() != null) { - String pubDateStr = DateUtils.formatAbbrev(getActivity(), item.getPubDate()); + String pubDateStr = DateFormatter.formatAbbrev(getActivity(), item.getPubDate()); txtvPublished.setText(pubDateStr); - txtvPublished.setContentDescription(DateUtils.formatForAccessibility(getContext(), item.getPubDate())); + txtvPublished.setContentDescription(DateFormatter.formatForAccessibility(getContext(), item.getPubDate())); } RequestOptions options = new RequestOptions() diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java index 02d45b2a0..cd3af5003 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java @@ -22,6 +22,7 @@ import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.CoverLoader; import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton; import de.danoeh.antennapod.core.event.PlaybackPositionEvent; +import de.danoeh.antennapod.core.util.DateFormatter; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.model.playback.MediaType; @@ -31,7 +32,6 @@ import de.danoeh.antennapod.core.service.download.DownloadRequest; import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.Converter; -import de.danoeh.antennapod.core.util.DateUtils; import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.core.util.NetworkUtils; import de.danoeh.antennapod.ui.common.CircularProgressBar; @@ -103,8 +103,8 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder { placeholder.setText(item.getFeed().getTitle()); title.setText(item.getTitle()); leftPadding.setContentDescription(item.getTitle()); - pubDate.setText(DateUtils.formatAbbrev(activity, item.getPubDate())); - pubDate.setContentDescription(DateUtils.formatForAccessibility(activity, item.getPubDate())); + pubDate.setText(DateFormatter.formatAbbrev(activity, item.getPubDate())); + pubDate.setContentDescription(DateFormatter.formatForAccessibility(activity, item.getPubDate())); isNew.setVisibility(item.isNew() ? View.VISIBLE : View.GONE); isFavorite.setVisibility(item.isTagged(FeedItem.TAG_FAVORITE) ? View.VISIBLE : View.GONE); isInQueue.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE); diff --git a/core/build.gradle b/core/build.gradle index e78b70881..2190ad35f 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -24,6 +24,7 @@ dependencies { implementation project(':net:ssl') implementation project(':net:sync:gpoddernet') implementation project(':net:sync:model') + implementation project(':parser:feed') implementation project(':ui:app-start-intent') implementation project(':ui:common') implementation project(':ui:png-icons') diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlWriter.java index e2205471c..a44d90557 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/export/opml/OpmlWriter.java @@ -4,6 +4,7 @@ import android.content.Context; import android.util.Log; import android.util.Xml; +import de.danoeh.antennapod.core.util.DateFormatter; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; @@ -13,7 +14,6 @@ import java.util.List; import de.danoeh.antennapod.core.export.ExportWriter; import de.danoeh.antennapod.model.feed.Feed; -import de.danoeh.antennapod.core.util.DateUtils; /** Writes OPML documents. */ public class OpmlWriter implements ExportWriter { @@ -44,7 +44,7 @@ public class OpmlWriter implements ExportWriter { xs.text(OPML_TITLE); xs.endTag(null, OpmlSymbols.TITLE); xs.startTag(null, OpmlSymbols.DATE_CREATED); - xs.text(DateUtils.formatRFC822Date(new Date())); + xs.text(DateFormatter.formatRfc822Date(new Date())); xs.endTag(null, OpmlSymbols.DATE_CREATED); xs.endTag(null, OpmlSymbols.HEAD); diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java b/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java index 7a8c4969b..82583b7b5 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/LocalFeedUpdater.java @@ -27,7 +27,7 @@ import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; -import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.parser.feed.util.DateUtils; import de.danoeh.antennapod.core.util.DownloadError; import de.danoeh.antennapod.model.feed.Feed; import de.danoeh.antennapod.model.feed.FeedItem; diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java index 1320b7052..781110f82 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java @@ -24,7 +24,7 @@ import java.util.regex.Pattern; import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.model.feed.FeedMedia; -import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.parser.feed.util.DateUtils; import de.danoeh.antennapod.core.util.DownloadError; import de.danoeh.antennapod.core.util.StorageUtils; import de.danoeh.antennapod.core.util.URIUtil; diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java index 3e3da00e7..9a0916109 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java @@ -8,9 +8,9 @@ import de.danoeh.antennapod.model.feed.VolumeAdaptionSetting; import de.danoeh.antennapod.core.service.download.DownloadRequest; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.storage.DownloadRequester; -import de.danoeh.antennapod.core.syndication.handler.FeedHandler; -import de.danoeh.antennapod.core.syndication.handler.FeedHandlerResult; -import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeException; +import de.danoeh.antennapod.parser.feed.FeedHandler; +import de.danoeh.antennapod.parser.feed.FeedHandlerResult; +import de.danoeh.antennapod.parser.feed.UnsupportedFeedtypeException; import de.danoeh.antennapod.core.util.DownloadError; import de.danoeh.antennapod.core.util.InvalidFeedException; import org.xml.sax.SAXException; diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java index 1ca4d1194..dcc1c8fdb 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java @@ -9,7 +9,7 @@ import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; -import de.danoeh.antennapod.core.syndication.handler.FeedHandlerResult; +import de.danoeh.antennapod.parser.feed.FeedHandlerResult; public class FeedSyncTask { private static final String TAG = "FeedParserTask"; diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/ChapterCursorMapper.java b/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/ChapterCursorMapper.java index b171f2bcc..61613a25a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/ChapterCursorMapper.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/ChapterCursorMapper.java @@ -4,7 +4,7 @@ import android.database.Cursor; import androidx.annotation.NonNull; import de.danoeh.antennapod.model.feed.Chapter; import de.danoeh.antennapod.core.feed.ID3Chapter; -import de.danoeh.antennapod.core.feed.SimpleChapter; +import de.danoeh.antennapod.parser.feed.element.SimpleChapter; import de.danoeh.antennapod.core.feed.VorbisCommentChapter; import de.danoeh.antennapod.core.storage.PodDBAdapter; diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java deleted file mode 100644 index 9c09be714..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/SyndHandler.java +++ /dev/null @@ -1,138 +0,0 @@ -package de.danoeh.antennapod.core.syndication.handler; - -import android.util.Log; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import de.danoeh.antennapod.model.feed.Feed; -import de.danoeh.antennapod.core.syndication.namespace.NSContent; -import de.danoeh.antennapod.core.syndication.namespace.NSDublinCore; -import de.danoeh.antennapod.core.syndication.namespace.NSITunes; -import de.danoeh.antennapod.core.syndication.namespace.NSMedia; -import de.danoeh.antennapod.core.syndication.namespace.NSRSS20; -import de.danoeh.antennapod.core.syndication.namespace.NSSimpleChapters; -import de.danoeh.antennapod.core.syndication.namespace.Namespace; -import de.danoeh.antennapod.core.syndication.namespace.PodcastIndex; -import de.danoeh.antennapod.core.syndication.namespace.SyndElement; -import de.danoeh.antennapod.core.syndication.namespace.atom.NSAtom; - -/** Superclass for all SAX Handlers which process Syndication formats */ -class SyndHandler extends DefaultHandler { - private static final String TAG = "SyndHandler"; - private static final String DEFAULT_PREFIX = ""; - final HandlerState state; - - public SyndHandler(Feed feed, TypeGetter.Type type) { - state = new HandlerState(feed); - if (type == TypeGetter.Type.RSS20 || type == TypeGetter.Type.RSS091) { - state.defaultNamespaces.push(new NSRSS20()); - } - } - - @Override - public void startElement(String uri, String localName, String qName, - Attributes attributes) throws SAXException { - state.contentBuf = new StringBuilder(); - Namespace handler = getHandlingNamespace(uri, qName); - if (handler != null) { - SyndElement element = handler.handleElementStart(localName, state, - attributes); - state.tagstack.push(element); - - } - } - - @Override - public void characters(char[] ch, int start, int length) - throws SAXException { - if (!state.tagstack.empty()) { - if (state.getTagstack().size() >= 2) { - if (state.contentBuf != null) { - state.contentBuf.append(ch, start, length); - } - } - } - } - - @Override - public void endElement(String uri, String localName, String qName) - throws SAXException { - Namespace handler = getHandlingNamespace(uri, qName); - if (handler != null) { - handler.handleElementEnd(localName, state); - state.tagstack.pop(); - - } - state.contentBuf = null; - - } - - @Override - public void endPrefixMapping(String prefix) throws SAXException { - if (state.defaultNamespaces.size() > 1 && prefix.equals(DEFAULT_PREFIX)) { - state.defaultNamespaces.pop(); - } - } - - @Override - public void startPrefixMapping(String prefix, String uri) - throws SAXException { - // Find the right namespace - if (!state.namespaces.containsKey(uri)) { - if (uri.equals(NSAtom.NSURI)) { - if (prefix.equals(DEFAULT_PREFIX)) { - state.defaultNamespaces.push(new NSAtom()); - } else if (prefix.equals(NSAtom.NSTAG)) { - state.namespaces.put(uri, new NSAtom()); - Log.d(TAG, "Recognized Atom namespace"); - } - } else if (uri.equals(NSContent.NSURI) - && prefix.equals(NSContent.NSTAG)) { - state.namespaces.put(uri, new NSContent()); - Log.d(TAG, "Recognized Content namespace"); - } else if (uri.equals(NSITunes.NSURI) - && prefix.equals(NSITunes.NSTAG)) { - state.namespaces.put(uri, new NSITunes()); - Log.d(TAG, "Recognized ITunes namespace"); - } else if (uri.equals(NSSimpleChapters.NSURI) - && prefix.matches(NSSimpleChapters.NSTAG)) { - state.namespaces.put(uri, new NSSimpleChapters()); - Log.d(TAG, "Recognized SimpleChapters namespace"); - } else if (uri.equals(NSMedia.NSURI) - && prefix.equals(NSMedia.NSTAG)) { - state.namespaces.put(uri, new NSMedia()); - Log.d(TAG, "Recognized media namespace"); - } else if (uri.equals(NSDublinCore.NSURI) - && prefix.equals(NSDublinCore.NSTAG)) { - state.namespaces.put(uri, new NSDublinCore()); - Log.d(TAG, "Recognized DublinCore namespace"); - } else if (uri.equals(PodcastIndex.NSURI) || uri.equals(PodcastIndex.NSURI2) - && prefix.equals(PodcastIndex.NSTAG)) { - state.namespaces.put(uri, new PodcastIndex()); - Log.d(TAG, "Recognized PodcastIndex namespace"); - } - } - } - - private Namespace getHandlingNamespace(String uri, String qName) { - Namespace handler = state.namespaces.get(uri); - if (handler == null && !state.defaultNamespaces.empty() - && !qName.contains(":")) { - handler = state.defaultNamespaces.peek(); - } - return handler; - } - - @Override - public void endDocument() throws SAXException { - super.endDocument(); - state.getFeed().setItems(state.getItems()); - } - - public HandlerState getState() { - return state; - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java deleted file mode 100644 index e6011e3fa..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/TypeGetter.java +++ /dev/null @@ -1,120 +0,0 @@ -package de.danoeh.antennapod.core.syndication.handler; - -import android.util.Log; - -import org.apache.commons.io.input.XmlStreamReader; -import org.jsoup.Jsoup; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.Reader; - -import de.danoeh.antennapod.model.feed.Feed; - -/** Gets the type of a specific feed by reading the root element. */ -public class TypeGetter { - private static final String TAG = "TypeGetter"; - - public enum Type { - RSS20, RSS091, ATOM, INVALID - } - - private static final String ATOM_ROOT = "feed"; - private static final String RSS_ROOT = "rss"; - - public Type getType(Feed feed) throws UnsupportedFeedtypeException { - XmlPullParserFactory factory; - if (feed.getFile_url() != null) { - Reader reader = null; - try { - factory = XmlPullParserFactory.newInstance(); - factory.setNamespaceAware(true); - XmlPullParser xpp = factory.newPullParser(); - reader = createReader(feed); - xpp.setInput(reader); - int eventType = xpp.getEventType(); - - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG) { - String tag = xpp.getName(); - switch (tag) { - case ATOM_ROOT: - feed.setType(Feed.TYPE_ATOM1); - Log.d(TAG, "Recognized type Atom"); - - String strLang = xpp.getAttributeValue("http://www.w3.org/XML/1998/namespace", "lang"); - if (strLang != null) { - feed.setLanguage(strLang); - } - - return Type.ATOM; - case RSS_ROOT: - String strVersion = xpp.getAttributeValue(null, "version"); - if (strVersion == null) { - feed.setType(Feed.TYPE_RSS2); - Log.d(TAG, "Assuming type RSS 2.0"); - return Type.RSS20; - } else if (strVersion.equals("2.0")) { - feed.setType(Feed.TYPE_RSS2); - Log.d(TAG, "Recognized type RSS 2.0"); - return Type.RSS20; - } else if (strVersion.equals("0.91") || strVersion.equals("0.92")) { - Log.d(TAG, "Recognized type RSS 0.91/0.92"); - return Type.RSS091; - } - throw new UnsupportedFeedtypeException("Unsupported rss version"); - default: - Log.d(TAG, "Type is invalid"); - throw new UnsupportedFeedtypeException(Type.INVALID, tag); - } - } else { - eventType = xpp.next(); - } - } - } catch (XmlPullParserException e) { - e.printStackTrace(); - // XML document might actually be a HTML document -> try to parse as HTML - String rootElement = null; - try { - if (Jsoup.parse(new File(feed.getFile_url()), null) != null) { - rootElement = "html"; - } - } catch (IOException e1) { - e1.printStackTrace(); - } - throw new UnsupportedFeedtypeException(Type.INVALID, rootElement); - - } catch (IOException e) { - e.printStackTrace(); - } finally { - if(reader != null) { - try { - reader.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - Log.d(TAG, "Type is invalid"); - throw new UnsupportedFeedtypeException(Type.INVALID); - } - - private Reader createReader(Feed feed) { - Reader reader; - try { - reader = new XmlStreamReader(new File(feed.getFile_url())); - } catch (FileNotFoundException e) { - e.printStackTrace(); - return null; - } catch (IOException e) { - e.printStackTrace(); - return null; - } - return reader; - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/Namespace.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/Namespace.java deleted file mode 100644 index e5fbdb9bb..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/Namespace.java +++ /dev/null @@ -1,21 +0,0 @@ -package de.danoeh.antennapod.core.syndication.namespace; - -import org.xml.sax.Attributes; - -import de.danoeh.antennapod.core.syndication.handler.HandlerState; - - -public abstract class Namespace { - public static final String NSTAG = null; - public static final String NSURI = null; - - /** Called by a Feedhandler when in startElement and it detects a namespace element - * @return The SyndElement to push onto the stack - * */ - public abstract SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes); - - /** Called by a Feedhandler when in endElement and it detects a namespace element - * */ - public abstract void handleElementEnd(String localName, HandlerState state); - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/SyndElement.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/SyndElement.java deleted file mode 100644 index ba1b8ba5c..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/SyndElement.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.danoeh.antennapod.core.syndication.namespace; - -/** Defines a XML Element that is pushed on the tagstack */ -public class SyndElement { - private final String name; - private final Namespace namespace; - - public SyndElement(String name, Namespace namespace) { - this.name = name; - this.namespace = namespace; - } - - public Namespace getNamespace() { - return namespace; - } - - public String getName() { - return name; - } - - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java b/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java new file mode 100644 index 000000000..99628dfcc --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java @@ -0,0 +1,46 @@ +package de.danoeh.antennapod.core.util; + +import android.content.Context; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; + +/** + * Formats dates. + */ +public class DateFormatter { + private DateFormatter() { + + } + + public static String formatRfc822Date(Date date) { + SimpleDateFormat format = new SimpleDateFormat("dd MMM yy HH:mm:ss Z", Locale.US); + return format.format(date); + } + + public static String formatAbbrev(final Context context, final Date date) { + if (date == null) { + return ""; + } + GregorianCalendar now = new GregorianCalendar(); + GregorianCalendar cal = new GregorianCalendar(); + cal.setTime(date); + boolean withinLastYear = now.get(Calendar.YEAR) == cal.get(Calendar.YEAR); + int format = android.text.format.DateUtils.FORMAT_ABBREV_ALL; + if (withinLastYear) { + format |= android.text.format.DateUtils.FORMAT_NO_YEAR; + } + return android.text.format.DateUtils.formatDateTime(context, date.getTime(), format); + } + + public static String formatForAccessibility(final Context context, final Date date) { + if (date == null) { + return ""; + } + return DateFormat.getDateInstance(DateFormat.LONG).format(date); + } +} diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/DbTestUtils.java b/core/src/test/java/de/danoeh/antennapod/core/storage/DbTestUtils.java index 6c1e8d4f9..413243d1d 100644 --- a/core/src/test/java/de/danoeh/antennapod/core/storage/DbTestUtils.java +++ b/core/src/test/java/de/danoeh/antennapod/core/storage/DbTestUtils.java @@ -9,7 +9,7 @@ import de.danoeh.antennapod.model.feed.Chapter; import de.danoeh.antennapod.model.feed.Feed; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedMedia; -import de.danoeh.antennapod.core.feed.SimpleChapter; +import de.danoeh.antennapod.parser.feed.element.SimpleChapter; import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator; import static org.junit.Assert.assertTrue; diff --git a/parser/README.md b/parser/README.md new file mode 100644 index 000000000..c4fe1a933 --- /dev/null +++ b/parser/README.md @@ -0,0 +1,3 @@ +# :parser + +This folder contains modules that parse data, for example XML or media files. diff --git a/parser/feed/README.md b/parser/feed/README.md new file mode 100644 index 000000000..cfda75a4c --- /dev/null +++ b/parser/feed/README.md @@ -0,0 +1,3 @@ +# :parser:feed + +This module provides the XML feed parser. diff --git a/parser/feed/build.gradle b/parser/feed/build.gradle new file mode 100644 index 000000000..3f6ea4aa3 --- /dev/null +++ b/parser/feed/build.gradle @@ -0,0 +1,23 @@ +apply plugin: "com.android.library" +apply from: "../../common.gradle" + +android { + lintOptions { + disable "TrustAllX509TrustManager" + } +} + +dependencies { + implementation project(':model') + + annotationProcessor "androidx.annotation:annotation:$annotationVersion" + + implementation "androidx.core:core:$appcompatVersion" + + implementation "org.apache.commons:commons-lang3:$commonslangVersion" + implementation "commons-io:commons-io:$commonsioVersion" + implementation "org.jsoup:jsoup:$jsoupVersion" + + testImplementation 'junit:junit:4.13' + testImplementation 'org.robolectric:robolectric:4.5-alpha-1' +} diff --git a/parser/feed/src/main/AndroidManifest.xml b/parser/feed/src/main/AndroidManifest.xml new file mode 100644 index 000000000..44b10f29a --- /dev/null +++ b/parser/feed/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandler.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/FeedHandler.java similarity index 97% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandler.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/FeedHandler.java index 2928ba836..c7f5c4f21 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandler.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/FeedHandler.java @@ -1,8 +1,9 @@ -package de.danoeh.antennapod.core.syndication.handler; +package de.danoeh.antennapod.parser.feed; import android.text.TextUtils; import android.util.Log; +import de.danoeh.antennapod.parser.feed.util.TypeGetter; import org.apache.commons.io.input.XmlStreamReader; import org.xml.sax.InputSource; import org.xml.sax.SAXException; diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandlerResult.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/FeedHandlerResult.java similarity index 88% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandlerResult.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/FeedHandlerResult.java index fb4bf4707..43b3387a0 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/FeedHandlerResult.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/FeedHandlerResult.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.syndication.handler; +package de.danoeh.antennapod.parser.feed; import java.util.Map; diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/HandlerState.java similarity index 87% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/HandlerState.java index 2fecb0536..706a328e8 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/HandlerState.java @@ -1,16 +1,15 @@ -package de.danoeh.antennapod.core.syndication.handler; - -import androidx.collection.ArrayMap; +package de.danoeh.antennapod.parser.feed; import java.util.ArrayList; +import java.util.HashMap; import java.util.Map; import java.util.Stack; import de.danoeh.antennapod.model.feed.Feed; import de.danoeh.antennapod.model.feed.FeedFunding; import de.danoeh.antennapod.model.feed.FeedItem; -import de.danoeh.antennapod.core.syndication.namespace.Namespace; -import de.danoeh.antennapod.core.syndication.namespace.SyndElement; +import de.danoeh.antennapod.parser.feed.namespace.Namespace; +import de.danoeh.antennapod.parser.feed.element.SyndElement; /** * Contains all relevant information to describe the current state of a @@ -21,12 +20,12 @@ public class HandlerState { /** * Feed that the Handler is currently processing. */ - Feed feed; + public 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 */ - final Map alternateUrls; + public final Map alternateUrls; private final ArrayList items; private FeedItem currentItem; private FeedFunding currentFunding; @@ -48,12 +47,12 @@ public class HandlerState { public HandlerState(Feed feed) { this.feed = feed; - alternateUrls = new ArrayMap<>(); + alternateUrls = new HashMap<>(); items = new ArrayList<>(); tagstack = new Stack<>(); - namespaces = new ArrayMap<>(); + namespaces = new HashMap<>(); defaultNamespaces = new Stack<>(); - tempObjects = new ArrayMap<>(); + tempObjects = new HashMap<>(); } public Feed getFeed() { diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/SyndHandler.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/SyndHandler.java new file mode 100644 index 000000000..16bbecbb8 --- /dev/null +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/SyndHandler.java @@ -0,0 +1,139 @@ +package de.danoeh.antennapod.parser.feed; + +import android.util.Log; + +import de.danoeh.antennapod.parser.feed.util.TypeGetter; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import de.danoeh.antennapod.model.feed.Feed; +import de.danoeh.antennapod.parser.feed.namespace.Content; +import de.danoeh.antennapod.parser.feed.namespace.DublinCore; +import de.danoeh.antennapod.parser.feed.namespace.Itunes; +import de.danoeh.antennapod.parser.feed.namespace.Media; +import de.danoeh.antennapod.parser.feed.namespace.Rss20; +import de.danoeh.antennapod.parser.feed.namespace.SimpleChapters; +import de.danoeh.antennapod.parser.feed.namespace.Namespace; +import de.danoeh.antennapod.parser.feed.namespace.PodcastIndex; +import de.danoeh.antennapod.parser.feed.element.SyndElement; +import de.danoeh.antennapod.parser.feed.namespace.Atom; + +/** Superclass for all SAX Handlers which process Syndication formats */ +public class SyndHandler extends DefaultHandler { + private static final String TAG = "SyndHandler"; + private static final String DEFAULT_PREFIX = ""; + public final HandlerState state; + + public SyndHandler(Feed feed, TypeGetter.Type type) { + state = new HandlerState(feed); + if (type == TypeGetter.Type.RSS20 || type == TypeGetter.Type.RSS091) { + state.defaultNamespaces.push(new Rss20()); + } + } + + @Override + public void startElement(String uri, String localName, String qualifiedName, + Attributes attributes) throws SAXException { + state.contentBuf = new StringBuilder(); + Namespace handler = getHandlingNamespace(uri, qualifiedName); + if (handler != null) { + SyndElement element = handler.handleElementStart(localName, state, + attributes); + state.tagstack.push(element); + + } + } + + @Override + public void characters(char[] ch, int start, int length) + throws SAXException { + if (!state.tagstack.empty()) { + if (state.getTagstack().size() >= 2) { + if (state.contentBuf != null) { + state.contentBuf.append(ch, start, length); + } + } + } + } + + @Override + public void endElement(String uri, String localName, String qualifiedName) + throws SAXException { + Namespace handler = getHandlingNamespace(uri, qualifiedName); + if (handler != null) { + handler.handleElementEnd(localName, state); + state.tagstack.pop(); + + } + state.contentBuf = null; + + } + + @Override + public void endPrefixMapping(String prefix) throws SAXException { + if (state.defaultNamespaces.size() > 1 && prefix.equals(DEFAULT_PREFIX)) { + state.defaultNamespaces.pop(); + } + } + + @Override + public void startPrefixMapping(String prefix, String uri) + throws SAXException { + // Find the right namespace + if (!state.namespaces.containsKey(uri)) { + if (uri.equals(Atom.NSURI)) { + if (prefix.equals(DEFAULT_PREFIX)) { + state.defaultNamespaces.push(new Atom()); + } else if (prefix.equals(Atom.NSTAG)) { + state.namespaces.put(uri, new Atom()); + Log.d(TAG, "Recognized Atom namespace"); + } + } else if (uri.equals(Content.NSURI) + && prefix.equals(Content.NSTAG)) { + state.namespaces.put(uri, new Content()); + Log.d(TAG, "Recognized Content namespace"); + } else if (uri.equals(Itunes.NSURI) + && prefix.equals(Itunes.NSTAG)) { + state.namespaces.put(uri, new Itunes()); + Log.d(TAG, "Recognized ITunes namespace"); + } else if (uri.equals(SimpleChapters.NSURI) + && prefix.matches(SimpleChapters.NSTAG)) { + state.namespaces.put(uri, new SimpleChapters()); + Log.d(TAG, "Recognized SimpleChapters namespace"); + } else if (uri.equals(Media.NSURI) + && prefix.equals(Media.NSTAG)) { + state.namespaces.put(uri, new Media()); + Log.d(TAG, "Recognized media namespace"); + } else if (uri.equals(DublinCore.NSURI) + && prefix.equals(DublinCore.NSTAG)) { + state.namespaces.put(uri, new DublinCore()); + Log.d(TAG, "Recognized DublinCore namespace"); + } else if (uri.equals(PodcastIndex.NSURI) || uri.equals(PodcastIndex.NSURI2) + && prefix.equals(PodcastIndex.NSTAG)) { + state.namespaces.put(uri, new PodcastIndex()); + Log.d(TAG, "Recognized PodcastIndex namespace"); + } + } + } + + private Namespace getHandlingNamespace(String uri, String qualifiedName) { + Namespace handler = state.namespaces.get(uri); + if (handler == null && !state.defaultNamespaces.empty() + && !qualifiedName.contains(":")) { + handler = state.defaultNamespaces.peek(); + } + return handler; + } + + @Override + public void endDocument() throws SAXException { + super.endDocument(); + state.getFeed().setItems(state.getItems()); + } + + public HandlerState getState() { + return state; + } + +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/UnsupportedFeedtypeException.java similarity index 86% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/UnsupportedFeedtypeException.java index c9f9f19c8..74c126a50 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/UnsupportedFeedtypeException.java @@ -1,6 +1,7 @@ -package de.danoeh.antennapod.core.syndication.handler; +package de.danoeh.antennapod.parser.feed; -import de.danoeh.antennapod.core.syndication.handler.TypeGetter.Type; +import de.danoeh.antennapod.parser.feed.util.TypeGetter; +import de.danoeh.antennapod.parser.feed.util.TypeGetter.Type; public class UnsupportedFeedtypeException extends Exception { private static final long serialVersionUID = 9105878964928170669L; diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element/AtomText.java similarity index 80% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element/AtomText.java index 0c0561279..8acd9cbb4 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element/AtomText.java @@ -1,13 +1,11 @@ -package de.danoeh.antennapod.core.syndication.namespace.atom; +package de.danoeh.antennapod.parser.feed.element; import androidx.core.text.HtmlCompat; -import de.danoeh.antennapod.core.syndication.namespace.Namespace; -import de.danoeh.antennapod.core.syndication.namespace.SyndElement; +import de.danoeh.antennapod.parser.feed.namespace.Namespace; /** Represents Atom Element which contains text (content, title, summary). */ public class AtomText extends SyndElement { - public static final String TYPE_TEXT = "text"; public static final String TYPE_HTML = "html"; private static final String TYPE_XHTML = "xhtml"; diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element/SimpleChapter.java similarity index 88% rename from core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element/SimpleChapter.java index ca59f867b..069e49f09 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element/SimpleChapter.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.feed; +package de.danoeh.antennapod.parser.feed.element; import de.danoeh.antennapod.model.feed.Chapter; diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element/SyndElement.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element/SyndElement.java new file mode 100644 index 000000000..98dbe2801 --- /dev/null +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/element/SyndElement.java @@ -0,0 +1,22 @@ +package de.danoeh.antennapod.parser.feed.element; + +import de.danoeh.antennapod.parser.feed.namespace.Namespace; + +/** Defines a XML Element that is pushed on the tagstack */ +public class SyndElement { + private final String name; + private final Namespace namespace; + + public SyndElement(String name, Namespace namespace) { + this.name = name; + this.namespace = namespace; + } + + public Namespace getNamespace() { + return namespace; + } + + public String getName() { + return name; + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java similarity index 91% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java index b93f41771..ef802c355 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Atom.java @@ -1,23 +1,21 @@ -package de.danoeh.antennapod.core.syndication.namespace.atom; +package de.danoeh.antennapod.parser.feed.namespace; import android.text.TextUtils; import android.util.Log; import de.danoeh.antennapod.model.feed.FeedFunding; -import de.danoeh.antennapod.core.syndication.util.SyndStringUtils; +import de.danoeh.antennapod.parser.feed.HandlerState; +import de.danoeh.antennapod.parser.feed.element.AtomText; +import de.danoeh.antennapod.parser.feed.util.DateUtils; +import de.danoeh.antennapod.parser.feed.util.SyndStringUtils; import org.xml.sax.Attributes; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedMedia; -import de.danoeh.antennapod.core.syndication.handler.HandlerState; -import de.danoeh.antennapod.core.syndication.namespace.NSITunes; -import de.danoeh.antennapod.core.syndication.namespace.NSRSS20; -import de.danoeh.antennapod.core.syndication.namespace.Namespace; -import de.danoeh.antennapod.core.syndication.namespace.SyndElement; -import de.danoeh.antennapod.core.syndication.util.SyndTypeUtils; -import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.parser.feed.element.SyndElement; +import de.danoeh.antennapod.parser.feed.util.SyndTypeUtils; -public class NSAtom extends Namespace { +public class Atom extends Namespace { private static final String TAG = "NSAtom"; public static final String NSTAG = "atom"; public static final String NSURI = "http://www.w3.org/2005/Atom"; @@ -63,8 +61,8 @@ public class NSAtom extends Namespace { private static final String isText = TITLE + "|" + CONTENT + "|" + SUBTITLE + "|" + SUMMARY; - private static final String isFeed = FEED + "|" + NSRSS20.CHANNEL; - private static final String isFeedItem = ENTRY + "|" + NSRSS20.ITEM; + private static final String isFeed = FEED + "|" + Rss20.CHANNEL; + private static final String isFeedItem = ENTRY + "|" + Rss20.ITEM; @Override public SyndElement handleElementStart(String localName, HandlerState state, @@ -152,13 +150,13 @@ public class NSAtom extends Namespace { public void handleElementEnd(String localName, HandlerState state) { if (ENTRY.equals(localName)) { if (state.getCurrentItem() != null && - state.getTempObjects().containsKey(NSITunes.DURATION)) { + state.getTempObjects().containsKey(Itunes.DURATION)) { FeedItem currentItem = state.getCurrentItem(); if (currentItem.hasMedia()) { - Integer duration = (Integer) state.getTempObjects().get(NSITunes.DURATION); + Integer duration = (Integer) state.getTempObjects().get(Itunes.DURATION); currentItem.getMedia().setDuration(duration); } - state.getTempObjects().remove(NSITunes.DURATION); + state.getTempObjects().remove(Itunes.DURATION); } state.setCurrentItem(null); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Content.java similarity index 77% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Content.java index bedf377aa..3a7d5ac3a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSContent.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Content.java @@ -1,10 +1,10 @@ -package de.danoeh.antennapod.core.syndication.namespace; +package de.danoeh.antennapod.parser.feed.namespace; +import de.danoeh.antennapod.parser.feed.HandlerState; +import de.danoeh.antennapod.parser.feed.element.SyndElement; import org.xml.sax.Attributes; -import de.danoeh.antennapod.core.syndication.handler.HandlerState; - -public class NSContent extends Namespace { +public class Content extends Namespace { public static final String NSTAG = "content"; public static final String NSURI = "http://purl.org/rss/1.0/modules/content/"; @@ -21,5 +21,4 @@ public class NSContent extends Namespace { state.getCurrentItem().setDescriptionIfLonger(state.getContentBuf().toString()); } } - } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSDublinCore.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java similarity index 82% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSDublinCore.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java index 0394b754a..003f72e9b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSDublinCore.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java @@ -1,12 +1,13 @@ -package de.danoeh.antennapod.core.syndication.namespace; +package de.danoeh.antennapod.parser.feed.namespace; +import de.danoeh.antennapod.parser.feed.HandlerState; +import de.danoeh.antennapod.parser.feed.element.SyndElement; +import de.danoeh.antennapod.parser.feed.util.DateUtils; import org.xml.sax.Attributes; import de.danoeh.antennapod.model.feed.FeedItem; -import de.danoeh.antennapod.core.syndication.handler.HandlerState; -import de.danoeh.antennapod.core.util.DateUtils; -public class NSDublinCore extends Namespace { +public class DublinCore extends Namespace { private static final String TAG = "NSDublinCore"; public static final String NSTAG = "dc"; public static final String NSURI = "http://purl.org/dc/elements/1.1/"; diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Itunes.java similarity index 91% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Itunes.java index 1dc8d8af3..5f47f8377 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Itunes.java @@ -1,16 +1,17 @@ -package de.danoeh.antennapod.core.syndication.namespace; +package de.danoeh.antennapod.parser.feed.namespace; import android.text.TextUtils; import android.util.Log; import androidx.core.text.HtmlCompat; +import de.danoeh.antennapod.parser.feed.HandlerState; +import de.danoeh.antennapod.parser.feed.element.SyndElement; +import de.danoeh.antennapod.parser.feed.util.DurationParser; import org.xml.sax.Attributes; -import de.danoeh.antennapod.core.syndication.handler.HandlerState; -import de.danoeh.antennapod.core.syndication.parsers.DurationParser; -public class NSITunes extends Namespace { +public class Itunes extends Namespace { public static final String NSTAG = "itunes"; public static final String NSURI = "http://www.itunes.com/dtds/podcast-1.0.dtd"; @@ -106,7 +107,7 @@ public class NSITunes extends Namespace { if (state.getCurrentItem() != null) { state.getCurrentItem().setDescriptionIfLonger(summary); - } else if (NSRSS20.CHANNEL.equals(secondElementName) && state.getFeed() != null) { + } else if (Rss20.CHANNEL.equals(secondElementName) && state.getFeed() != null) { state.getFeed().setDescription(summary); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Media.java similarity index 94% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Media.java index 3dba0735d..f480a0417 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Media.java @@ -1,19 +1,20 @@ -package de.danoeh.antennapod.core.syndication.namespace; +package de.danoeh.antennapod.parser.feed.namespace; import android.text.TextUtils; import android.util.Log; +import de.danoeh.antennapod.parser.feed.HandlerState; +import de.danoeh.antennapod.parser.feed.element.SyndElement; import org.xml.sax.Attributes; import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.model.feed.FeedMedia; -import de.danoeh.antennapod.core.syndication.handler.HandlerState; -import de.danoeh.antennapod.core.syndication.namespace.atom.AtomText; -import de.danoeh.antennapod.core.syndication.util.SyndTypeUtils; +import de.danoeh.antennapod.parser.feed.element.AtomText; +import de.danoeh.antennapod.parser.feed.util.SyndTypeUtils; /** Processes tags from the http://search.yahoo.com/mrss/ namespace. */ -public class NSMedia extends Namespace { +public class Media extends Namespace { private static final String TAG = "NSMedia"; public static final String NSTAG = "media"; diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Namespace.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Namespace.java new file mode 100644 index 000000000..5273c6731 --- /dev/null +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Namespace.java @@ -0,0 +1,19 @@ +package de.danoeh.antennapod.parser.feed.namespace; + +import de.danoeh.antennapod.parser.feed.HandlerState; +import de.danoeh.antennapod.parser.feed.element.SyndElement; +import org.xml.sax.Attributes; + +public abstract class Namespace { + public static final String NSTAG = null; + public static final String NSURI = null; + + /** Called by a Feedhandler when in startElement and it detects a namespace element + * @return The SyndElement to push onto the stack + * */ + public abstract SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes); + + /** Called by a Feedhandler when in endElement and it detects a namespace element + * */ + public abstract void handleElementEnd(String localName, HandlerState state); +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/PodcastIndex.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/PodcastIndex.java similarity index 89% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/PodcastIndex.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/PodcastIndex.java index ee150f839..1d4a91192 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/PodcastIndex.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/PodcastIndex.java @@ -1,9 +1,10 @@ -package de.danoeh.antennapod.core.syndication.namespace; +package de.danoeh.antennapod.parser.feed.namespace; +import de.danoeh.antennapod.parser.feed.HandlerState; +import de.danoeh.antennapod.parser.feed.element.SyndElement; import org.jsoup.helper.StringUtil; import org.xml.sax.Attributes; import de.danoeh.antennapod.model.feed.FeedFunding; -import de.danoeh.antennapod.core.syndication.handler.HandlerState; public class PodcastIndex extends Namespace { diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Rss20.java similarity index 91% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Rss20.java index 50c2dc118..a49cd16dd 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Rss20.java @@ -1,21 +1,24 @@ -package de.danoeh.antennapod.core.syndication.namespace; +package de.danoeh.antennapod.parser.feed.namespace; import android.text.TextUtils; import android.util.Log; -import de.danoeh.antennapod.core.syndication.util.SyndStringUtils; +import de.danoeh.antennapod.parser.feed.HandlerState; +import de.danoeh.antennapod.parser.feed.element.SyndElement; +import de.danoeh.antennapod.parser.feed.util.DateUtils; +import de.danoeh.antennapod.parser.feed.util.SyndStringUtils; import org.xml.sax.Attributes; import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedMedia; -import de.danoeh.antennapod.core.syndication.handler.HandlerState; -import de.danoeh.antennapod.core.syndication.util.SyndTypeUtils; -import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.parser.feed.util.SyndTypeUtils; + +import java.util.Locale; /** * SAX-Parser for reading RSS-Feeds. */ -public class NSRSS20 extends Namespace { +public class Rss20 extends Namespace { private static final String TAG = "NSRSS20"; @@ -85,12 +88,12 @@ public class NSRSS20 extends Namespace { currentItem.setTitle(currentItem.getDescription()); } - if (state.getTempObjects().containsKey(NSITunes.DURATION)) { + if (state.getTempObjects().containsKey(Itunes.DURATION)) { if (currentItem.hasMedia()) { - Integer duration = (Integer) state.getTempObjects().get(NSITunes.DURATION); + Integer duration = (Integer) state.getTempObjects().get(Itunes.DURATION); currentItem.getMedia().setDuration(duration); } - state.getTempObjects().remove(NSITunes.DURATION); + state.getTempObjects().remove(Itunes.DURATION); } } state.setCurrentItem(null); @@ -137,7 +140,7 @@ public class NSRSS20 extends Namespace { state.getCurrentItem().setDescriptionIfLonger(content); } } else if (LANGUAGE.equals(localName) && state.getFeed() != null) { - state.getFeed().setLanguage(content.toLowerCase()); + state.getFeed().setLanguage(content.toLowerCase(Locale.US)); } } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/SimpleChapters.java similarity index 84% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/SimpleChapters.java index 97d0ebb53..e1912ed45 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/SimpleChapters.java @@ -1,17 +1,18 @@ -package de.danoeh.antennapod.core.syndication.namespace; +package de.danoeh.antennapod.parser.feed.namespace; import android.util.Log; +import de.danoeh.antennapod.parser.feed.HandlerState; +import de.danoeh.antennapod.parser.feed.element.SimpleChapter; +import de.danoeh.antennapod.parser.feed.element.SyndElement; +import de.danoeh.antennapod.parser.feed.util.DateUtils; import org.xml.sax.Attributes; import java.util.ArrayList; import de.danoeh.antennapod.model.feed.FeedItem; -import de.danoeh.antennapod.core.feed.SimpleChapter; -import de.danoeh.antennapod.core.syndication.handler.HandlerState; -import de.danoeh.antennapod.core.util.DateUtils; -public class NSSimpleChapters extends Namespace { +public class SimpleChapters extends Namespace { private static final String TAG = "NSSimpleChapters"; public static final String NSTAG = "psc|sc"; diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/DateUtils.java similarity index 76% rename from core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/DateUtils.java index a0b9fbef9..9b7f48769 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/DateUtils.java @@ -1,17 +1,13 @@ -package de.danoeh.antennapod.core.util; +package de.danoeh.antennapod.parser.feed.util; -import android.content.Context; import android.util.Log; import androidx.annotation.Nullable; import org.apache.commons.lang3.StringUtils; -import java.text.DateFormat; import java.text.ParsePosition; import java.text.SimpleDateFormat; -import java.util.Calendar; import java.util.Date; -import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; @@ -20,7 +16,9 @@ import java.util.TimeZone; */ public class DateUtils { - private DateUtils(){} + private DateUtils() { + + } private static final String TAG = "DateUtils"; private static final TimeZone defaultTimezone = TimeZone.getTimeZone("GMT"); @@ -58,7 +56,8 @@ public class DateUtils { // less than 4 decimal places: pad to have a consistent format for the parser } else if (current - start < 4) { if (current < date.length() - 1) { - date = date.substring(0, current) + StringUtils.repeat("0", 4 - (current - start)) + date.substring(current); + date = date.substring(0, current) + StringUtils.repeat("0", 4 - (current - start)) + + date.substring(current); } else { date = date.substring(0, current) + StringUtils.repeat("0", 4 - (current - start)); } @@ -161,42 +160,4 @@ public class DateUtils { } return result; } - - public static String formatRFC822Date(Date date) { - SimpleDateFormat format = new SimpleDateFormat("dd MMM yy HH:mm:ss Z", Locale.US); - return format.format(date); - } - - public static String formatRFC3339Local(Date date) { - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US); - return format.format(date); - } - - public static String formatRFC3339UTC(Date date) { - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); - format.setTimeZone(defaultTimezone); - return format.format(date); - } - - public static String formatAbbrev(final Context context, final Date date) { - if (date == null) { - return ""; - } - GregorianCalendar now = new GregorianCalendar(); - GregorianCalendar cal = new GregorianCalendar(); - cal.setTime(date); - boolean withinLastYear = now.get(Calendar.YEAR) == cal.get(Calendar.YEAR); - int format = android.text.format.DateUtils.FORMAT_ABBREV_ALL; - if (withinLastYear) { - format |= android.text.format.DateUtils.FORMAT_NO_YEAR; - } - return android.text.format.DateUtils.formatDateTime(context, date.getTime(), format); - } - - public static String formatForAccessibility(final Context context, final Date date) { - if (date == null) { - return ""; - } - return DateFormat.getDateInstance(DateFormat.LONG).format(date); - } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/parsers/DurationParser.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/DurationParser.java similarity index 95% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/parsers/DurationParser.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/DurationParser.java index 8b036c6a9..af79f542a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/parsers/DurationParser.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/DurationParser.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.syndication.parsers; +package de.danoeh.antennapod.parser.feed.util; import static java.util.concurrent.TimeUnit.HOURS; import static java.util.concurrent.TimeUnit.MINUTES; diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndStringUtils.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/SyndStringUtils.java similarity index 86% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndStringUtils.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/SyndStringUtils.java index addcdd4b7..403d1671f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndStringUtils.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/SyndStringUtils.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.syndication.util; +package de.danoeh.antennapod.parser.feed.util; public class SyndStringUtils { private SyndStringUtils() { diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/SyndTypeUtils.java similarity index 95% rename from core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java rename to parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/SyndTypeUtils.java index 155673296..2e6cf864f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndTypeUtils.java +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/SyndTypeUtils.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.syndication.util; +package de.danoeh.antennapod.parser.feed.util; import android.webkit.MimeTypeMap; import org.apache.commons.io.FilenameUtils; diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/TypeGetter.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/TypeGetter.java new file mode 100644 index 000000000..12834f94f --- /dev/null +++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/util/TypeGetter.java @@ -0,0 +1,121 @@ +package de.danoeh.antennapod.parser.feed.util; + +import android.util.Log; + +import de.danoeh.antennapod.parser.feed.UnsupportedFeedtypeException; +import org.apache.commons.io.input.XmlStreamReader; +import org.jsoup.Jsoup; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Reader; + +import de.danoeh.antennapod.model.feed.Feed; + +/** Gets the type of a specific feed by reading the root element. */ +public class TypeGetter { + private static final String TAG = "TypeGetter"; + + public enum Type { + RSS20, RSS091, ATOM, INVALID + } + + private static final String ATOM_ROOT = "feed"; + private static final String RSS_ROOT = "rss"; + + public Type getType(Feed feed) throws UnsupportedFeedtypeException { + XmlPullParserFactory factory; + if (feed.getFile_url() != null) { + Reader reader = null; + try { + factory = XmlPullParserFactory.newInstance(); + factory.setNamespaceAware(true); + XmlPullParser xpp = factory.newPullParser(); + reader = createReader(feed); + xpp.setInput(reader); + int eventType = xpp.getEventType(); + + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + String tag = xpp.getName(); + switch (tag) { + case ATOM_ROOT: + feed.setType(Feed.TYPE_ATOM1); + Log.d(TAG, "Recognized type Atom"); + + String strLang = xpp.getAttributeValue("http://www.w3.org/XML/1998/namespace", "lang"); + if (strLang != null) { + feed.setLanguage(strLang); + } + + return Type.ATOM; + case RSS_ROOT: + String strVersion = xpp.getAttributeValue(null, "version"); + if (strVersion == null) { + feed.setType(Feed.TYPE_RSS2); + Log.d(TAG, "Assuming type RSS 2.0"); + return Type.RSS20; + } else if (strVersion.equals("2.0")) { + feed.setType(Feed.TYPE_RSS2); + Log.d(TAG, "Recognized type RSS 2.0"); + return Type.RSS20; + } else if (strVersion.equals("0.91") || strVersion.equals("0.92")) { + Log.d(TAG, "Recognized type RSS 0.91/0.92"); + return Type.RSS091; + } + throw new UnsupportedFeedtypeException("Unsupported rss version"); + default: + Log.d(TAG, "Type is invalid"); + throw new UnsupportedFeedtypeException(Type.INVALID, tag); + } + } else { + eventType = xpp.next(); + } + } + } catch (XmlPullParserException e) { + e.printStackTrace(); + // XML document might actually be a HTML document -> try to parse as HTML + String rootElement = null; + try { + if (Jsoup.parse(new File(feed.getFile_url()), null) != null) { + rootElement = "html"; + } + } catch (IOException e1) { + e1.printStackTrace(); + } + throw new UnsupportedFeedtypeException(Type.INVALID, rootElement); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + Log.d(TAG, "Type is invalid"); + throw new UnsupportedFeedtypeException(Type.INVALID); + } + + private Reader createReader(Feed feed) { + Reader reader; + try { + reader = new XmlStreamReader(new File(feed.getFile_url())); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + return reader; + } +} diff --git a/core/src/test/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomTextTest.java b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/element/AtomTextTest.java similarity index 76% rename from core/src/test/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomTextTest.java rename to parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/element/AtomTextTest.java index 6bc614364..2ec91ab1d 100644 --- a/core/src/test/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomTextTest.java +++ b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/element/AtomTextTest.java @@ -1,5 +1,7 @@ -package de.danoeh.antennapod.core.syndication.namespace.atom; +package de.danoeh.antennapod.parser.feed.element.element; +import de.danoeh.antennapod.parser.feed.element.AtomText; +import de.danoeh.antennapod.parser.feed.namespace.Atom; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -27,7 +29,7 @@ public class AtomTextTest { @Test public void testProcessingHtml() { for (String[] pair : TEST_DATA) { - final AtomText atomText = new AtomText("", new NSAtom(), AtomText.TYPE_HTML); + final AtomText atomText = new AtomText("", new Atom(), AtomText.TYPE_HTML); atomText.setContent(pair[0]); assertEquals(pair[1], atomText.getProcessedContent()); } diff --git a/core/src/test/java/de/danoeh/antennapod/core/syndication/handler/AtomParserTest.java b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace/AtomParserTest.java similarity index 98% rename from core/src/test/java/de/danoeh/antennapod/core/syndication/handler/AtomParserTest.java rename to parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace/AtomParserTest.java index 36ca7f0d8..ba8aaf4f0 100644 --- a/core/src/test/java/de/danoeh/antennapod/core/syndication/handler/AtomParserTest.java +++ b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace/AtomParserTest.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.syndication.handler; +package de.danoeh.antennapod.parser.feed.element.namespace; import org.junit.Test; import org.junit.runner.RunWith; @@ -12,9 +12,9 @@ import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedMedia; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertFalse; /** * Tests for Atom feeds in FeedHandler. diff --git a/core/src/test/java/de/danoeh/antennapod/core/syndication/handler/FeedParserTestHelper.java b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace/FeedParserTestHelper.java similarity index 89% rename from core/src/test/java/de/danoeh/antennapod/core/syndication/handler/FeedParserTestHelper.java rename to parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace/FeedParserTestHelper.java index b9318b377..5cc52d8cb 100644 --- a/core/src/test/java/de/danoeh/antennapod/core/syndication/handler/FeedParserTestHelper.java +++ b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace/FeedParserTestHelper.java @@ -1,10 +1,11 @@ -package de.danoeh.antennapod.core.syndication.handler; +package de.danoeh.antennapod.parser.feed.element.namespace; import androidx.annotation.NonNull; import java.io.File; import de.danoeh.antennapod.model.feed.Feed; +import de.danoeh.antennapod.parser.feed.FeedHandler; /** * Tests for FeedHandler. diff --git a/core/src/test/java/de/danoeh/antennapod/core/syndication/handler/RssParserTest.java b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace/RssParserTest.java similarity index 98% rename from core/src/test/java/de/danoeh/antennapod/core/syndication/handler/RssParserTest.java rename to parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace/RssParserTest.java index d95c8b3ab..8f8942d7b 100644 --- a/core/src/test/java/de/danoeh/antennapod/core/syndication/handler/RssParserTest.java +++ b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/namespace/RssParserTest.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.syndication.handler; +package de.danoeh.antennapod.parser.feed.element.namespace; import android.text.TextUtils; import org.junit.Test; diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/DateUtilsTest.java b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/util/DateUtilsTest.java similarity index 98% rename from core/src/test/java/de/danoeh/antennapod/core/util/DateUtilsTest.java rename to parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/util/DateUtilsTest.java index 92888ae8b..1f039d703 100644 --- a/core/src/test/java/de/danoeh/antennapod/core/util/DateUtilsTest.java +++ b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/util/DateUtilsTest.java @@ -1,5 +1,6 @@ -package de.danoeh.antennapod.core.util; +package de.danoeh.antennapod.parser.feed.element.util; +import de.danoeh.antennapod.parser.feed.util.DateUtils; import org.junit.Test; import java.util.Calendar; diff --git a/core/src/test/java/de/danoeh/antennapod/core/syndication/parsers/DurationParserTest.java b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/util/DurationParserTest.java similarity index 91% rename from core/src/test/java/de/danoeh/antennapod/core/syndication/parsers/DurationParserTest.java rename to parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/util/DurationParserTest.java index e7c861969..91d9ea5ed 100644 --- a/core/src/test/java/de/danoeh/antennapod/core/syndication/parsers/DurationParserTest.java +++ b/parser/feed/src/test/java/de/danoeh/antennapod/parser/feed/element/util/DurationParserTest.java @@ -1,5 +1,6 @@ -package de.danoeh.antennapod.core.syndication.parsers; +package de.danoeh.antennapod.parser.feed.element.util; +import de.danoeh.antennapod.parser.feed.util.DurationParser; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/resources/feed-atom-testAtomBasic.xml b/parser/feed/src/test/resources/feed-atom-testAtomBasic.xml similarity index 100% rename from core/src/test/resources/feed-atom-testAtomBasic.xml rename to parser/feed/src/test/resources/feed-atom-testAtomBasic.xml diff --git a/core/src/test/resources/feed-atom-testEmptyRelLinks.xml b/parser/feed/src/test/resources/feed-atom-testEmptyRelLinks.xml similarity index 100% rename from core/src/test/resources/feed-atom-testEmptyRelLinks.xml rename to parser/feed/src/test/resources/feed-atom-testEmptyRelLinks.xml diff --git a/core/src/test/resources/feed-atom-testLogoWithWhitespace.xml b/parser/feed/src/test/resources/feed-atom-testLogoWithWhitespace.xml similarity index 100% rename from core/src/test/resources/feed-atom-testLogoWithWhitespace.xml rename to parser/feed/src/test/resources/feed-atom-testLogoWithWhitespace.xml diff --git a/core/src/test/resources/feed-rss-testImageWithWhitespace.xml b/parser/feed/src/test/resources/feed-rss-testImageWithWhitespace.xml similarity index 100% rename from core/src/test/resources/feed-rss-testImageWithWhitespace.xml rename to parser/feed/src/test/resources/feed-rss-testImageWithWhitespace.xml diff --git a/core/src/test/resources/feed-rss-testMediaContentMime.xml b/parser/feed/src/test/resources/feed-rss-testMediaContentMime.xml similarity index 100% rename from core/src/test/resources/feed-rss-testMediaContentMime.xml rename to parser/feed/src/test/resources/feed-rss-testMediaContentMime.xml diff --git a/core/src/test/resources/feed-rss-testMultipleFundingTags.xml b/parser/feed/src/test/resources/feed-rss-testMultipleFundingTags.xml similarity index 100% rename from core/src/test/resources/feed-rss-testMultipleFundingTags.xml rename to parser/feed/src/test/resources/feed-rss-testMultipleFundingTags.xml diff --git a/core/src/test/resources/feed-rss-testRss2Basic.xml b/parser/feed/src/test/resources/feed-rss-testRss2Basic.xml similarity index 100% rename from core/src/test/resources/feed-rss-testRss2Basic.xml rename to parser/feed/src/test/resources/feed-rss-testRss2Basic.xml diff --git a/settings.gradle b/settings.gradle index 27cc1a863..edf55858e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,6 +6,8 @@ include ':net:ssl' include ':net:sync:gpoddernet' include ':net:sync:model' +include ':parser:feed' + include ':ui:app-start-intent' include ':ui:common' include ':ui:png-icons'