Added options for downloading/embedding metadata

This commit is contained in:
Kieran Eglin 2024-02-06 12:46:46 -08:00
parent 44bdf6a708
commit af5e6cb8b9
No known key found for this signature in database
GPG key ID: 193984967FCF432D
10 changed files with 1789 additions and 1773 deletions

View file

@ -10,14 +10,23 @@ defmodule Pinchflat.Media.MediaItem do
alias Pinchflat.MediaSource.Source alias Pinchflat.MediaSource.Source
alias Pinchflat.Media.MediaMetadata alias Pinchflat.Media.MediaMetadata
@allowed_fields ~w(
title
media_id
media_filepath
source_id
subtitle_filepaths
thumbnail_filepath
metadata_filepath
)a
@required_fields ~w(media_id source_id)a @required_fields ~w(media_id source_id)a
@allowed_fields ~w(title media_id media_filepath source_id subtitle_filepaths thumbnail_filepath)a
schema "media_items" do schema "media_items" do
field :title, :string field :title, :string
field :media_id, :string field :media_id, :string
field :media_filepath, :string field :media_filepath, :string
field :thumbnail_filepath, :string field :thumbnail_filepath, :string
field :metadata_filepath, :string
# This is an array of [iso-2 language, filepath] pairs. Probably could # This is an array of [iso-2 language, filepath] pairs. Probably could
# be an associated record, but I don't see the benefit right now. # be an associated record, but I don't see the benefit right now.
# Will very likely revisit because I can't leave well-enough alone. # Will very likely revisit because I can't leave well-enough alone.

View file

@ -26,6 +26,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.MetadataParser do
|> Map.merge(parse_media_metadata(metadata)) |> Map.merge(parse_media_metadata(metadata))
|> Map.merge(parse_subtitle_metadata(metadata)) |> Map.merge(parse_subtitle_metadata(metadata))
|> Map.merge(parse_thumbnail_metadata(metadata)) |> Map.merge(parse_thumbnail_metadata(metadata))
|> Map.merge(parse_infojson_metadata(metadata))
end end
defp parse_media_metadata(metadata) do defp parse_media_metadata(metadata) do
@ -60,4 +61,10 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.MetadataParser do
thumbnail_filepath: thumbnail_filepath thumbnail_filepath: thumbnail_filepath
} }
end end
defp parse_infojson_metadata(metadata) do
%{
metadata_filepath: metadata["infojson_filename"]
}
end
end end

View file

@ -17,6 +17,8 @@ defmodule Pinchflat.Profiles.MediaProfile do
sub_langs sub_langs
download_thumbnail download_thumbnail
embed_thumbnail embed_thumbnail
download_metadata
embed_metadata
shorts_behaviour shorts_behaviour
livestream_behaviour livestream_behaviour
)a )a
@ -35,6 +37,9 @@ defmodule Pinchflat.Profiles.MediaProfile do
field :download_thumbnail, :boolean, default: true field :download_thumbnail, :boolean, default: true
field :embed_thumbnail, :boolean, default: true field :embed_thumbnail, :boolean, default: true
field :download_metadata, :boolean, default: true
field :embed_metadata, :boolean, default: true
# NOTE: these do NOT speed up indexing - the indexer still has to go # NOTE: these do NOT speed up indexing - the indexer still has to go
# through the entire collection to determine if a video is a short or # through the entire collection to determine if a video is a short or
# a livestream. # a livestream.

View file

@ -25,6 +25,7 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder do
default_options() ++ default_options() ++
subtitle_options(media_profile) ++ subtitle_options(media_profile) ++
thumbnail_options(media_profile) ++ thumbnail_options(media_profile) ++
metadata_options(media_profile) ++
output_options(media_profile) output_options(media_profile)
{:ok, built_options} {:ok, built_options}
@ -32,10 +33,7 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder do
# This will be updated a lot as I add new options to profiles # This will be updated a lot as I add new options to profiles
defp default_options do defp default_options do
[ [:no_progress]
:embed_metadata,
:no_progress
]
end end
defp subtitle_options(media_profile) do defp subtitle_options(media_profile) do
@ -77,6 +75,18 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder do
end) end)
end end
defp metadata_options(media_profile) do
mapped_struct = Map.from_struct(media_profile)
Enum.reduce(mapped_struct, [], fn attr, acc ->
case attr do
{:download_metadata, true} -> acc ++ [:write_info_json, :clean_info_json]
{:embed_metadata, true} -> acc ++ [:embed_metadata]
_ -> acc
end
end)
end
defp output_options(media_profile) do defp output_options(media_profile) do
{:ok, output_path} = OutputPathBuilder.build(media_profile.output_path_template) {:ok, output_path} = OutputPathBuilder.build(media_profile.output_path_template)

View file

@ -15,6 +15,10 @@
<.input field={f[:download_thumbnail]} type="checkbox" label="Download Thumbnail" /> <.input field={f[:download_thumbnail]} type="checkbox" label="Download Thumbnail" />
<.input field={f[:embed_thumbnail]} type="checkbox" label="Embed Thumbnail" /> <.input field={f[:embed_thumbnail]} type="checkbox" label="Embed Thumbnail" />
<h3>Metadata Options</h3>
<.input field={f[:download_metadata]} type="checkbox" label="Download Metadata" />
<.input field={f[:embed_metadata]} type="checkbox" label="Embed Metadata" />
<h3>Release Format Options</h3> <h3>Release Format Options</h3>
<.input <.input
field={f[:shorts_behaviour]} field={f[:shorts_behaviour]}

