[VERY WIP] basic podcast RSS setup

This commit is contained in:
Kieran Eglin 2024-03-23 15:53:20 -07:00
parent 0d9003cffd
commit 67f8000f5a
No known key found for this signature in database
GPG key ID: 193984967FCF432D
3 changed files with 98 additions and 51 deletions

View file

@ -21,6 +21,7 @@ config :pinchflat,
# If either is unset, basic auth will not be used.
basic_auth_username: System.get_env("BASIC_AUTH_USERNAME"),
basic_auth_password: System.get_env("BASIC_AUTH_PASSWORD"),
url_base: System.get_env("BASIC_AUTH_PASSWORD") || "http://localhost:4008",
file_watcher_poll_interval: 1000
# Configures the endpoint

View file

@ -66,7 +66,8 @@ if config_env() == :prod do
config :pinchflat,
yt_dlp_executable: System.find_executable("yt-dlp"),
metadata_directory: metadata_path,
dns_cluster_query: System.get_env("DNS_CLUSTER_QUERY")
dns_cluster_query: System.get_env("DNS_CLUSTER_QUERY"),
url_base: System.get_env("URL_BASE") || "http://localhost:8945"
config :pinchflat, Pinchflat.Repo,
database: db_path,
@ -123,54 +124,4 @@ if config_env() == :prod do
formatter: Logger.Formatter.new()
}}
]
# ## SSL Support
#
# To get SSL working, you will need to add the `https` key
# to your endpoint configuration:
#
# config :pinchflat, PinchflatWeb.Endpoint,
# https: [
# ...,
# port: 443,
# cipher_suite: :strong,
# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
# certfile: System.get_env("SOME_APP_SSL_CERT_PATH")
# ]
#
# The `cipher_suite` is set to `:strong` to support only the
# latest and more secure SSL ciphers. This means old browsers
# and clients may not be supported. You can set it to
# `:compatible` for wider support.
#
# `:keyfile` and `:certfile` expect an absolute path to the key
# and cert in disk or a relative path inside priv, for example
# "priv/ssl/server.key". For all supported SSL configuration
# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1
#
# We also recommend setting `force_ssl` in your endpoint, ensuring
# no data is ever sent via http, always redirecting to https:
#
# config :pinchflat, PinchflatWeb.Endpoint,
# force_ssl: [hsts: true]
#
# Check `Plug.SSL` for all available options in `force_ssl`.
# ## Configuring the mailer
#
# In production you need to configure the mailer to use a different adapter.
# Also, you may need to configure the Swoosh API client of your choice if you
# are not using SMTP. Here is an example of the configuration:
#
# config :pinchflat, Pinchflat.Mailer,
# adapter: Swoosh.Adapters.Mailgun,
# api_key: System.get_env("MAILGUN_API_KEY"),
# domain: System.get_env("MAILGUN_DOMAIN")
#
# For this example you need include a HTTP client required by Swoosh API client.
# Swoosh supports Hackney and Finch out of the box:
#
# config :swoosh, :api_client, Swoosh.ApiClient.Hackney
#
# See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details.
end

View file

@ -0,0 +1,95 @@
defmodule Pinchflat.Podcasts.RssFeedBuilder do
@datetime_format "%a, %d %b %Y %H:%M:%S %z"
# TODO: only MIs that are confirmed to exist on-disk should be provided
def build(source, media_items) do
media_item_xml = Enum.map(media_items, &build_media_item_xml(source, &1))
build_source_xml(source, media_item_xml)
end
defp build_media_item_xml(source, media_item) do
# NOTE: improvements for future:
# - Add <itunes:duration>
# - Serve proper images instead of the placeholders
"""
<item>
<guid isPermaLink="false">#{media_item.uuid}</guid>
<title>#{media_item.title}</title>
<link>#{media_item.original_url}</link>
<description>#{media_item.description}</description>
<pubDate>#{generate_upload_date(media_item)}</pubDate>
<enclosure
url="#{generate_media_stream_path(media_item)}"
length="#{media_item.media_size_bytes}"
type="#{determine_content_type(media_item)}">
</enclosure>
<itunes:author>#{source.custom_name}</itunes:author>
<itunes:subtitle>#{media_item.title}</itunes:subtitle>
<itunes:summary><![CDATA[#{media_item.description}]]></itunes:summary>
<itunes:image href="https://raw.githubusercontent.com/kieraneglin/pinchflat/master/priv/static/images/originals/logo.png"></itunes:image>
<itunes:explicit>false</itunes:explicit>
</item>
"""
end
defp build_source_xml(source, media_item_xml) do
# Useful: https://validator.w3.org/feed/#validate_by_input
# NOTE: improvements for future:
# - Add real <description>
# - Add <itunes:summary>
# - Serve proper images instead of the placeholders
# - Ass <atom:link href="<LINK TO FEED>" rel="self" type="application/rss+xml" />
"""
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
<channel>
<title>#{source.custom_name}</title>
<link>#{source.original_url}</link>
<description>#{source.custom_name}</description>
<category>TV &amp; Film</category>
<generator>Generated by Pinchflat</generator>
<language>en-us</language>
<lastBuildDate>#{Calendar.strftime(DateTime.utc_now(), @datetime_format)}</lastBuildDate>
<pubDate>#{Calendar.strftime(source.inserted_at, @datetime_format)}</pubDate>
<image>
<url>https://raw.githubusercontent.com/kieraneglin/pinchflat/master/priv/static/images/originals/logo.png</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="https://raw.githubusercontent.com/kieraneglin/pinchflat/master/priv/static/images/originals/logo.png"></itunes:image>
<itunes:explicit>false</itunes:explicit>
<itunes:category text="TV &amp; Film"></itunes:category>
#{Enum.join(media_item_xml, "\n")}
</channel>
</rss>
"""
end
defp generate_media_stream_path(media_item) do
extension = Path.extname(media_item.media_filepath)
"#{url_base()}/media/#{media_item.uuid}/stream#{extension}"
end
defp generate_upload_date(media_item) do
media_item.upload_date
|> Date.to_gregorian_days()
|> Kernel.*(86400)
|> DateTime.from_gregorian_seconds()
|> Calendar.strftime(@datetime_format)
end
defp determine_content_type(media_item) do
MIME.from_path(media_item.media_filepath)
end
defp url_base do
Application.get_env(:pinchflat, :url_base)
end
end