diff --git a/lib/pinchflat/podcasts/opml_feed_builder.ex b/lib/pinchflat/podcasts/opml_feed_builder.ex new file mode 100644 index 00000000..c764a661 --- /dev/null +++ b/lib/pinchflat/podcasts/opml_feed_builder.ex @@ -0,0 +1,40 @@ +defmodule Pinchflat.Podcasts.OpmlFeedBuilder do + @moduledoc """ + Methods for building an OPML feed for a list of sources. + """ + + import Pinchflat.Utils.XmlUtils, only: [safe: 1] + + alias PinchflatWeb.Router.Helpers, as: Routes + + @doc """ + Builds an OPML feed for a given list of sources. + + Returns an XML document as a string. + """ + def build(url_base, sources) do + sources_xml = + Enum.map( + sources, + &""" + + """ + ) + + """ + + + + All Sources + + + #{Enum.join(sources_xml, "\n")} + + + """ + end + + defp source_route(url_base, source) do + Path.join(url_base, "#{Routes.podcast_path(PinchflatWeb.Endpoint, :rss_feed, source.uuid)}.xml") + end +end diff --git a/lib/pinchflat/podcasts/podcast_helpers.ex b/lib/pinchflat/podcasts/podcast_helpers.ex index 041107c5..30ba17ac 100644 --- a/lib/pinchflat/podcasts/podcast_helpers.ex +++ b/lib/pinchflat/podcasts/podcast_helpers.ex @@ -5,11 +5,25 @@ defmodule Pinchflat.Podcasts.PodcastHelpers do """ use Pinchflat.Media.MediaQuery + use Pinchflat.Sources.SourcesQuery alias Pinchflat.Repo alias Pinchflat.Metadata.MediaMetadata alias Pinchflat.Metadata.SourceMetadata + @doc """ + Returns a list of sources that are not marked for deletion. + + Returns: [%Source{}] + """ + def opml_sources() do + SourcesQuery.new() + |> select([s], %{custom_name: s.custom_name, uuid: s.uuid}) + |> where([s], is_nil(s.marked_for_deletion_at)) + |> order_by(asc: :custom_name) + |> Repo.all() + end + @doc """ Returns a list of media items that have been downloaded to disk and have been proven to still exist there. diff --git a/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex b/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex index d69e4f6d..84401fe4 100644 --- a/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex +++ b/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex @@ -6,8 +6,19 @@ defmodule PinchflatWeb.Podcasts.PodcastController do alias Pinchflat.Sources.Source alias Pinchflat.Media.MediaItem alias Pinchflat.Podcasts.RssFeedBuilder + alias Pinchflat.Podcasts.OpmlFeedBuilder alias Pinchflat.Podcasts.PodcastHelpers + def opml_feed(conn, _params) do + url_base = url(conn, ~p"/") + xml = OpmlFeedBuilder.build(url_base, PodcastHelpers.opml_sources()) + + conn + |> put_resp_content_type("application/opml+xml") + |> put_resp_header("content-disposition", "inline") + |> send_resp(200, xml) + end + def rss_feed(conn, %{"uuid" => uuid}) do source = Repo.get_by!(Source, uuid: uuid) url_base = url(conn, ~p"/") diff --git a/lib/pinchflat_web/controllers/sources/source_html.ex b/lib/pinchflat_web/controllers/sources/source_html.ex index d9673ebc..4692a043 100644 --- a/lib/pinchflat_web/controllers/sources/source_html.ex +++ b/lib/pinchflat_web/controllers/sources/source_html.ex @@ -43,6 +43,10 @@ defmodule PinchflatWeb.Sources.SourceHTML do url(conn, ~p"/sources/#{source.uuid}/feed") <> ".xml" end + def opml_feed_url(conn) do + url(conn, ~p"/sources/opml") <> ".xml" + end + def output_path_template_override_placeholders(media_profiles) do media_profiles |> Enum.map(&{&1.id, &1.output_path_template}) diff --git a/lib/pinchflat_web/controllers/sources/source_html/index.html.heex b/lib/pinchflat_web/controllers/sources/source_html/index.html.heex index 47615525..6ace2bc9 100644 --- a/lib/pinchflat_web/controllers/sources/source_html/index.html.heex +++ b/lib/pinchflat_web/controllers/sources/source_html/index.html.heex @@ -1,6 +1,16 @@

Sources