Added options for downloading/embedding metadata
This commit is contained in:
parent
44bdf6a708
commit
af5e6cb8b9
10 changed files with 1789 additions and 1773 deletions
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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]}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Reference in a new issue