diff --git a/lib/pinchflat/downloading/quality_option_builder.ex b/lib/pinchflat/downloading/quality_option_builder.ex index b7edc8f..1884502 100644 --- a/lib/pinchflat/downloading/quality_option_builder.ex +++ b/lib/pinchflat/downloading/quality_option_builder.ex @@ -1,19 +1,31 @@ defmodule Pinchflat.Downloading.QualityOptionBuilder do + @moduledoc """ + A standalone builder module for building quality-related options for yt-dlp to download media. + + Currently exclusively used in DownloadOptionBuilder since this logic is too complex to just + place in the main module. + """ + alias Pinchflat.Settings alias Pinchflat.Profiles.MediaProfile - # TODO: test - def build(%MediaProfile{preferred_resolution: :audio, media_container: container}) do + @doc """ + Builds the quality-related options for yt-dlp to download media based on the given media profile + + Includes things like container, preferred format/codec, and audio track options. + """ + def build(%MediaProfile{preferred_resolution: :audio, media_container: container} = media_profile) do acodec = Settings.get!(:audio_codec_preference) [ :extract_audio, format_sort: "+acodec:#{acodec}", - audio_format: container || "best" - ] ++ build_format_string(nil) + audio_format: container || "best", + format: build_format_string(media_profile) + ] end - def build(%MediaProfile{preferred_resolution: resolution_atom, media_container: container}) do + def build(%MediaProfile{preferred_resolution: resolution_atom, media_container: container} = media_profile) do vcodec = Settings.get!(:video_codec_preference) acodec = Settings.get!(:audio_codec_preference) {resolution_string, _} = resolution_atom |> Atom.to_string() |> Integer.parse() @@ -21,22 +33,27 @@ defmodule Pinchflat.Downloading.QualityOptionBuilder do [ # Since Plex doesn't support reading metadata from MKV remux_video: container || "mp4", - format_sort: "res:#{resolution_string},+codec:#{vcodec}:#{acodec}" - ] ++ build_format_string(nil) + format_sort: "res:#{resolution_string},+codec:#{vcodec}:#{acodec}", + format: build_format_string(media_profile) + ] end - # TODO: pass in the entire media profile once we have the language preference column - # TODO: test - # TODO: Set to ba/b if it's audio-only - defp build_format_string(language_preference) do - if language_preference do - ["bestvideo+bestaudio[#{build_format_modifier(language_preference)}]/bestvideo*+bestaudio/best"] + defp build_format_string(%MediaProfile{preferred_resolution: :audio, audio_track: audio_track}) do + if audio_track do + "bestaudio[#{build_format_modifier(audio_track)}]/bestaudio/best" else - ["bestvideo*+bestaudio/best"] + "bestaudio/best" + end + end + + defp build_format_string(%MediaProfile{audio_track: audio_track}) do + if audio_track do + "bestvideo+bestaudio[#{build_format_modifier(audio_track)}]/bestvideo*+bestaudio/best" + else + "bestvideo*+bestaudio/best" end end - # TODO: test defp build_format_modifier("original"), do: "format_note*=original" defp build_format_modifier("default"), do: "format_note*=(default)" # This uses the carat to anchor the language to the beginning of the string diff --git a/lib/pinchflat/profiles/media_profile.ex b/lib/pinchflat/profiles/media_profile.ex index 0d156e9..8c9c61d 100644 --- a/lib/pinchflat/profiles/media_profile.ex +++ b/lib/pinchflat/profiles/media_profile.ex @@ -26,7 +26,7 @@ defmodule Pinchflat.Profiles.MediaProfile do sponsorblock_categories shorts_behaviour livestream_behaviour - audio_lang + audio_track preferred_resolution media_container redownload_delay_days @@ -66,7 +66,7 @@ defmodule Pinchflat.Profiles.MediaProfile do # See `build_format_clauses` in the Media context for more. field :shorts_behaviour, Ecto.Enum, values: ~w(include exclude only)a, default: :include field :livestream_behaviour, Ecto.Enum, values: ~w(include exclude only)a, default: :include - field :audio_lang, :string + field :audio_track, :string field :preferred_resolution, Ecto.Enum, values: ~w(4320p 2160p 1080p 720p 480p 360p audio)a, default: :"1080p" field :media_container, :string, default: nil diff --git a/priv/repo/erd.png b/priv/repo/erd.png index cb4dc3c..74613c1 100644 Binary files a/priv/repo/erd.png and b/priv/repo/erd.png differ diff --git a/priv/repo/migrations/20241127172054_add_audio_lang_to_media_profiles.exs b/priv/repo/migrations/20241127172054_add_audio_lang_to_media_profiles.exs index 9c6607e..b19d981 100644 --- a/priv/repo/migrations/20241127172054_add_audio_lang_to_media_profiles.exs +++ b/priv/repo/migrations/20241127172054_add_audio_lang_to_media_profiles.exs @@ -3,7 +3,7 @@ defmodule Pinchflat.Repo.Migrations.AddAudioLangToMediaProfiles do def change do alter table(:media_profiles) do - add :audio_lang, :string + add :audio_track, :string end end end diff --git a/test/pinchflat/downloading/download_option_builder_test.exs b/test/pinchflat/downloading/download_option_builder_test.exs index 071ec8d..403d9a5 100644 --- a/test/pinchflat/downloading/download_option_builder_test.exs +++ b/test/pinchflat/downloading/download_option_builder_test.exs @@ -6,7 +6,6 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilderTest do alias Pinchflat.Sources alias Pinchflat.Profiles - alias Pinchflat.Settings alias Pinchflat.Utils.FilesystemUtils alias Pinchflat.Downloading.DownloadOptionBuilder diff --git a/test/pinchflat/downloading/quality_option_builder_test.exs b/test/pinchflat/downloading/quality_option_builder_test.exs index 6690b68..cdf482b 100644 --- a/test/pinchflat/downloading/quality_option_builder_test.exs +++ b/test/pinchflat/downloading/quality_option_builder_test.exs @@ -6,7 +6,32 @@ defmodule Pinchflat.Downloading.QualityOptionBuilderTest do alias Pinchflat.Settings alias Pinchflat.Downloading.QualityOptionBuilder - # TODO: this basically tests the existing logic but doesn't test any of the new stuff. Add those tests. + describe "build/1" do + test "includes format options if audio_track is set to original" do + media_profile = media_profile_fixture(%{audio_track: "original"}) + + assert res = QualityOptionBuilder.build(media_profile) + + assert {:format, "bestvideo+bestaudio[format_note*=original]/bestvideo*+bestaudio/best"} in res + end + + test "includes format options if audio_track is set to default" do + media_profile = media_profile_fixture(%{audio_track: "default"}) + + assert res = QualityOptionBuilder.build(media_profile) + + assert {:format, "bestvideo+bestaudio[format_note*=(default)]/bestvideo*+bestaudio/best"} in res + end + + test "includes format options if audio_track is set to a language code" do + media_profile = media_profile_fixture(%{audio_track: "en"}) + + assert res = QualityOptionBuilder.build(media_profile) + + assert {:format, "bestvideo+bestaudio[language^=en]/bestvideo*+bestaudio/best"} in res + end + end + describe "build/1 when testing audio profiles" do setup do {:ok, media_profile: media_profile_fixture(%{preferred_resolution: :audio})} @@ -29,6 +54,12 @@ defmodule Pinchflat.Downloading.QualityOptionBuilderTest do assert {:audio_format, "flac"} in res end + + test "includes custom format options", %{media_profile: media_profile} do + assert res = QualityOptionBuilder.build(media_profile) + + assert {:format, "bestaudio/best"} in res + end end describe "build/1 when testing non-audio profiles" do @@ -68,5 +99,11 @@ defmodule Pinchflat.Downloading.QualityOptionBuilderTest do assert {:remux_video, "mkv"} in res end + + test "includes custom format options", %{media_profile: media_profile} do + assert res = QualityOptionBuilder.build(media_profile) + + assert {:format, "bestvideo*+bestaudio/best"} in res + end end end