Adds thumbnails as episode-level images for podcasts (#201)
This commit is contained in:
parent
f65ebea738
commit
09cac46e14
6 changed files with 94 additions and 6 deletions
|
|
@ -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)
|
||||
|
||||
"""
|
||||
<item>
|
||||
<guid isPermaLink="false">#{media_item.uuid}</guid>
|
||||
|
|
@ -91,6 +93,10 @@ defmodule Pinchflat.Podcasts.RssFeedBuilder do
|
|||
<itunes:author>#{safe(source.custom_name)}</itunes:author>
|
||||
<itunes:subtitle>#{safe(media_item.title)}</itunes:subtitle>
|
||||
<itunes:summary><![CDATA[#{media_item.description}]]></itunes:summary>
|
||||
|
||||
#{item_image_path && ~s(<itunes:image href="#{safe(item_image_path)}"></itunes:image>)}
|
||||
#{item_image_path && ~s(<podcast:images srcset="#{safe(item_image_path)}" />)}
|
||||
|
||||
<itunes:explicit>false</itunes:explicit>
|
||||
</item>
|
||||
"""
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(<itunes:image href="http://localhost:8945/media/#{media_item.uuid}/episode_image.jpg"></itunes:image>)
|
||||
)
|
||||
|
||||
assert String.contains?(
|
||||
item_xml,
|
||||
~s(<podcast:images srcset="http://localhost:8945/media/#{media_item.uuid}/episode_image.jpg" />)
|
||||
)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)}"
|
||||
])
|
||||
|
||||
FilesystemUtils.cp_p!(media_filepath_fixture(), stored_media_filepath)
|
||||
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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue