Added output path override to table and download option builder

This commit is contained in:
Kieran Eglin 2024-04-11 09:39:32 -07:00
parent 3acdb5ccba
commit 4df43f0993
No known key found for this signature in database
GPG key ID: 193984967FCF432D
7 changed files with 92 additions and 4 deletions

View file

@ -3,6 +3,7 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilder do
Builds the options for yt-dlp to download media based on the given media profile.
"""
alias Pinchflat.Sources
alias Pinchflat.Sources.Source
alias Pinchflat.Media.MediaItem
alias Pinchflat.Downloading.OutputPathBuilder
@ -30,12 +31,12 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilder do
@doc """
Builds the output path for yt-dlp to download media based on the given source's
media profile.
media profile. Uses the source's override output path template if it exists.
Returns binary()
"""
def build_output_path_for(%Source{} = source_with_preloads) do
output_path_template = source_with_preloads.media_profile.output_path_template
output_path_template = Sources.output_path_template(source_with_preloads)
build_output_path(output_path_template, source_with_preloads)
end
@ -184,7 +185,7 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilder do
# It's dependent on the output_path_template being a string ending `.{{ ext }}`
# (or equivalent), but that's validated by the MediaProfile schema.
defp determine_thumbnail_location(media_item_with_preloads) do
output_path_template = media_item_with_preloads.source.media_profile.output_path_template
output_path_template = Sources.output_path_template(media_item_with_preloads.source)
output_path_template
|> String.split(~r{\.}, include_captures: true)

View file

@ -80,7 +80,8 @@ defmodule Pinchflat.Profiles.MediaProfile do
|> unique_constraint(:name)
end
defp ext_regex do
@doc false
def ext_regex do
~r/\.({{ ?ext ?}}|%\( ?ext ?\)[sS])$/
end
end

View file

@ -32,6 +32,7 @@ defmodule Pinchflat.Sources.Source do
retention_period_days
title_filter_regex
media_profile_id
output_path_template_override
)a
# Expensive API calls are made when a source is inserted/updated so
@ -76,6 +77,7 @@ defmodule Pinchflat.Sources.Source do
field :retention_period_days, :integer
field :original_url, :string
field :title_filter_regex, :string
field :output_path_template_override, :string
field :series_directory, :string
field :nfo_filepath, :string
@ -109,6 +111,8 @@ defmodule Pinchflat.Sources.Source do
|> dynamic_default(:uuid, fn _ -> Ecto.UUID.generate() end)
|> validate_required(required_fields)
|> validate_number(:retention_period_days, greater_than_or_equal_to: 0)
# Ensures it ends with `.{{ ext }}` or `.%(ext)s` or similar (with a little wiggle room)
|> validate_format(:output_path_template_override, MediaProfile.ext_regex(), message: "must end with .{{ ext }}")
|> cast_assoc(:metadata, with: &SourceMetadata.changeset/2, required: false)
|> unique_constraint([:collection_id, :media_profile_id, :title_filter_regex], error_key: :original_url)
end

View file

@ -19,6 +19,19 @@ defmodule Pinchflat.Sources do
alias Pinchflat.SlowIndexing.SlowIndexingHelpers
alias Pinchflat.Metadata.SourceMetadataStorageWorker
@doc """
Returns the relevant output path template for a source.
Pulls from the source's override if present, otherwise uses the media profile's.
Returns binary()
"""
def output_path_template(source) do
source = Repo.preload(source, :media_profile)
media_profile = source.media_profile
source.output_path_template_override || media_profile.output_path_template
end
@doc """
Returns the list of sources. Returns [%Source{}, ...]
"""

View file

@ -0,0 +1,9 @@
defmodule Pinchflat.Repo.Migrations.AddOutputTemplateToSources do
use Ecto.Migration
def change do
alter table(:sources) do
add :output_path_template_override, :string
end
end
end

View file

@ -4,6 +4,7 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilderTest do
import Pinchflat.SourcesFixtures
import Pinchflat.ProfilesFixtures
alias Pinchflat.Sources
alias Pinchflat.Profiles
alias Pinchflat.Utils.FilesystemUtils
alias Pinchflat.Downloading.DownloadOptionBuilder
@ -31,6 +32,20 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilderTest do
assert {:output, "/tmp/test/media/#{media_item.source.custom_name}.%(ext)s"} in res
end
test "uses source's output override if present", %{media_item: media_item} do
source = media_item.source
{:ok, _} = Sources.update_source(source, %{output_path_template_override: "override.%(ext)s"})
media_item =
media_item
|> Repo.reload()
|> Repo.preload(source: :media_profile)
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:output, "/tmp/test/media/override.%(ext)s"} in res
end
end
describe "build/1 when testing default options" do
@ -135,6 +150,20 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilderTest do
assert {:output, "thumbnail:/tmp/test/media/%(title)S-thumb.%(ext)s"} in res
end
test "appends -thumb to source's output path override, if present", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{download_thumbnail: true})
{:ok, _} = Sources.update_source(media_item.source, %{output_path_template_override: "override.%(ext)s"})
media_item =
media_item
|> Repo.reload()
|> Repo.preload(source: :media_profile)
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:output, "thumbnail:/tmp/test/media/override-thumb.%(ext)s"} in res
end
test "converts thumbnail to jpg when download_thumbnail is true", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{download_thumbnail: true})
@ -359,6 +388,15 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilderTest do
assert path == "/tmp/test/media/%(title)S.%(ext)s"
end
test "uses source's output override if present", %{media_item: media_item} do
source = media_item.source
{:ok, source} = Sources.update_source(source, %{output_path_template_override: "override.%(ext)s"})
path = DownloadOptionBuilder.build_output_path_for(source)
assert path == "/tmp/test/media/override.%(ext)s"
end
end
defp update_media_profile_attribute(media_item_with_preloads, attrs) do

View file

@ -35,6 +35,28 @@ defmodule Pinchflat.SourcesTest do
end
end
describe "output_path_template/1" do
test "returns the source's override if present" do
source = source_fixture(%{output_path_template_override: "/override/{{ title }}.{{ ext }}"})
assert Sources.output_path_template(source) == "/override/{{ title }}.{{ ext }}"
end
test "returns the media profile's template if no override is present" do
media_profile = media_profile_fixture(%{output_path_template: "/profile/{{ title }}.{{ ext }}"})
source = source_fixture(%{media_profile_id: media_profile.id})
assert Sources.output_path_template(source) == "/profile/{{ title }}.{{ ext }}"
end
test "Treats empty strings as being blank" do
media_profile = media_profile_fixture(%{output_path_template: "/profile/{{ title }}.{{ ext }}"})
source = source_fixture(%{media_profile_id: media_profile.id, output_path_template_override: " "})
assert Sources.output_path_template(source) == "/profile/{{ title }}.{{ ext }}"
end
end
describe "list_sources/0" do
test "it returns all sources" do
source = source_fixture()