[WIP] Working on refactoring feed
This commit is contained in:
parent
d199f02a57
commit
ab47bdbdf5
7 changed files with 111 additions and 56 deletions
44
lib/pinchflat/podcasts/podcast_helpers.ex
Normal file
44
lib/pinchflat/podcasts/podcast_helpers.ex
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
|||
<podcast:locked>yes</podcast:locked>
|
||||
<podcast:guid>#{source.uuid}</podcast:guid>
|
||||
<image>
|
||||
<url>#{generate_source_image_path(source)}</url>
|
||||
<url>#{feed_image_path(source)}</url>
|
||||
<title>#{source.custom_name}</title>
|
||||
<link>#{source.original_url}</link>
|
||||
</image>
|
||||
<itunes:author>#{source.custom_name}</itunes:author>
|
||||
<itunes:subtitle>#{source.custom_name}</itunes:subtitle>
|
||||
<itunes:block>yes</itunes:block>
|
||||
<itunes:image href="#{generate_source_image_path(source)}"></itunes:image>
|
||||
<itunes:image href="#{feed_image_path(source)}"></itunes:image>
|
||||
<itunes:explicit>false</itunes:explicit>
|
||||
<itunes:category text="TV & Film"></itunes:category>
|
||||
|
||||
|
|
@ -63,7 +66,7 @@ defmodule Pinchflat.Podcasts.RssFeedBuilder do
|
|||
<description>#{media_item.description}</description>
|
||||
<pubDate>#{generate_upload_date(media_item)}</pubDate>
|
||||
<enclosure
|
||||
url="#{generate_media_stream_path(media_item)}"
|
||||
url="#{media_stream_path(media_item)}"
|
||||
length="#{media_item.media_size_bytes}"
|
||||
type="#{determine_content_type(media_item)}">
|
||||
</enclosure>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
34
lib/pinchflat_web/controllers/podcasts/podcast_controller.ex
Normal file
34
lib/pinchflat_web/controllers/podcasts/podcast_controller.ex
Normal file
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue