[Enhancement] Allow setting preference for video/audio codec (#255)

* [WIP] started on codec parser

* Added codec preferences to settings model

* [WIP] added basic codec preference fields to settings form

* Hooked up the backend portion of the codec preference work

* Added codec settings to frontend

* Ensured you can remove codec data
This commit is contained in:
Kieran
2024-05-21 16:28:19 -07:00
committed by GitHub
parent dec3938780
commit 81d5efd4c1
12 changed files with 373 additions and 31 deletions
@@ -0,0 +1,70 @@
defmodule Pinchflat.Downloading.CodecParserTest do
use Pinchflat.DataCase
alias Pinchflat.Settings
alias Pinchflat.Downloading.CodecParser
describe "generate_vcodec_string_from_settings/1" do
test "returns a default vcodec string when setting isn't set" do
Settings.set(video_codec_preference: [])
assert "bestvideo[vcodec~='^avc']/bestvideo" == CodecParser.generate_vcodec_string_from_settings()
end
test "generates a vcodec string" do
Settings.set(video_codec_preference: ["av01"])
assert "bestvideo[vcodec~='^av01']/bestvideo" == CodecParser.generate_vcodec_string_from_settings()
end
end
describe "generate_acodec_string_from_settings/1" do
test "returns a default acodec string when setting isn't set" do
Settings.set(audio_codec_preference: [])
assert "bestaudio[acodec~='^mp4a']/bestaudio" == CodecParser.generate_acodec_string_from_settings()
end
test "generates an acodec string" do
Settings.set(audio_codec_preference: ["mp3"])
assert "bestaudio[acodec~='^mp3']/bestaudio" == CodecParser.generate_acodec_string_from_settings()
end
end
describe "generate_vcodec_string/1" do
test "returns a default vcodec string when nil" do
assert "bestvideo[vcodec~='^avc']/bestvideo" == CodecParser.generate_vcodec_string(nil)
end
test "returns a default vcodec string when empty" do
assert "bestvideo[vcodec~='^avc']/bestvideo" == CodecParser.generate_vcodec_string([])
end
test "generates a vcodec string" do
assert "bestvideo[vcodec~='^av01']/bestvideo" == CodecParser.generate_vcodec_string(["av01"])
end
test "ignores options that don't exist" do
assert "bestvideo[vcodec~='^av01']/bestvideo" == CodecParser.generate_vcodec_string(["av01", "foo"])
end
end
describe "generate_acodec_string/1" do
test "returns a default acodec string when nil" do
assert "bestaudio[acodec~='^mp4a']/bestaudio" == CodecParser.generate_acodec_string(nil)
end
test "returns a default acodec string when empty" do
assert "bestaudio[acodec~='^mp4a']/bestaudio" == CodecParser.generate_acodec_string([])
end
test "generates an acodec string" do
assert "bestaudio[acodec~='^mp3']/bestaudio" == CodecParser.generate_acodec_string(["mp3"])
end
test "ignores options that don't exist" do
assert "bestaudio[acodec~='^mp3']/bestaudio" == CodecParser.generate_acodec_string(["mp3", "foo"])
end
end
end
@@ -6,6 +6,7 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilderTest do
alias Pinchflat.Sources
alias Pinchflat.Profiles
alias Pinchflat.Settings
alias Pinchflat.Utils.FilesystemUtils
alias Pinchflat.Downloading.DownloadOptionBuilder
@@ -244,7 +245,7 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilderTest do
end
describe "build/1 when testing quality options" do
test "it includes quality options" do
test "includes quality options" do
resolutions = ["360", "480", "720", "1080", "2160", "4320"]
Enum.each(resolutions, fn resolution ->
@@ -255,21 +256,35 @@ defmodule Pinchflat.Downloading.DownloadOptionBuilderTest do
media_item = Repo.preload(media_item_fixture(source_id: source.id), source: :media_profile)
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:format_sort, "res:#{resolution},+codec:avc:m4a"} in res
assert {:format_sort, "res:#{resolution}"} in res
assert {:format, "((bestvideo[vcodec~='^avc']/bestvideo)+(bestaudio[acodec~='^mp4a']/bestaudio))/best"} in res
assert {:remux_video, "mp4"} in res
end)
end
test "it includes quality options for audio only", %{media_item: media_item} do
test "includes quality options for audio only", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{preferred_resolution: :audio})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :extract_audio in res
assert {:format, "bestaudio[ext=m4a]/bestaudio[ext=mp3]/bestaudio/best[ext=m4a]/best[ext=mp3]/best"} in res
assert {:format, "bestaudio[acodec~='^mp4a']/bestaudio/best"} in res
refute {:remux_video, "mp4"} in res
end
test "includes custom quality options if specified", %{media_item: media_item} do
Settings.set(video_codec_preference: ["av01"])
Settings.set(audio_codec_preference: ["aac"])
media_item = update_media_profile_attribute(media_item, %{preferred_resolution: :"1080p"})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:format, "((bestvideo[vcodec~='^av01']/bestvideo)+(bestaudio[acodec~='^aac']/bestaudio))/best"} in res
end
end
describe "build/1 when testing sponsorblock options" do
+60
View File
@@ -78,4 +78,64 @@ defmodule Pinchflat.SettingsTest do
assert %Ecto.Changeset{} = Settings.change_setting(setting, %{onboarding: true})
end
end
describe "change_setting/2 when testing codec preferences" do
test "converts (video|audio)_codec_preference_string to an array" do
setting = Settings.record()
new_setting = %{
video_codec_preference_string: "avc>vp9",
audio_codec_preference_string: "aac>opus"
}
changeset = Settings.change_setting(setting, new_setting)
assert ["avc", "vp9"] = changeset.changes.video_codec_preference
assert ["aac", "opus"] = changeset.changes.audio_codec_preference
end
test "removes whitespace from (video|audio)_codec_preference" do
setting = Settings.record()
new_setting = %{
video_codec_preference_string: " avc > > vp9 ",
audio_codec_preference_string: "aac> opus "
}
changeset = Settings.change_setting(setting, new_setting)
assert ["avc", "vp9"] = changeset.changes.video_codec_preference
assert ["aac", "opus"] = changeset.changes.audio_codec_preference
end
test "downcases (video|audio)_codec_preference" do
setting = Settings.record()
new_setting = %{
video_codec_preference_string: "AVC>VP9",
audio_codec_preference_string: "AAC>OPUS"
}
changeset = Settings.change_setting(setting, new_setting)
assert ["avc", "vp9"] = changeset.changes.video_codec_preference
assert ["aac", "opus"] = changeset.changes.audio_codec_preference
end
test "an empty value will remove the codec settings" do
Settings.set(video_codec_preference: ["avc", "vp9"])
Settings.set(audio_codec_preference: ["aac", "opus"])
setting = Settings.record()
new_setting = %{
video_codec_preference_string: "",
audio_codec_preference_string: ""
}
changeset = Settings.change_setting(setting, new_setting)
assert [] = changeset.changes.video_codec_preference
assert [] = changeset.changes.audio_codec_preference
end
end
end