diff --git a/lib/pinchflat/podcasts/rss_feed_builder.ex b/lib/pinchflat/podcasts/rss_feed_builder.ex
index 5e23edd0..0bb3ee77 100644
--- a/lib/pinchflat/podcasts/rss_feed_builder.ex
+++ b/lib/pinchflat/podcasts/rss_feed_builder.ex
@@ -75,6 +75,8 @@ defmodule Pinchflat.Podcasts.RssFeedBuilder do
end
defp build_media_item_xml(source, media_item, url_base) do
+ item_image_path = item_image_path(url_base, media_item)
+
"""
-
#{media_item.uuid}
@@ -91,6 +93,10 @@ defmodule Pinchflat.Podcasts.RssFeedBuilder do
#{safe(source.custom_name)}
#{safe(media_item.title)}
+
+ #{item_image_path && ~s()}
+ #{item_image_path && ~s()}
+
false
"""
@@ -117,6 +123,16 @@ defmodule Pinchflat.Podcasts.RssFeedBuilder do
end
end
+ def item_image_path(url_base, media_item) do
+ if media_item.thumbnail_filepath && File.exists?(media_item.thumbnail_filepath) do
+ extension = Path.extname(media_item.thumbnail_filepath)
+
+ Path.join(url_base, "#{podcast_route(:episode_image, media_item.uuid)}#{extension}")
+ else
+ nil
+ end
+ end
+
defp generate_upload_date(media_item) do
media_item.upload_date
|> DatetimeUtils.date_to_datetime()
diff --git a/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex b/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex
index f59e579f..65e0ca7a 100644
--- a/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex
+++ b/lib/pinchflat_web/controllers/podcasts/podcast_controller.ex
@@ -2,8 +2,9 @@ defmodule PinchflatWeb.Podcasts.PodcastController do
use PinchflatWeb, :controller
alias Pinchflat.Repo
- alias Pinchflat.Media.MediaQuery
alias Pinchflat.Sources.Source
+ alias Pinchflat.Media.MediaItem
+ alias Pinchflat.Media.MediaQuery
alias Pinchflat.Podcasts.RssFeedBuilder
alias Pinchflat.Podcasts.PodcastHelpers
@@ -40,4 +41,16 @@ defmodule PinchflatWeb.Podcasts.PodcastController do
|> send_file(200, filepath)
end
end
+
+ def episode_image(conn, %{"uuid" => uuid}) do
+ media_item = Repo.get_by!(MediaItem, uuid: uuid)
+
+ if media_item.thumbnail_filepath && File.exists?(media_item.thumbnail_filepath) do
+ conn
+ |> put_resp_content_type(MIME.from_path(media_item.thumbnail_filepath))
+ |> send_file(200, media_item.thumbnail_filepath)
+ else
+ send_resp(conn, 404, "Image not found")
+ end
+ end
end
diff --git a/lib/pinchflat_web/router.ex b/lib/pinchflat_web/router.ex
index b04f8400..2829315e 100644
--- a/lib/pinchflat_web/router.ex
+++ b/lib/pinchflat_web/router.ex
@@ -50,6 +50,7 @@ defmodule PinchflatWeb.Router do
get "/sources/:uuid/feed", Podcasts.PodcastController, :rss_feed
get "/sources/:uuid/feed_image", Podcasts.PodcastController, :feed_image
+ get "/media/:uuid/episode_image", Podcasts.PodcastController, :episode_image
get "/media/:uuid/stream", MediaItems.MediaItemController, :stream
end
diff --git a/test/pinchflat/podcasts/rss_feed_builder_test.exs b/test/pinchflat/podcasts/rss_feed_builder_test.exs
index 99bf32cf..bec1aaca 100644
--- a/test/pinchflat/podcasts/rss_feed_builder_test.exs
+++ b/test/pinchflat/podcasts/rss_feed_builder_test.exs
@@ -137,6 +137,34 @@ defmodule Pinchflat.Podcasts.RssFeedBuilderTest do
assert String.contains?(item_xml, ~s(length="1234"))
assert String.contains?(item_xml, ~s(type="video/mp4"))
end
+
+ test "returns image tags if the media has a thumbnail", %{source: source} do
+ media_item = media_item_with_attachments(%{source_id: source.id, media_size_bytes: 1234})
+
+ res = RssFeedBuilder.build(source)
+ [_before, item_xml, _after] = String.split(res, ~r(?item>))
+
+ assert String.contains?(
+ item_xml,
+ ~s()
+ )
+
+ assert String.contains?(
+ item_xml,
+ ~s()
+ )
+ end
+
+ test "does not return image tags if the media does not have a thumbnail", %{source: source} do
+ media_item = media_item_with_attachments(%{source_id: source.id})
+ File.rm!(media_item.thumbnail_filepath)
+
+ res = RssFeedBuilder.build(source)
+ [_before, item_xml, _after] = String.split(res, ~r(?item>))
+
+ refute String.contains?(item_xml, ~s(itunes:image))
+ refute String.contains?(item_xml, ~s(podcast:images))
+ end
end
defp format_date(date) do
diff --git a/test/pinchflat_web/controllers/podcast_controller_test.exs b/test/pinchflat_web/controllers/podcast_controller_test.exs
index 0e327ebc..676ab54b 100644
--- a/test/pinchflat_web/controllers/podcast_controller_test.exs
+++ b/test/pinchflat_web/controllers/podcast_controller_test.exs
@@ -1,6 +1,7 @@
defmodule PinchflatWeb.PodcastControllerTest do
use PinchflatWeb.ConnCase
+ import Pinchflat.MediaFixtures
import Pinchflat.SourcesFixtures
describe "rss_feed" do
@@ -35,4 +36,25 @@ defmodule PinchflatWeb.PodcastControllerTest do
assert conn.resp_body == "Image not found"
end
end
+
+ describe "episode_image" do
+ test "returns an episode image if one can be found", %{conn: conn} do
+ media_item = media_item_with_attachments()
+
+ conn = get(conn, ~p"/media/#{media_item.uuid}/episode_image" <> ".jpg")
+
+ assert conn.status == 200
+ assert {"content-type", "image/jpeg; charset=utf-8"} in conn.resp_headers
+ assert conn.resp_body == File.read!(media_item.thumbnail_filepath)
+ end
+
+ test "returns 404 if an image cannot be found", %{conn: conn} do
+ media_item = media_item_fixture()
+
+ conn = get(conn, ~p"/media/#{media_item.uuid}/episode_image" <> ".jpg")
+
+ assert conn.status == 404
+ assert conn.resp_body == "Image not found"
+ end
+ end
end
diff --git a/test/support/fixtures/media_fixtures.ex b/test/support/fixtures/media_fixtures.ex
index f80f4942..54dedcaa 100644
--- a/test/support/fixtures/media_fixtures.ex
+++ b/test/support/fixtures/media_fixtures.ex
@@ -67,16 +67,24 @@ defmodule Pinchflat.MediaFixtures do
end
def media_item_with_attachments(attrs \\ %{}) do
- stored_media_filepath =
+ base_dir =
Path.join([
Application.get_env(:pinchflat, :media_directory),
- "#{:rand.uniform(1_000_000)}",
- "#{:rand.uniform(1_000_000)}_media.mp4"
+ "#{:rand.uniform(1_000_000)}"
])
+ stored_media_filepath = Path.join(base_dir, "#media.mp4")
+ thumbnail_filepath = Path.join(base_dir, "thumbnail.jpg")
+
FilesystemUtils.cp_p!(media_filepath_fixture(), stored_media_filepath)
+ FilesystemUtils.cp_p!(thumbnail_filepath_fixture(), thumbnail_filepath)
+
+ merged_attrs =
+ Map.merge(attrs, %{
+ media_filepath: stored_media_filepath,
+ thumbnail_filepath: thumbnail_filepath
+ })
- merged_attrs = Map.merge(attrs, %{media_filepath: stored_media_filepath})
media_item_fixture(merged_attrs)
end