View file

@ -0,0 +1,14 @@
defmodule Pinchflat.Repo.Migrations.AddMetadataOptionsToMediaProfiles do
use Ecto.Migration
def change do
alter table(:media_profiles) do
add :download_metadata, :boolean, default: true, null: false
add :embed_metadata, :boolean, default: true, null: false
end
alter table(:media_items) do
add :metadata_filepath, :string
end
end
end

View file

@ -47,7 +47,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.MediaParserTest do
test "extracts the subtitle filepaths", %{metadata: metadata} do test "extracts the subtitle filepaths", %{metadata: metadata} do
result = Parser.parse_for_media_item(metadata) result = Parser.parse_for_media_item(metadata)
assert [["de", german_filepath], ["en", english_filepath]] = result.subtitle_filepaths assert [["de", german_filepath], ["en", english_filepath] | _rest] = result.subtitle_filepaths
assert String.ends_with?(english_filepath, ".en.srt") assert String.ends_with?(english_filepath, ".en.srt")
assert String.ends_with?(german_filepath, ".de.srt") assert String.ends_with?(german_filepath, ".de.srt")
@ -107,4 +107,20 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.MediaParserTest do
assert result.thumbnail_filepath == nil assert result.thumbnail_filepath == nil
end end
end end
describe "parse_for_media_item/1 when testing infojson metadata" do
test "extracts the metadata filepath", %{metadata: metadata} do
result = Parser.parse_for_media_item(metadata)
assert String.ends_with?(result.metadata_filepath, ".info.json")
end
test "doesn't freak out if the video has no infojson", %{metadata: metadata} do
metadata = Map.put(metadata, "infojson_filename", nil)
result = Parser.parse_for_media_item(metadata)
assert result.metadata_filepath == nil
end
end
end end

View file

@ -28,25 +28,6 @@ defmodule Pinchflat.MediaClient.VideoDownloaderTest do
assert {:ok, _} = VideoDownloader.download_for_media_item(media_item) assert {:ok, _} = VideoDownloader.download_for_media_item(media_item)
end end
test "it writes attributes to the media item", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
{:ok, render_metadata(:media_metadata)}
end)
assert %{
media_filepath: nil,
title: nil,
subtitle_filepaths: [],
thumbnail_filepath: nil
} = media_item
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item)
assert updated_media_item.media_filepath
assert updated_media_item.title
assert length(updated_media_item.subtitle_filepaths) > 0
assert updated_media_item.thumbnail_filepath
end
test "it saves the metadata to the database", %{media_item: media_item} do test "it saves the metadata to the database", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
{:ok, render_metadata(:media_metadata)} {:ok, render_metadata(:media_metadata)}
@ -66,4 +47,44 @@ defmodule Pinchflat.MediaClient.VideoDownloaderTest do
assert {:error, :some_error} = VideoDownloader.download_for_media_item(media_item) assert {:error, :some_error} = VideoDownloader.download_for_media_item(media_item)
end end
end end
describe "download_for_media_item/3 when testing media_item attributes" do
setup do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
{:ok, render_metadata(:media_metadata)}
end)
:ok
end
test "it extracts the title", %{media_item: media_item} do
assert media_item.title == nil
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item)
assert updated_media_item.title == "Trying to Wheelie Without the Rear Brake"
end
test "it extracts the media_filepath", %{media_item: media_item} do
assert media_item.media_filepath == nil
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item)
assert String.ends_with?(updated_media_item.media_filepath, ".mkv")
end
test "it extracts the subtitle_filepaths", %{media_item: media_item} do
assert media_item.subtitle_filepaths == []
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item)
assert [["de", _], ["en", _] | _rest] = updated_media_item.subtitle_filepaths
end
test "it extracts the thumbnail_filepath", %{media_item: media_item} do
assert media_item.thumbnail_filepath == nil
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item)
assert String.ends_with?(updated_media_item.thumbnail_filepath, ".webp")
end
test "it extracts the metadata_filepath", %{media_item: media_item} do
assert media_item.metadata_filepath == nil
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item)
assert String.ends_with?(updated_media_item.metadata_filepath, ".info.json")
end
end
end end

View file

@ -125,4 +125,37 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilderTest do
refute :embed_thumbnail in res refute :embed_thumbnail in res
end end
end end
describe "build/1 when testing metadata options" do
test "includes :write_info_json option when specified" do
media_profile = %MediaProfile{@media_profile | download_metadata: true}
assert {:ok, res} = DownloadOptionBuilder.build(media_profile)
assert :write_info_json in res
assert :clean_info_json in res
end
test "includes :embed_metadata option when specified" do
media_profile = %MediaProfile{@media_profile | embed_metadata: true}
assert {:ok, res} = DownloadOptionBuilder.build(media_profile)
assert :embed_metadata in res
end
test "doesn't include these options when not specified" do
media_profile = %MediaProfile{
@media_profile
| embed_metadata: false,
download_metadata: false
}
assert {:ok, res} = DownloadOptionBuilder.build(media_profile)
refute :write_info_json in res
refute :clean_info_json in res
refute :embed_metadata in res
end
end
end end

File diff suppressed because one or more lines are too long