diff --git a/lib/pinchflat/podcasts/podcast_helpers.ex b/lib/pinchflat/podcasts/podcast_helpers.ex
new file mode 100644
index 0000000..d67482a
--- /dev/null
+++ b/lib/pinchflat/podcasts/podcast_helpers.ex
@@ -0,0 +1,44 @@
+defmodule Pinchflat.Podcasts.PostcastHelpers do
+ alias Pinchflat.Repo
+ alias Pinchflat.Media
+
+ # TODO: test
+ def persisted_media_items_for(source, opts \\ []) do
+ limit = Keyword.get(opts, :limit, 500)
+
+ source
+ |> Media.list_downloaded_media_items_for(limit: limit)
+ |> Enum.filter(fn media_item -> File.exists?(media_item.media_filepath) end)
+ end
+
+ # TODO: test
+ # Returns string or nil
+ def select_cover_image(source) do
+ source_with_preloads = Repo.preload(source, :metadata)
+ # Since we're looking for the metadata image, _any_ downloaded media
+ # items should be fine
+ media_items = Media.list_downloaded_media_items_for(source, limit: 1)
+
+ source_with_preloads
+ |> get_images_by_preference(media_items)
+ |> Enum.reject(&is_nil(&1))
+ |> Enum.find(&File.exists?/1)
+ end
+
+ def get_images_by_preference(source_with_preloads, []) do
+ source_metadata = source_with_preloads.metadata
+
+ [
+ source_metadata.poster_filepath,
+ source_metadata.banner_filepath
+ ]
+ end
+
+ def get_images_by_preference(source_with_preloads, [media_item | _]) do
+ media_item_with_preloads = Repo.preload(media_item, :metadata)
+ media_item_metadata = media_item_with_preloads.metadata
+ source_images = get_images_by_preference(source_with_preloads, [])
+
+ source_images ++ [media_item_metadata.thumbnail_filepath]
+ end
+end
diff --git a/lib/pinchflat/podcasts/rss_feed_builder.ex b/lib/pinchflat/podcasts/rss_feed_builder.ex
index 1c921ed..0e6b260 100644
--- a/lib/pinchflat/podcasts/rss_feed_builder.ex
+++ b/lib/pinchflat/podcasts/rss_feed_builder.ex
@@ -1,6 +1,9 @@
defmodule Pinchflat.Podcasts.RssFeedBuilder do
@datetime_format "%a, %d %b %Y %H:%M:%S %z"
+ alias Pinchflat.Podcasts.PostcastHelpers
+ alias PinchflatWeb.Router.Helpers, as: Routes
+
# TODO: test
# TODO: only MIs that are confirmed to exist on-disk should be provided
def build(source, media_items) do
@@ -36,14 +39,14 @@ defmodule Pinchflat.Podcasts.RssFeedBuilder do
yes
#{source.uuid}
- #{generate_source_image_path(source)}
+ #{feed_image_path(source)}
#{source.custom_name}
#{source.original_url}
#{source.custom_name}
#{source.custom_name}
yes
-
+
false
@@ -63,7 +66,7 @@ defmodule Pinchflat.Podcasts.RssFeedBuilder do
#{media_item.description}
#{generate_upload_date(media_item)}
@@ -76,18 +79,26 @@ defmodule Pinchflat.Podcasts.RssFeedBuilder do
end
defp generate_self_link(source) do
- "#{url_base()}/sources/#{source.uuid}/feed.xml"
+ Path.join(url_base(), "#{podcast_route(:rss_feed, source.uuid)}.xml")
end
- defp generate_media_stream_path(media_item) do
+ defp media_stream_path(media_item) do
extension = Path.extname(media_item.media_filepath)
- "#{url_base()}/media/#{media_item.uuid}/stream#{extension}"
+ Path.join(url_base(), "#{media_route(:stream, media_item.uuid)}#{extension}")
end
- # TODO: add extension maybe. maybe refactor controller to handle this
- defp generate_source_image_path(source) do
- "#{url_base()}/sources/#{source.uuid}/feed_image"
+ defp feed_image_path(source) do
+ image_path_on_disk = PostcastHelpers.select_cover_image(source)
+
+ case image_path_on_disk do
+ nil ->
+ ""
+
+ _ ->
+ extension = Path.extname(image_path_on_disk)
+ Path.join(url_base(), "#{podcast_route(:feed_image, source.uuid)}#{extension}")
+ end
end
defp generate_upload_date(media_item) do
@@ -102,6 +113,14 @@ defmodule Pinchflat.Podcasts.RssFeedBuilder do
MIME.from_path(media_item.media_filepath)
end
+ defp podcast_route(action, params) do
+ Routes.podcast_path(PinchflatWeb.Endpoint, action, params)
+ end
+
+ defp media_route(action, params) do
+ Routes.media_item_path(PinchflatWeb.Endpoint, action, params)
+ end
+
defp url_base do
Application.get_env(:pinchflat, :url_base)
end
diff --git a/lib/pinchflat_web.ex b/lib/pinchflat_web.ex
index e7fbc32..ef58d00 100644
--- a/lib/pinchflat_web.ex
+++ b/lib/pinchflat_web.ex
@@ -21,7 +21,7 @@ defmodule PinchflatWeb do
def router do
quote do
- use Phoenix.Router, helpers: false
+ use Phoenix.Router, helpers: true
# Import common connection and controller functions to use in pipelines
import Plug.Conn
diff --git a/lib/pinchflat_web/controllers/media_items/media_item_controller.ex b/lib/pinchflat_web/controllers/media_items/media_item_controller.ex
index bf44c77..5efc308 100644
--- a/lib/pinchflat_web/controllers/media_items/media_item_controller.ex
+++ b/lib/pinchflat_web/controllers/media_items/media_item_controller.ex
@@ -36,7 +36,7 @@ defmodule PinchflatWeb.MediaItems.MediaItemController do
#
# Uses the UUID instead of the ID to avoid enumeration attacks
# since streaming is a public endpoint (ie: no auth required)
- def stream(conn, %{"id" => uuid}) do
+ def stream(conn, %{"uuid" => uuid}) do
media_item = Repo.get_by!(MediaItem, uuid: uuid)
if File.exists?(media_item.media_filepath) do
diff --git a/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex b/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex
new file mode 100644
index 0000000..b5e2c36
--- /dev/null
+++ b/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex
@@ -0,0 +1,34 @@
+defmodule PinchflatWeb.Podcasts.PodcastController do
+ use PinchflatWeb, :controller
+
+ alias Pinchflat.Repo
+ alias Pinchflat.Podcasts.RssFeedBuilder
+ alias Pinchflat.Podcasts.PostcastHelpers
+
+ # TODO: test
+ def rss_feed(conn, %{"uuid" => uuid}) do
+ # TODO: change this to UUID
+ source = Repo.get_by!(Source, id: uuid)
+ media_items = PostcastHelpers.persisted_media_items_for(source)
+ xml = RssFeedBuilder.build(source, media_items)
+
+ conn
+ |> put_resp_content_type("application/rss+xml")
+ |> put_resp_header("content-disposition", "inline")
+ |> send_resp(200, xml)
+ end
+
+ # TODO: test
+ def feed_image(conn, %{"uuid" => uuid}) do
+ source = Repo.get_by!(Source, uuid: uuid)
+ filepath = PostcastHelpers.select_cover_image(source)
+
+ if filepath && File.exists?(filepath) do
+ conn
+ |> put_resp_content_type(MIME.from_path(filepath))
+ |> send_file(200, filepath)
+ else
+ send_resp(conn, 404, "File not found")
+ end
+ end
+end
diff --git a/lib/pinchflat_web/controllers/sources/source_controller.ex b/lib/pinchflat_web/controllers/sources/source_controller.ex
index b67846f..3211ccc 100644
--- a/lib/pinchflat_web/controllers/sources/source_controller.ex
+++ b/lib/pinchflat_web/controllers/sources/source_controller.ex
@@ -7,7 +7,6 @@ defmodule PinchflatWeb.Sources.SourceController do
alias Pinchflat.Sources
alias Pinchflat.Profiles
alias Pinchflat.Sources.Source
- alias Pinchflat.Podcasts.RssFeedBuilder
def index(conn, _params) do
sources = Repo.preload(Sources.list_sources(), :media_profile)
@@ -59,47 +58,6 @@ defmodule PinchflatWeb.Sources.SourceController do
)
end
- # TODO: test
- # TODO: maybe move both of these to a separate controller
- def feed(conn, %{"id" => uuid}) do
- # TODO: change this to UUID
- source = Repo.get_by!(Source, id: uuid)
- media_items = Media.list_downloaded_media_items_for(source, limit: 100)
-
- xml = RssFeedBuilder.build(source, media_items)
-
- conn
- |> put_resp_content_type("application/rss+xml")
- |> put_resp_header("content-disposition", "inline")
- |> send_resp(200, xml)
- end
-
- # TODO: test
- # TODO: look into media_items having a thumbnail path when the image is embedded but not on disk
- # TODO: pull these images from the internal metadata instead. this implies I'll have to hook up
- # metadata images for sources
- def feed_image(conn, %{"id" => uuid}) do
- source = Repo.get_by!(Source, uuid: uuid)
- media_item = Media.list_downloaded_media_items_for(source, limit: 1)
-
- filepath =
- case {source.poster_filepath, media_item} do
- {poster, _} when poster != nil -> poster
- {nil, [media_item]} -> media_item.thumbnail_filepath
- _ -> nil
- end
-
- IO.inspect(filepath)
-
- if filepath && File.exists?(filepath) do
- conn
- |> put_resp_content_type(MIME.from_path(filepath))
- |> send_file(200, filepath)
- else
- send_resp(conn, 404, "File not found")
- end
- end
-
def edit(conn, %{"id" => id}) do
source = Sources.get_source!(id)
changeset = Sources.change_source(source)
diff --git a/lib/pinchflat_web/router.ex b/lib/pinchflat_web/router.ex
index 0a1071c..3c8cc67 100644
--- a/lib/pinchflat_web/router.ex
+++ b/lib/pinchflat_web/router.ex
@@ -36,10 +36,10 @@ defmodule PinchflatWeb.Router do
# TODO: consider putting the basic auth here behind a config flag
# so people that want RSS feeds to work can enable it.
scope "/", PinchflatWeb do
- get "/sources/:id/feed", Sources.SourceController, :feed
- get "/sources/:id/feed_image", Sources.SourceController, :feed_image
+ get "/sources/:uuid/rss_feed", Podcasts.PodcastController, :rss_feed
+ get "/sources/:uuid/feed_image", Podcasts.PodcastController, :feed_image
- get "/media/:id/stream", MediaItems.MediaItemController, :stream
+ get "/media/:uuid/stream", MediaItems.MediaItemController, :stream
end
# Enable LiveDashboard and Swoosh mailbox preview in development