Refactor modules into contexts (#78)

* [WIP] break out a few contexts, start refactoring fast index modules

* [WIP] more contexts, this time around slow indexing and downloads

* [WIP] got all tests passing

* [WIP] Added moduledocs

* Built a genserver to rename old jobs on boot

* Added a module naming check; moved things around

* Fixed specs
This commit is contained in:
Kieran
2024-03-12 17:54:55 -07:00
committed by GitHub
parent 7fa5c4da63
commit 33baa99aae
66 changed files with 1092 additions and 568 deletions
@@ -1,7 +1,7 @@
defmodule Pinchflat.YtDlp.Backend.CommandRunnerTest do
defmodule Pinchflat.YtDlp.CommandRunnerTest do
use ExUnit.Case, async: true
alias Pinchflat.YtDlp.Backend.CommandRunner, as: Runner
alias Pinchflat.YtDlp.CommandRunner, as: Runner
@original_executable Application.compile_env(:pinchflat, :yt_dlp_executable)
@media_url "https://www.youtube.com/watch?v=-LHXuyzpex0"
@@ -1,211 +0,0 @@
defmodule Pinchflat.YtDlp.DownloadOptionBuilderTest do
use Pinchflat.DataCase
import Pinchflat.MediaFixtures
import Pinchflat.ProfilesFixtures
import Pinchflat.SourcesFixtures
alias Pinchflat.Profiles
alias Pinchflat.YtDlp.DownloadOptionBuilder
setup do
media_profile = media_profile_fixture(%{output_path_template: "{{ title }}.%(ext)s"})
source = source_fixture(%{media_profile_id: media_profile.id, custom_name: "my source"})
media_item = Repo.preload(media_item_fixture(source_id: source.id), source: :media_profile)
{:ok, media_item: media_item}
end
describe "build/1 when testing output options" do
test "it generates an expanded output path based on the given template", %{media_item: media_item} do
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:output, "/tmp/test/media/%(title)S.%(ext)s"} in res
end
test "it respects custom output path options", %{media_item: media_item} do
media_item =
update_media_profile_attribute(media_item, %{output_path_template: "{{ source_custom_name }}.%(ext)s"})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:output, "/tmp/test/media/#{media_item.source.custom_name}.%(ext)s"} in res
end
end
describe "build/1 when testing default options" do
test "it includes default options", %{media_item: media_item} do
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :no_progress in res
assert :windows_filenames in res
end
end
describe "build/1 when testing subtitle options" do
test "includes :write_subs option when specified", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{download_subs: true})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :write_subs in res
end
test "forces SRT format when download_subs is true", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{download_subs: true})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:convert_subs, "srt"} in res
end
test "includes :write_auto_subs option when specified", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{download_subs: true, download_auto_subs: true})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :write_auto_subs in res
end
test "doesn't include :write_auto_subs option when download_subs is false", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{download_subs: false, download_auto_subs: true})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
refute :write_auto_subs in res
end
test "includes :embed_subs option when specified", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{embed_subs: true})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :embed_subs in res
end
test "doesn't include :embed_subs option when preferred_resolution is :audio", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{embed_subs: true, preferred_resolution: :audio})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
refute :embed_subs in res
end
test "includes sub_langs option when download_subs is true", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{download_subs: true, sub_langs: "en"})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:sub_langs, "en"} in res
end
test "includes sub_langs option when embed_subs is true", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{embed_subs: true, sub_langs: "en"})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:sub_langs, "en"} in res
end
test "doesn't include sub_langs option when neither downloading nor embedding", %{media_item: media_item} do
media_item =
update_media_profile_attribute(media_item, %{embed_subs: false, download_subs: false, sub_langs: "en"})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
refute {:sub_langs, "en"} in res
end
end
describe "build/1 when testing thumbnail options" do
test "includes :write_thumbnail option when specified", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{download_thumbnail: true})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :write_thumbnail in res
end
test "convertes thumbnail to jpg when download_thumbnail is true", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{download_thumbnail: true})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:convert_thumbnail, "jpg"} in res
end
test "includes :embed_thumbnail option when specified", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{embed_thumbnail: true})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :embed_thumbnail in res
end
test "doesn't include these options when not specified", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{embed_thumbnail: false, download_thumbnail: false})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
refute :write_thumbnail in res
refute :embed_thumbnail in res
end
end
describe "build/1 when testing metadata options" do
test "includes :write_info_json option when specified", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{download_metadata: true})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :write_info_json in res
assert :clean_info_json in res
end
test "includes :embed_metadata option when specified", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{embed_metadata: true})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :embed_metadata in res
end
test "doesn't include these options when not specified", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{embed_metadata: false, download_metadata: false})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
refute :write_info_json in res
refute :clean_info_json in res
refute :embed_metadata in res
end
end
describe "build/1 when testing quality options" do
test "it includes quality options", %{media_item: media_item} do
media_item = update_media_profile_attribute(media_item, %{preferred_resolution: :"1080p"})
assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:format_sort, "res:1080,+codec:avc:m4a"} in res
end
test "it 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]"} in res
end
end
defp update_media_profile_attribute(media_item_with_preloads, attrs) do
media_item_with_preloads.source.media_profile
|> Profiles.change_media_profile(attrs)
|> Repo.update!()
media_item_with_preloads
|> Repo.reload()
|> Repo.preload(source: :media_profile)
end
end
@@ -1,10 +1,10 @@
defmodule Pinchflat.YtDlp.Backend.MediaCollectionTest do
defmodule Pinchflat.YtDlp.MediaCollectionTest do
use Pinchflat.DataCase
import Mox
import Pinchflat.SourcesFixtures
alias Pinchflat.YtDlp.Backend.Media
alias Pinchflat.YtDlp.Backend.MediaCollection
alias Pinchflat.YtDlp.Media
alias Pinchflat.YtDlp.MediaCollection
@channel_url "https://www.youtube.com/c/TheUselessTrials"
@@ -1,106 +0,0 @@
defmodule Pinchflat.MediaClient.MediaDownloaderTest do
use Pinchflat.DataCase
import Mox
import Pinchflat.MediaFixtures
alias Pinchflat.MediaClient.MediaDownloader
setup :verify_on_exit!
setup do
media_item =
Repo.preload(
media_item_fixture(%{title: "Something", media_filepath: nil}),
[:metadata, source: :media_profile]
)
stub(HTTPClientMock, :get, fn _url, _headers, _opts ->
{:ok, ""}
end)
{:ok, %{media_item: media_item}}
end
describe "download_for_media_item/3" do
test "it calls the backend runner", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, fn url, _opts, ot ->
assert url == media_item.original_url
assert ot == "after_move:%()j"
{:ok, render_metadata(:media_metadata)}
end)
assert {:ok, _} = MediaDownloader.download_for_media_item(media_item)
end
test "it saves the metadata filepatha to the database", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
{:ok, render_metadata(:media_metadata)}
end)
assert is_nil(media_item.metadata)
assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert updated_media_item.metadata.metadata_filepath =~ "media_items/#{media_item.id}/metadata.json.gz"
assert updated_media_item.metadata.thumbnail_filepath =~ "media_items/#{media_item.id}/maxresdefault.jpg"
end
test "errors are passed through", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot ->
{:error, :some_error}
end)
assert {:error, :some_error} = MediaDownloader.download_for_media_item(media_item)
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 sets the media_downloaded_at", %{media_item: media_item} do
assert media_item.media_downloaded_at == nil
assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert DateTime.diff(DateTime.utc_now(), updated_media_item.media_downloaded_at) < 2
end
test "it extracts the title", %{media_item: media_item} do
assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert updated_media_item.title == "Trying to Wheelie Without the Rear Brake"
end
test "it extracts the description", %{media_item: media_item} do
assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert is_binary(updated_media_item.description)
end
test "it extracts the media_filepath", %{media_item: media_item} do
assert media_item.media_filepath == nil
assert {:ok, updated_media_item} = MediaDownloader.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} = MediaDownloader.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} = MediaDownloader.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} = MediaDownloader.download_for_media_item(media_item)
assert String.ends_with?(updated_media_item.metadata_filepath, ".info.json")
end
end
end
@@ -1,9 +1,9 @@
defmodule Pinchflat.YtDlp.Backend.MediaTest do
defmodule Pinchflat.YtDlp.MediaTest do
use Pinchflat.DataCase
import Mox
import Pinchflat.MediaFixtures
alias Pinchflat.YtDlp.Backend.Media
alias Pinchflat.YtDlp.Media
@media_url "https://www.youtube.com/watch?v=TiZPUDkDYbk"