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()) + + 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()) + + 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