pinchflat/lib/pinchflat/media_client/media_downloader.ex

88 lines
2.9 KiB
Elixir

defmodule Pinchflat.MediaClient.MediaDownloader do
@moduledoc """
This is the integration layer for actually downloading medias.
It takes into account the media profile's settings in order
to download the media with the desired options.
Technically hardcodes the yt-dlp backend for now, but should leave
it open-ish for future expansion (just in case).
"""
alias Pinchflat.Repo
alias Pinchflat.Media
alias Pinchflat.Media.MediaItem
alias Pinchflat.MediaClient.Backends.YtDlp.Media, as: YtDlpMedia
alias Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder, as: YtDlpDownloadOptionBuilder
alias Pinchflat.MediaClient.Backends.YtDlp.MetadataParser, as: YtDlpMetadataParser
alias Pinchflat.MediaClient.Backends.YtDlp.MetadataFileHelpers, as: YtDlpMetadataHelpers
@doc """
Downloads media for a media item, updating the media item based on the metadata
returned by the backend. Also saves the entire metadata response to the associated
media_metadata record.
NOTE: related methods (like the download worker) won't download if the media item's source
is set to not download media. However, I'm not enforcing that here since I need this for testing.
This may change in the future but I'm not stressed.
Returns {:ok, %MediaItem{}} | {:error, any, ...any}
"""
def download_for_media_item(%MediaItem{} = media_item, backend \\ :yt_dlp) do
item_with_preloads = Repo.preload(media_item, [:metadata, source: :media_profile])
case download_with_options(media_item.original_url, item_with_preloads, backend) do
{:ok, parsed_json} ->
{parser, helpers} = metadata_parsers(backend)
parsed_attrs =
parsed_json
|> parser.parse_for_media_item()
|> Map.merge(%{
media_downloaded_at: DateTime.utc_now(),
metadata: %{
metadata_filepath: helpers.compress_and_store_metadata_for(media_item, parsed_json),
thumbnail_filepath: helpers.download_and_store_thumbnail_for(media_item, parsed_json)
}
})
# Don't forgor to use preloaded associations or updates to
# associations won't work!
Media.update_media_item(item_with_preloads, parsed_attrs)
err ->
err
end
end
# def download_for_source(source, url, backend \\ :yt_dlp) do
# # Create MI from source and URL
# media_item = nil
# end
defp download_with_options(url, item_with_preloads, backend) do
option_builder = option_builder(backend)
media_backend = media_backend(backend)
{:ok, options} = option_builder.build(item_with_preloads)
media_backend.download(url, options)
end
defp option_builder(backend) do
case backend do
:yt_dlp -> YtDlpDownloadOptionBuilder
end
end
defp media_backend(backend) do
case backend do
:yt_dlp -> YtDlpMedia
end
end
defp metadata_parsers(backend) do
case backend do
:yt_dlp -> {YtDlpMetadataParser, YtDlpMetadataHelpers}
end
end
end