diff --git a/lib/pinchflat/downloading/media_downloader.ex b/lib/pinchflat/downloading/media_downloader.ex index a10e6b9..df5ea4f 100644 --- a/lib/pinchflat/downloading/media_downloader.ex +++ b/lib/pinchflat/downloading/media_downloader.ex @@ -106,8 +106,9 @@ defmodule Pinchflat.Downloading.MediaDownloader do defp download_with_options(url, item_with_preloads, output_filepath, override_opts) do {:ok, options} = DownloadOptionBuilder.build(item_with_preloads, override_opts) + runner_opts = [output_filepath: output_filepath, use_cookies: item_with_preloads.source.use_cookies] - YtDlpMedia.download(url, options, output_filepath: output_filepath) + YtDlpMedia.download(url, options, runner_opts) end defp recoverable_errors do diff --git a/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex b/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex index 02fc00f..67540e6 100644 --- a/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex +++ b/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex @@ -68,7 +68,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do defp create_media_item_from_media_id(source, media_id) do url = "https://www.youtube.com/watch?v=#{media_id}" - case YtDlpMedia.get_media_attributes(url) do + case YtDlpMedia.get_media_attributes(url, use_cookies: source.use_cookies) do {:ok, media_attrs} -> Media.create_media_item_from_backend_attrs(source, media_attrs) diff --git a/lib/pinchflat/metadata/metadata_file_helpers.ex b/lib/pinchflat/metadata/metadata_file_helpers.ex index b728f47..7adc632 100644 --- a/lib/pinchflat/metadata/metadata_file_helpers.ex +++ b/lib/pinchflat/metadata/metadata_file_helpers.ex @@ -62,11 +62,13 @@ defmodule Pinchflat.Metadata.MetadataFileHelpers do Returns binary() | nil """ - def download_and_store_thumbnail_for(database_record) do - yt_dlp_filepath = generate_filepath_for(database_record, "thumbnail.%(ext)s") - real_filepath = generate_filepath_for(database_record, "thumbnail.jpg") + def download_and_store_thumbnail_for(media_item_with_preloads) do + yt_dlp_filepath = generate_filepath_for(media_item_with_preloads, "thumbnail.%(ext)s") + real_filepath = generate_filepath_for(media_item_with_preloads, "thumbnail.jpg") + command_opts = [output: yt_dlp_filepath] + addl_opts = [use_cookies: media_item_with_preloads.source.use_cookies] - case YtDlpMedia.download_thumbnail(database_record.original_url, output: yt_dlp_filepath) do + case YtDlpMedia.download_thumbnail(media_item_with_preloads.original_url, command_opts, addl_opts) do {:ok, _} -> real_filepath _ -> nil end diff --git a/lib/pinchflat/metadata/source_metadata_storage_worker.ex b/lib/pinchflat/metadata/source_metadata_storage_worker.ex index 8ccfdf9..adaf0df 100644 --- a/lib/pinchflat/metadata/source_metadata_storage_worker.ex +++ b/lib/pinchflat/metadata/source_metadata_storage_worker.ex @@ -92,7 +92,9 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do defp determine_series_directory(source) do output_path = DownloadOptionBuilder.build_output_path_for(source) - {:ok, %{filepath: filepath}} = MediaCollection.get_source_details(source.original_url, output: output_path) + runner_opts = [output: output_path] + addl_opts = [use_cookies: source.use_cookies] + {:ok, %{filepath: filepath}} = MediaCollection.get_source_details(source.original_url, runner_opts, addl_opts) case MetadataFileHelpers.series_directory_from_media_filepath(filepath) do {:ok, series_directory} -> series_directory @@ -119,7 +121,7 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do base_opts ++ [:write_thumbnail, playlist_items: 1] end - MediaCollection.get_source_metadata(source.original_url, opts) + MediaCollection.get_source_metadata(source.original_url, opts, use_cookies: source.use_cookies) end defp tmp_directory do diff --git a/lib/pinchflat/slow_indexing/slow_indexing_helpers.ex b/lib/pinchflat/slow_indexing/slow_indexing_helpers.ex index 2434b92..816d162 100644 --- a/lib/pinchflat/slow_indexing/slow_indexing_helpers.ex +++ b/lib/pinchflat/slow_indexing/slow_indexing_helpers.ex @@ -94,7 +94,8 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpers do {:ok, pid} = FileFollowerServer.start_link() handler = fn filepath -> setup_file_follower_watcher(pid, filepath, source) end - result = MediaCollection.get_media_attributes_for_collection(source.original_url, file_listener_handler: handler) + runner_opts = [file_listener_handler: handler, use_cookies: source.use_cookies] + result = MediaCollection.get_media_attributes_for_collection(source.original_url, runner_opts) FileFollowerServer.stop(pid) diff --git a/lib/pinchflat/sources/source.ex b/lib/pinchflat/sources/source.ex index b6d9154..3a23db8 100644 --- a/lib/pinchflat/sources/source.ex +++ b/lib/pinchflat/sources/source.ex @@ -27,6 +27,7 @@ defmodule Pinchflat.Sources.Source do series_directory index_frequency_minutes fast_index + use_cookies download_media last_indexed_at original_url @@ -73,6 +74,7 @@ defmodule Pinchflat.Sources.Source do field :collection_type, Ecto.Enum, values: [:channel, :playlist] field :index_frequency_minutes, :integer, default: 60 * 24 field :fast_index, :boolean, default: false + field :use_cookies, :boolean, default: false field :download_media, :boolean, default: true field :last_indexed_at, :utc_datetime # Only download media items that were published after this date diff --git a/lib/pinchflat/sources/sources.ex b/lib/pinchflat/sources/sources.ex index 6cd45c1..6e2d2f3 100644 --- a/lib/pinchflat/sources/sources.ex +++ b/lib/pinchflat/sources/sources.ex @@ -180,7 +180,9 @@ defmodule Pinchflat.Sources do end defp add_source_details_to_changeset(source, changeset) do - case MediaCollection.get_source_details(changeset.changes.original_url) do + use_cookies = Ecto.Changeset.get_field(changeset, :use_cookies) + + case MediaCollection.get_source_details(changeset.changes.original_url, [], use_cookies: use_cookies) do {:ok, source_details} -> add_source_details_by_collection_type(source, changeset, source_details) diff --git a/lib/pinchflat/yt_dlp/command_runner.ex b/lib/pinchflat/yt_dlp/command_runner.ex index 30b2404..7cd21dd 100644 --- a/lib/pinchflat/yt_dlp/command_runner.ex +++ b/lib/pinchflat/yt_dlp/command_runner.ex @@ -18,6 +18,8 @@ defmodule Pinchflat.YtDlp.CommandRunner do - :output_filepath - the path to save the output to. If not provided, a temporary file will be created and used. Useful for if you need a reference to the file for a file watcher. + - :use_cookies - if true, will add a cookie file to the command options. Will not + attach a cookie file if the user hasn't set one up. Returns {:ok, binary()} | {:error, output, status}. """ @@ -28,7 +30,7 @@ defmodule Pinchflat.YtDlp.CommandRunner do output_filepath = generate_output_filepath(addl_opts) print_to_file_opts = [{:print_to_file, output_template}, output_filepath] - user_configured_opts = cookie_file_options() + user_configured_opts = cookie_file_options(addl_opts) # These must stay in exactly this order, hence why I'm giving it its own variable. all_opts = command_opts ++ print_to_file_opts ++ user_configured_opts ++ global_options() formatted_command_opts = [url] ++ CliUtils.parse_options(all_opts) @@ -78,7 +80,14 @@ defmodule Pinchflat.YtDlp.CommandRunner do ] end - defp cookie_file_options do + defp cookie_file_options(addl_opts) do + case Keyword.get(addl_opts, :use_cookies) do + true -> add_cookie_file() + _ -> [] + end + end + + defp add_cookie_file do base_dir = Application.get_env(:pinchflat, :extras_directory) filename_options_map = %{cookies: "cookies.txt"} diff --git a/lib/pinchflat/yt_dlp/media.ex b/lib/pinchflat/yt_dlp/media.ex index cecf08a..5cb3fdc 100644 --- a/lib/pinchflat/yt_dlp/media.ex +++ b/lib/pinchflat/yt_dlp/media.ex @@ -37,9 +37,9 @@ defmodule Pinchflat.YtDlp.Media do Returns {:ok, map()} | {:error, any, ...}. """ def download(url, command_opts \\ [], addl_opts \\ []) do - opts = [:no_simulate] ++ command_opts + all_command_opts = [:no_simulate] ++ command_opts - with {:ok, output} <- backend_runner().run(url, opts, "after_move:%()j", addl_opts), + with {:ok, output} <- backend_runner().run(url, all_command_opts, "after_move:%()j", addl_opts), {:ok, parsed_json} <- Phoenix.json_library().decode(output) do {:ok, parsed_json} else @@ -53,12 +53,12 @@ defmodule Pinchflat.YtDlp.Media do Returns {:ok, ""} | {:error, any, ...}. """ - def download_thumbnail(url, command_opts \\ []) do - opts = [:no_simulate, :skip_download, :write_thumbnail, convert_thumbnail: "jpg"] ++ command_opts + def download_thumbnail(url, command_opts \\ [], addl_opts \\ []) do + all_command_opts = [:no_simulate, :skip_download, :write_thumbnail, convert_thumbnail: "jpg"] ++ command_opts # NOTE: it doesn't seem like this command actually returns anything in `after_move` since # we aren't downloading the main media file - backend_runner().run(url, opts, "after_move:%()j") + backend_runner().run(url, all_command_opts, "after_move:%()j", addl_opts) end @doc """ @@ -66,12 +66,12 @@ defmodule Pinchflat.YtDlp.Media do Returns {:ok, %Media{}} | {:error, any, ...}. """ - def get_media_attributes(url) do + def get_media_attributes(url, addl_opts \\ []) do runner = Application.get_env(:pinchflat, :yt_dlp_runner) command_opts = [:simulate, :skip_download] output_template = indexing_output_template() - case runner.run(url, command_opts, output_template) do + case runner.run(url, command_opts, output_template, addl_opts) do {:ok, output} -> output |> Phoenix.json_library().decode!() diff --git a/lib/pinchflat/yt_dlp/media_collection.ex b/lib/pinchflat/yt_dlp/media_collection.ex index f657195..b09b868 100644 --- a/lib/pinchflat/yt_dlp/media_collection.ex +++ b/lib/pinchflat/yt_dlp/media_collection.ex @@ -25,15 +25,17 @@ defmodule Pinchflat.YtDlp.MediaCollection do # the first video has not released yet (ie: is a premier). We don't care about # available formats since we're just getting the media details command_opts = [:simulate, :skip_download, :ignore_no_formats_error, :no_warnings] + use_cookies = Keyword.get(addl_opts, :use_cookies, false) output_template = YtDlpMedia.indexing_output_template() output_filepath = FilesystemUtils.generate_metadata_tmpfile(:json) file_listener_handler = Keyword.get(addl_opts, :file_listener_handler, false) + runner_opts = [output_filepath: output_filepath, use_cookies: use_cookies] if file_listener_handler do file_listener_handler.(output_filepath) end - case runner.run(url, command_opts, output_template, output_filepath: output_filepath) do + case runner.run(url, command_opts, output_template, runner_opts) do {:ok, output} -> parsed_lines = output @@ -64,7 +66,7 @@ defmodule Pinchflat.YtDlp.MediaCollection do Returns {:ok, map()} | {:error, any, ...}. """ - def get_source_details(source_url, addl_opts \\ []) do + def get_source_details(source_url, command_opts \\ [], addl_opts \\ []) do # `ignore_no_formats_error` is necessary because yt-dlp will error out if # the first video has not released yet (ie: is a premier). We don't care about # available formats since we're just getting the source details @@ -75,10 +77,10 @@ defmodule Pinchflat.YtDlp.MediaCollection do playlist_end: 1 ] - command_opts = default_opts ++ addl_opts + all_command_opts = default_opts ++ command_opts output_template = "%(.{channel,channel_id,playlist_id,playlist_title,filename})j" - with {:ok, output} <- backend_runner().run(source_url, command_opts, output_template), + with {:ok, output} <- backend_runner().run(source_url, all_command_opts, output_template, addl_opts), {:ok, parsed_json} <- Phoenix.json_library().decode(output) do {:ok, format_source_details(parsed_json)} else @@ -109,14 +111,14 @@ defmodule Pinchflat.YtDlp.MediaCollection do Returns {:ok, map()} | {:error, any, ...}. """ - def get_source_metadata(source_url, addl_opts \\ [playlist_items: 0]) do + def get_source_metadata(source_url, command_opts, addl_opts \\ []) do # This only validates that the `playlist_items` key is present. It's otherwise unused - _playlist_items = Keyword.fetch!(addl_opts, :playlist_items) + _playlist_items = Keyword.fetch!(command_opts, :playlist_items) - opts = [:skip_download] ++ addl_opts + all_command_opts = [:skip_download] ++ command_opts output_template = "playlist:%()j" - with {:ok, output} <- backend_runner().run(source_url, opts, output_template), + with {:ok, output} <- backend_runner().run(source_url, all_command_opts, output_template, addl_opts), {:ok, parsed_json} <- Phoenix.json_library().decode(output) do {:ok, parsed_json} else diff --git a/lib/pinchflat_web/controllers/sources/source_html/source_form.html.heex b/lib/pinchflat_web/controllers/sources/source_html/source_form.html.heex index 409b328..c30efed 100644 --- a/lib/pinchflat_web/controllers/sources/source_html/source_form.html.heex +++ b/lib/pinchflat_web/controllers/sources/source_html/source_form.html.heex @@ -86,6 +86,13 @@ help="Unchecking still indexes media but it won't be downloaded until you enable this option" /> + <.input + field={f[:use_cookies]} + type="toggle" + label="Use Cookies for Downloading" + help="Uses your YouTube cookies for this source (if configured). Used for downloading private playlists and videos. See docs for important details" + /> + <.input field={f[:download_cutoff_date]} type="text" diff --git a/priv/repo/erd.png b/priv/repo/erd.png index 70f395c..958d3d5 100644 Binary files a/priv/repo/erd.png and b/priv/repo/erd.png differ diff --git a/priv/repo/migrations/20240814154844_add_use_cookies_to_sources.exs b/priv/repo/migrations/20240814154844_add_use_cookies_to_sources.exs new file mode 100644 index 0000000..c7b0f59 --- /dev/null +++ b/priv/repo/migrations/20240814154844_add_use_cookies_to_sources.exs @@ -0,0 +1,9 @@ +defmodule Pinchflat.Repo.Migrations.AddUseCookiesToSources do + use Ecto.Migration + + def change do + alter table(:sources) do + add :use_cookies, :boolean, default: true, null: false + end + end +end diff --git a/test/pinchflat/downloading/media_download_worker_test.exs b/test/pinchflat/downloading/media_download_worker_test.exs index 35eabeb..315ac35 100644 --- a/test/pinchflat/downloading/media_download_worker_test.exs +++ b/test/pinchflat/downloading/media_download_worker_test.exs @@ -9,7 +9,7 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do alias Pinchflat.Downloading.MediaDownloadWorker setup do - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end) + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, ""} end) stub(UserScriptRunnerMock, :run, fn _event_type, _data -> {:ok, "", 0} end) stub(HTTPClientMock, :get, fn _url, _headers, _opts -> {:ok, ""} end) @@ -53,10 +53,12 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do describe "perform/1" do test "it saves attributes to the media_item", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + assert media_item.media_filepath == nil perform_job(MediaDownloadWorker, %{id: media_item.id}) media_item = Repo.reload(media_item) @@ -65,10 +67,12 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do end test "it saves the metadata to the media_item", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + assert media_item.metadata == nil perform_job(MediaDownloadWorker, %{id: media_item.id}) assert Repo.reload(media_item).metadata != nil @@ -138,13 +142,15 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do end test "it saves the file's size to the database", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> metadata = render_parsed_metadata(:media_metadata) FilesystemUtils.write_p!(metadata["filepath"], "test") {:ok, Phoenix.json_library().encode!(metadata)} end) + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + perform_job(MediaDownloadWorker, %{id: media_item.id}) media_item = Repo.reload(media_item) @@ -152,7 +158,7 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do end test "does not set redownloaded_at by default", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> + expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)} end) @@ -167,13 +173,15 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do end test "sets the no_force_overwrites runner option", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, opts, _ot, _addl -> + expect(YtDlpRunnerMock, :run, 1, fn _url, opts, _ot, _addl -> assert :no_force_overwrites in opts refute :force_overwrites in opts {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + perform_job(MediaDownloadWorker, %{id: media_item.id}) end end @@ -189,23 +197,27 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do end test "sets force_overwrites runner option", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, opts, _ot, _addl -> + expect(YtDlpRunnerMock, :run, 1, fn _url, opts, _ot, _addl -> assert :force_overwrites in opts refute :no_force_overwrites in opts {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + perform_job(MediaDownloadWorker, %{id: media_item.id, force: true}) end end describe "perform/1 when testing re-downloads" do test "sets redownloaded_at on the media_item", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + perform_job(MediaDownloadWorker, %{id: media_item.id, quality_upgrade?: true}) media_item = Repo.reload(media_item) @@ -213,13 +225,15 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do end test "sets force_overwrites runner option", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, opts, _ot, _addl -> + expect(YtDlpRunnerMock, :run, 1, fn _url, opts, _ot, _addl -> assert :force_overwrites in opts refute :no_force_overwrites in opts {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + perform_job(MediaDownloadWorker, %{id: media_item.id, force: true}) end end diff --git a/test/pinchflat/downloading/media_downloader_test.exs b/test/pinchflat/downloading/media_downloader_test.exs index be5f10e..70ab6fe 100644 --- a/test/pinchflat/downloading/media_downloader_test.exs +++ b/test/pinchflat/downloading/media_downloader_test.exs @@ -16,27 +16,29 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do ) stub(HTTPClientMock, :get, fn _url, _headers, _opts -> {:ok, ""} end) - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end) + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl_args -> {: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, addl -> + test "calls the backend runner", %{media_item: media_item} do + expect(YtDlpRunnerMock, :run, 1, fn url, _opts, ot, addl -> assert url == media_item.original_url assert ot == "after_move:%()j" - assert [{:output_filepath, filepath}] = addl + assert [{:output_filepath, filepath} | _] = addl assert is_binary(filepath) {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl_args -> {:ok, ""} end) + assert {:ok, _} = MediaDownloader.download_for_media_item(media_item) end - test "it saves the metadata filepath to the database", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> + test "saves the metadata filepath to the database", %{media_item: media_item} do + expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)} end) @@ -67,19 +69,51 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do describe "download_for_media_item/3 when testing override options" do test "includes override opts if specified", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, opts, _ot, _addl -> + expect(YtDlpRunnerMock, :run, 1, fn _url, opts, _ot, _addl -> refute :force_overwrites in opts assert :no_force_overwrites in opts {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + override_opts = [overwrite_behaviour: :no_force_overwrites] assert {:ok, _} = MediaDownloader.download_for_media_item(media_item, override_opts) end end + describe "download_for_media_item/3 when testing cookie usage" do + test "sets use_cookies if the source uses cookies" do + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, addl -> + assert {:use_cookies, true} in addl + {:ok, render_metadata(:media_metadata)} + end) + + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl_args -> {:ok, ""} end) + + source = source_fixture(%{use_cookies: true}) + media_item = media_item_fixture(%{source_id: source.id}) + + assert {:ok, _} = MediaDownloader.download_for_media_item(media_item) + end + + test "does not set use_cookies if the source does not use cookies" do + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, addl -> + assert {:use_cookies, false} in addl + {:ok, render_metadata(:media_metadata)} + end) + + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl_args -> {:ok, ""} end) + + source = source_fixture(%{use_cookies: false}) + media_item = media_item_fixture(%{source_id: source.id}) + + assert {:ok, _} = MediaDownloader.download_for_media_item(media_item) + end + end + describe "download_for_media_item/3 when testing retries" do test "returns a recovered tuple on recoverable errors", %{media_item: media_item} do message = "Unable to communicate with SponsorBlock" @@ -94,13 +128,15 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do test "attempts to update the media item on recoverable errors", %{media_item: media_item} do message = "Unable to communicate with SponsorBlock" - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl -> - [{:output_filepath, filepath}] = addl + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, addl -> + [{:output_filepath, filepath} | _] = addl File.write(filepath, render_metadata(:media_metadata)) {:error, message, 1} end) + expect(YtDlpRunnerMock, :run, 1, fn _url, _opts, _ot, _addl_args -> {:ok, ""} end) + assert {:recovered, ^message} = MediaDownloader.download_for_media_item(media_item) media_item = Repo.reload(media_item) @@ -118,48 +154,48 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do :ok end - test "it sets the media_downloaded_at", %{media_item: media_item} do + test "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 sets the culled_at to nil", %{media_item: media_item} do + test "sets the culled_at to nil", %{media_item: media_item} do Media.update_media_item(media_item, %{culled_at: DateTime.utc_now()}) assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item) assert updated_media_item.culled_at == nil end - test "it extracts the title", %{media_item: media_item} do + test "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 == "Pinchflat Example Video" end - test "it extracts the description", %{media_item: media_item} do + test "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 + test "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 + test "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 duration_seconds", %{media_item: media_item} do + test "extracts the duration_seconds", %{media_item: media_item} do assert media_item.duration_seconds == nil assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item) assert is_integer(updated_media_item.duration_seconds) end - test "it extracts the thumbnail_filepath", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> + test "extracts the thumbnail_filepath", %{media_item: media_item} do + expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot, _addl -> metadata = render_parsed_metadata(:media_metadata) thumbnail_filepath = @@ -182,8 +218,8 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do File.rm(updated_media_item.thumbnail_filepath) end - test "it extracts the metadata_filepath", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> + test "extracts the metadata_filepath", %{media_item: media_item} do + expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot, _addl -> metadata = render_parsed_metadata(:media_metadata) infojson_filepath = metadata["infojson_filename"] @@ -202,14 +238,14 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do describe "download_for_media_item/3 when testing NFO generation" do setup do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)} end) :ok end - test "it generates an NFO file if the source is set to download NFOs" do + test "generates an NFO file if the source is set to download NFOs" do profile = media_profile_fixture(%{download_nfo: true}) source = source_fixture(%{media_profile_id: profile.id}) media_item = media_item_fixture(%{source_id: source.id}) @@ -222,7 +258,7 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do File.rm!(updated_media_item.nfo_filepath) end - test "it does not generate an NFO file if the source is set to not download NFOs" do + test "does not generate an NFO file if the source is set to not download NFOs" do profile = media_profile_fixture(%{download_nfo: false}) source = source_fixture(%{media_profile_id: profile.id}) media_item = media_item_fixture(%{source_id: source.id}) diff --git a/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs b/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs index 46f4226..788173d 100644 --- a/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs +++ b/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs @@ -12,7 +12,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do alias Pinchflat.FastIndexing.FastIndexingHelpers setup do - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, media_attributes_return_fixture()} end) @@ -61,13 +61,41 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do assert [_] = Tasks.list_tasks_for(media_item, "MediaDownloadWorker") end + test "sets use_cookies if the source uses cookies" do + expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end) + + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl -> + assert {:use_cookies, true} in addl + + {:ok, media_attributes_return_fixture()} + end) + + source = source_fixture(%{use_cookies: true}) + + assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source) + end + + test "does not set use_cookies if the source does not use cookies" do + expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end) + + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl -> + assert {:use_cookies, false} in addl + + {:ok, media_attributes_return_fixture()} + end) + + source = source_fixture(%{use_cookies: false}) + + assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source) + end + test "does not enqueue a download job if the media item does not match the format rules" do expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end) profile = media_profile_fixture(%{shorts_behaviour: :exclude}) source = source_fixture(%{media_profile_id: profile.id}) - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> output = Phoenix.json_library().encode!(%{ id: "video2", @@ -91,7 +119,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do test "does not blow up if a media item cannot be created", %{source: source} do expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end) - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, "{}"} end) @@ -101,7 +129,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do test "does not blow up if a media item causes a yt-dlp error", %{source: source} do expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end) - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:error, "message", 1} end) diff --git a/test/pinchflat/fast_indexing/fast_indexing_worker_test.exs b/test/pinchflat/fast_indexing/fast_indexing_worker_test.exs index 40e3805..aa4f681 100644 --- a/test/pinchflat/fast_indexing/fast_indexing_worker_test.exs +++ b/test/pinchflat/fast_indexing/fast_indexing_worker_test.exs @@ -84,7 +84,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingWorkerTest do source = source_fixture(fast_index: true) expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end) - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)} end) expect(AppriseRunnerMock, :run, fn servers, opts -> assert "server_1" = servers @@ -110,7 +110,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingWorkerTest do source = source_fixture(fast_index: true, download_media: false) expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end) - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)} end) expect(AppriseRunnerMock, :run, 0, fn _servers, _opts -> {:ok, ""} end) perform_job(FastIndexingWorker, %{id: source.id}) @@ -120,7 +120,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingWorkerTest do source = source_fixture(fast_index: true, title_filter_regex: "foobar") expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1"} end) - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, render_metadata(:media_metadata)} end) + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)} end) expect(AppriseRunnerMock, :run, 0, fn _servers, _opts -> {:ok, ""} end) perform_job(FastIndexingWorker, %{id: source.id}) diff --git a/test/pinchflat/media_test.exs b/test/pinchflat/media_test.exs index 597309f..9cf3c2a 100644 --- a/test/pinchflat/media_test.exs +++ b/test/pinchflat/media_test.exs @@ -665,8 +665,8 @@ defmodule Pinchflat.MediaTest do end test "does delete the media item's metadata files" do - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end) - media_item = Repo.preload(media_item_with_attachments(), :metadata) + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + media_item = Repo.preload(media_item_with_attachments(), [:metadata, :source]) update_attrs = %{ metadata: %{ @@ -697,8 +697,8 @@ defmodule Pinchflat.MediaTest do end test "deletes the media item's metadata files" do - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end) - media_item = Repo.preload(media_item_with_attachments(), :metadata) + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + media_item = Repo.preload(media_item_with_attachments(), [:metadata, :source]) update_attrs = %{ metadata: %{ @@ -783,8 +783,8 @@ defmodule Pinchflat.MediaTest do end test "does not delete the media item's metadata files" do - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end) - media_item = Repo.preload(media_item_with_attachments(), :metadata) + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, ""} end) + media_item = Repo.preload(media_item_with_attachments(), [:metadata, :source]) update_attrs = %{ metadata: %{ diff --git a/test/pinchflat/metadata/metadata_file_helpers_test.exs b/test/pinchflat/metadata/metadata_file_helpers_test.exs index b1b8b2b..ff98674 100644 --- a/test/pinchflat/metadata/metadata_file_helpers_test.exs +++ b/test/pinchflat/metadata/metadata_file_helpers_test.exs @@ -2,11 +2,12 @@ defmodule Pinchflat.Metadata.MetadataFileHelpersTest do use Pinchflat.DataCase import Pinchflat.MediaFixtures + import Pinchflat.SourcesFixtures alias Pinchflat.Metadata.MetadataFileHelpers, as: Helpers setup do - media_item = media_item_fixture() + media_item = Repo.preload(media_item_fixture(), :source) {:ok, %{media_item: media_item}} end @@ -61,7 +62,7 @@ defmodule Pinchflat.Metadata.MetadataFileHelpersTest do describe "download_and_store_thumbnail_for/2" do test "returns the filepath", %{media_item: media_item} do - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end) + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, ""} end) filepath = Helpers.download_and_store_thumbnail_for(media_item) @@ -69,7 +70,7 @@ defmodule Pinchflat.Metadata.MetadataFileHelpersTest do end test "calls yt-dlp with the expected options", %{media_item: media_item} do - expect(YtDlpRunnerMock, :run, fn url, opts, ot -> + expect(YtDlpRunnerMock, :run, fn url, opts, ot, _addl -> assert url == media_item.original_url assert ot == "after_move:%()j" @@ -87,8 +88,32 @@ defmodule Pinchflat.Metadata.MetadataFileHelpersTest do Helpers.download_and_store_thumbnail_for(media_item) end + test "sets use_cookies if the source uses cookies" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl -> + assert {:use_cookies, true} in addl + {:ok, ""} + end) + + source = source_fixture(%{use_cookies: true}) + media_item = Repo.preload(media_item_fixture(%{source_id: source.id}), :source) + + Helpers.download_and_store_thumbnail_for(media_item) + end + + test "does not set use_cookies if the source does not use cookies" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl -> + assert {:use_cookies, false} in addl + {:ok, ""} + end) + + source = source_fixture(%{use_cookies: false}) + media_item = Repo.preload(media_item_fixture(%{source_id: source.id}), :source) + + Helpers.download_and_store_thumbnail_for(media_item) + end + test "returns nil if yt-dlp fails", %{media_item: media_item} do - stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "error"} end) + stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:error, "error"} end) filepath = Helpers.download_and_store_thumbnail_for(media_item) diff --git a/test/pinchflat/metadata/source_metadata_storage_worker_test.exs b/test/pinchflat/metadata/source_metadata_storage_worker_test.exs index d8b0324..53590f2 100644 --- a/test/pinchflat/metadata/source_metadata_storage_worker_test.exs +++ b/test/pinchflat/metadata/source_metadata_storage_worker_test.exs @@ -32,8 +32,8 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do describe "perform/1" do test "won't call itself in an infinite loop" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> {:ok, source_details_return_fixture()} - _url, _opts, ot when ot == @metadata_ot -> {:ok, "{}"} + _url, _opts, ot, _addl when ot == @source_details_ot -> {:ok, source_details_return_fixture()} + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, "{}"} end) source = source_fixture() @@ -51,8 +51,8 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do describe "perform/1 when testing attribute updates" do test "the source description is saved" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> {:ok, source_details_return_fixture()} - _url, _opts, ot when ot == @metadata_ot -> {:ok, render_metadata(:channel_source_metadata)} + _url, _opts, ot, _addl when ot == @source_details_ot -> {:ok, source_details_return_fixture()} + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, render_metadata(:channel_source_metadata)} end) source = source_fixture(%{description: nil}) @@ -68,8 +68,8 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do describe "perform/1 when testing metadata storage" do test "sets metadata location for source" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> {:ok, source_details_return_fixture()} - _url, _opts, ot when ot == @metadata_ot -> {:ok, "{}"} + _url, _opts, ot, _addl when ot == @source_details_ot -> {:ok, source_details_return_fixture()} + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, "{}"} end) source = Repo.preload(source_fixture(), :metadata) @@ -87,8 +87,8 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do file_contents = Phoenix.json_library().encode!(%{"title" => "test"}) stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> {:ok, source_details_return_fixture()} - _url, _opts, ot when ot == @metadata_ot -> {:ok, file_contents} + _url, _opts, ot, _addl when ot == @source_details_ot -> {:ok, source_details_return_fixture()} + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, file_contents} end) perform_job(SourceMetadataStorageWorker, %{id: source.id}) @@ -100,8 +100,8 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do test "sets metadata image location for source" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> {:ok, source_details_return_fixture()} - _url, _opts, ot when ot == @metadata_ot -> {:ok, render_metadata(:channel_source_metadata)} + _url, _opts, ot, _addl when ot == @source_details_ot -> {:ok, source_details_return_fixture()} + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, render_metadata(:channel_source_metadata)} end) source = source_fixture() @@ -118,8 +118,8 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do test "stores metadata images for source" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> {:ok, source_details_return_fixture()} - _url, _opts, ot when ot == @metadata_ot -> {:ok, render_metadata(:channel_source_metadata)} + _url, _opts, ot, _addl when ot == @source_details_ot -> {:ok, source_details_return_fixture()} + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, render_metadata(:channel_source_metadata)} end) source = source_fixture() @@ -138,12 +138,12 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do describe "perform/1 when testing source image downloading" do test "downloads and stores source images" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> + _url, _opts, ot, _addl when ot == @source_details_ot -> filename = Path.join([Application.get_env(:pinchflat, :media_directory), "Season 1", "bar.mp4"]) {:ok, source_details_return_fixture(%{filename: filename})} - _url, opts, ot when ot == @metadata_ot -> + _url, opts, ot, _addl when ot == @metadata_ot -> assert {:convert_thumbnails, "jpg"} in opts {:ok, render_metadata(:channel_source_metadata)} @@ -168,10 +168,10 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do test "calls one set of yt-dlp metadata opts for channels" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> + _url, _opts, ot, _addl when ot == @source_details_ot -> {:ok, source_details_return_fixture()} - _url, opts, ot when ot == @metadata_ot -> + _url, opts, ot, _addl when ot == @metadata_ot -> assert {:playlist_items, 0} in opts assert :write_all_thumbnails in opts @@ -186,10 +186,10 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do test "calls another set of yt-dlp metadata opts for playlists" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> + _url, _opts, ot, _addl when ot == @source_details_ot -> {:ok, source_details_return_fixture()} - _url, opts, ot when ot == @metadata_ot -> + _url, opts, ot, _addl when ot == @metadata_ot -> assert {:playlist_items, 1} in opts assert :write_thumbnail in opts @@ -204,12 +204,12 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do test "does not store source images if the profile is not set to" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> + _url, _opts, ot, _addl when ot == @source_details_ot -> filename = Path.join([Application.get_env(:pinchflat, :media_directory), "Season 1", "bar.mp4"]) {:ok, source_details_return_fixture(%{filename: filename})} - _url, _opts, ot when ot == @metadata_ot -> + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, render_metadata(:channel_source_metadata)} end) @@ -226,12 +226,12 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do test "does not store source images if the series directory cannot be determined" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> + _url, _opts, ot, _addl when ot == @source_details_ot -> filename = Path.join([Application.get_env(:pinchflat, :media_directory), "foo", "bar.mp4"]) {:ok, source_details_return_fixture(%{filename: filename})} - _url, _opts, ot when ot == @metadata_ot -> + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, render_metadata(:channel_source_metadata)} end) @@ -245,17 +245,49 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do refute source.poster_filepath refute source.banner_filepath end + + test "sets use_cookies if the source uses cookies" do + expect(YtDlpRunnerMock, :run, 2, fn + _url, _opts, ot, _addl when ot == @source_details_ot -> + {:ok, source_details_return_fixture()} + + _url, _opts, ot, addl when ot == @metadata_ot -> + assert {:use_cookies, true} in addl + {:ok, render_metadata(:channel_source_metadata)} + end) + + profile = media_profile_fixture(%{download_source_images: true}) + source = source_fixture(media_profile_id: profile.id, use_cookies: true) + + perform_job(SourceMetadataStorageWorker, %{id: source.id}) + end + + test "does not set use_cookies if the source does not use cookies" do + expect(YtDlpRunnerMock, :run, 2, fn + _url, _opts, ot, _addl when ot == @source_details_ot -> + {:ok, source_details_return_fixture()} + + _url, _opts, ot, addl when ot == @metadata_ot -> + assert {:use_cookies, false} in addl + {:ok, render_metadata(:channel_source_metadata)} + end) + + profile = media_profile_fixture(%{download_source_images: true}) + source = source_fixture(media_profile_id: profile.id, use_cookies: false) + + perform_job(SourceMetadataStorageWorker, %{id: source.id}) + end end describe "perform/1 when determining the series_directory" do test "sets the series directory based on the returned media filepath" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> + _url, _opts, ot, _addl when ot == @source_details_ot -> filename = Path.join([Application.get_env(:pinchflat, :media_directory), "Season 1", "bar.mp4"]) {:ok, source_details_return_fixture(%{filename: filename})} - _url, _opts, ot when ot == @metadata_ot -> + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, "{}"} end) @@ -268,12 +300,12 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do test "does not set the series directory if it cannot be determined" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> + _url, _opts, ot, _addl when ot == @source_details_ot -> filename = Path.join([Application.get_env(:pinchflat, :media_directory), "foo", "bar.mp4"]) {:ok, source_details_return_fixture(%{filename: filename})} - _url, _opts, ot when ot == @metadata_ot -> + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, "{}"} end) @@ -283,17 +315,45 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do refute source.series_directory end + + test "sets use_cookies if the source is set to use cookies" do + expect(YtDlpRunnerMock, :run, 2, fn + _url, _opts, ot, addl when ot == @source_details_ot -> + assert {:use_cookies, true} in addl + {:ok, source_details_return_fixture()} + + _url, _opts, ot, _addl when ot == @metadata_ot -> + {:ok, "{}"} + end) + + source = source_fixture(%{series_directory: nil, use_cookies: true}) + perform_job(SourceMetadataStorageWorker, %{id: source.id}) + end + + test "does not set use_cookies if the source is not set to use cookies" do + expect(YtDlpRunnerMock, :run, 2, fn + _url, _opts, ot, addl when ot == @source_details_ot -> + assert {:use_cookies, false} in addl + {:ok, source_details_return_fixture()} + + _url, _opts, ot, _addl when ot == @metadata_ot -> + {:ok, "{}"} + end) + + source = source_fixture(%{series_directory: nil, use_cookies: false}) + perform_job(SourceMetadataStorageWorker, %{id: source.id}) + end end describe "perform/1 when storing the series NFO" do test "stores the NFO if specified" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> + _url, _opts, ot, _addl when ot == @source_details_ot -> filename = Path.join([Application.get_env(:pinchflat, :media_directory), "Season 1", "bar.mp4"]) {:ok, source_details_return_fixture(%{filename: filename})} - _url, _opts, ot when ot == @metadata_ot -> + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, "{}"} end) @@ -311,12 +371,12 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do test "does not store the NFO if not specified" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> + _url, _opts, ot, _addl when ot == @source_details_ot -> filename = Path.join([Application.get_env(:pinchflat, :media_directory), "Season 1", "bar.mp4"]) {:ok, source_details_return_fixture(%{filename: filename})} - _url, _opts, ot when ot == @metadata_ot -> + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, "{}"} end) @@ -330,12 +390,12 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do test "does not store the NFO if the series directory cannot be determined" do stub(YtDlpRunnerMock, :run, fn - _url, _opts, ot when ot == @source_details_ot -> + _url, _opts, ot, _addl when ot == @source_details_ot -> filename = Path.join([Application.get_env(:pinchflat, :media_directory), "foo", "bar.mp4"]) {:ok, source_details_return_fixture(%{filename: filename})} - _url, _opts, ot when ot == @metadata_ot -> + _url, _opts, ot, _addl when ot == @metadata_ot -> {:ok, "{}"} end) diff --git a/test/pinchflat/slow_indexing/slow_indexing_helpers_test.exs b/test/pinchflat/slow_indexing/slow_indexing_helpers_test.exs index bdd721f..b4391ba 100644 --- a/test/pinchflat/slow_indexing/slow_indexing_helpers_test.exs +++ b/test/pinchflat/slow_indexing/slow_indexing_helpers_test.exs @@ -15,7 +15,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do alias Pinchflat.SlowIndexing.MediaCollectionIndexingWorker describe "kickoff_indexing_task/3" do - test "it schedules a job" do + test "schedules a job" do source = source_fixture(index_frequency_minutes: 1) assert {:ok, _} = SlowIndexingHelpers.kickoff_indexing_task(source) @@ -23,7 +23,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert_enqueued(worker: MediaCollectionIndexingWorker, args: %{"id" => source.id}) end - test "it creates and attaches a task" do + test "creates and attaches a task" do source = source_fixture(index_frequency_minutes: 1) assert {:ok, %Task{} = task} = SlowIndexingHelpers.kickoff_indexing_task(source) @@ -31,7 +31,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert task.source_id == source.id end - test "it deletes any pending media collection tasks for the source" do + test "deletes any pending media collection tasks for the source" do source = source_fixture() {:ok, job} = Oban.insert(MediaCollectionIndexingWorker.new(%{"id" => source.id})) task = task_fixture(source_id: source.id, job_id: job.id) @@ -41,7 +41,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert_raise Ecto.NoResultsError, fn -> Repo.reload!(task) end end - test "it deletes any pending media tasks for the source" do + test "deletes any pending media tasks for the source" do source = source_fixture() {:ok, job} = Oban.insert(FastIndexingWorker.new(%{"id" => source.id})) task = task_fixture(source_id: source.id, job_id: job.id) @@ -51,7 +51,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert_raise Ecto.NoResultsError, fn -> Repo.reload!(task) end end - test "it deletes any fast indexing tasks for the source" do + test "deletes any fast indexing tasks for the source" do source = source_fixture() {:ok, job} = Oban.insert(FastIndexingWorker.new(%{"id" => source.id})) task = task_fixture(source_id: source.id, job_id: job.id) @@ -90,7 +90,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do {:ok, [source: source_fixture()]} end - test "it creates a media_item record for each media ID returned", %{source: source} do + test "creates a media_item record for each media ID returned", %{source: source} do assert media_items = SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source) assert Enum.count(media_items) == 3 @@ -101,7 +101,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert Enum.all?(media_items, fn %MediaItem{} -> true end) end - test "it attaches all media_items to the given source", %{source: source} do + test "attaches all media_items to the given source", %{source: source} do source_id = source.id assert media_items = SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source) @@ -109,7 +109,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert Enum.all?(media_items, fn %MediaItem{source_id: ^source_id} -> true end) end - test "it won't duplicate media_items based on media_id and source", %{source: source} do + test "won't duplicate media_items based on media_id and source", %{source: source} do _first_run = SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source) _duplicate_run = SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source) @@ -117,7 +117,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert Enum.count(media_items) == 3 end - test "it can duplicate media_ids for different sources", %{source: source} do + test "can duplicate media_ids for different sources", %{source: source} do other_source = source_fixture() media_items = SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source) @@ -130,7 +130,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do Enum.map(media_items_other_source, & &1.media_id) end - test "it returns a list of media_items", %{source: source} do + test "returns a list of media_items", %{source: source} do first_run = SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source) duplicate_run = SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source) @@ -140,7 +140,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert first_ids == duplicate_ids end - test "it updates the source's last_indexed_at field", %{source: source} do + test "updates the source's last_indexed_at field", %{source: source} do assert source.last_indexed_at == nil SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source) @@ -149,7 +149,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert DateTime.diff(DateTime.utc_now(), source.last_indexed_at) < 2 end - test "it enqueues a job for each pending media item" do + test "enqueues a job for each pending media item" do source = source_fixture() media_item = media_item_fixture(source_id: source.id, media_filepath: nil) @@ -158,7 +158,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id}) end - test "it does not attach tasks if the source is set to not download" do + test "does not attach tasks if the source is set to not download" do source = source_fixture(download_media: false) media_item = media_item_fixture(source_id: source.id, media_filepath: nil) @@ -167,7 +167,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert [] = Tasks.list_tasks_for(media_item) end - test "it doesn't blow up if a media item cannot be coerced into a struct", %{source: source} do + test "doesn't blow up if a media item cannot be coerced into a struct", %{source: source} do stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl_opts -> response = Phoenix.json_library().encode!(%{ @@ -190,6 +190,28 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do assert %Ecto.Changeset{} = changeset end + + test "sets use_cookies if the source uses cookies" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl_opts -> + assert {:use_cookies, true} in addl_opts + {:ok, source_attributes_return_fixture()} + end) + + source = source_fixture(%{use_cookies: true}) + + SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source) + end + + test "doesn't set use_cookies if the source doesn't use cookies" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl_opts -> + assert {:use_cookies, false} in addl_opts + {:ok, source_attributes_return_fixture()} + end) + + source = source_fixture(%{use_cookies: false}) + + SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source) + end end describe "index_and_enqueue_download_for_media_items/1 when testing file watcher" do diff --git a/test/pinchflat/sources_test.exs b/test/pinchflat/sources_test.exs index 59e004b..662d697 100644 --- a/test/pinchflat/sources_test.exs +++ b/test/pinchflat/sources_test.exs @@ -85,7 +85,7 @@ defmodule Pinchflat.SourcesTest do describe "create_source/2" do test "automatically sets the UUID" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -97,7 +97,7 @@ defmodule Pinchflat.SourcesTest do end test "UUID is not writable by the user" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -110,7 +110,7 @@ defmodule Pinchflat.SourcesTest do end test "creates a source and adds name + ID from runner response for channels" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -123,7 +123,7 @@ defmodule Pinchflat.SourcesTest do end test "creates a source and adds name + ID for playlists" do - expect(YtDlpRunnerMock, :run, &playlist_mock/3) + expect(YtDlpRunnerMock, :run, &playlist_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -136,7 +136,7 @@ defmodule Pinchflat.SourcesTest do end test "adds an error if the runner fails" do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "some error", 1} end) + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:error, "some error", 1} end) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -148,7 +148,7 @@ defmodule Pinchflat.SourcesTest do end test "you can specify a custom custom_name" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -162,7 +162,7 @@ defmodule Pinchflat.SourcesTest do end test "friendly name is pulled from collection_name if not specified" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -175,7 +175,7 @@ defmodule Pinchflat.SourcesTest do end test "creation enforces uniqueness of collection_id scoped to the media_profile and title regex" do - expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot -> + expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot, _addl -> {:ok, Phoenix.json_library().encode!(%{ channel: "some channel name", @@ -196,7 +196,7 @@ defmodule Pinchflat.SourcesTest do end test "creation lets you duplicate collection_ids and profiles as long as the regex is different" do - expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot -> + expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot, _addl -> {:ok, Phoenix.json_library().encode!(%{ channel: "some channel name", @@ -220,7 +220,7 @@ defmodule Pinchflat.SourcesTest do end test "creation lets you duplicate collection_ids as long as the media profile is different" do - expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot -> + expect(YtDlpRunnerMock, :run, 2, fn _url, _opts, _ot, _addl -> {:ok, Phoenix.json_library().encode!(%{ channel: "some channel name", @@ -244,8 +244,8 @@ defmodule Pinchflat.SourcesTest do end test "collection_type is inferred from source details" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) - expect(YtDlpRunnerMock, :run, &playlist_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) + expect(YtDlpRunnerMock, :run, &playlist_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -264,13 +264,13 @@ defmodule Pinchflat.SourcesTest do end test "creation with invalid data fails fast and does not call the runner" do - expect(YtDlpRunnerMock, :run, 0, &channel_mock/3) + expect(YtDlpRunnerMock, :run, 0, &channel_mock/4) assert {:error, %Ecto.Changeset{}} = Sources.create_source(@invalid_source_attrs) end test "creation will schedule the indexing task" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -283,7 +283,7 @@ defmodule Pinchflat.SourcesTest do end test "creation schedules an index test even if the index frequency is 0" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -297,7 +297,7 @@ defmodule Pinchflat.SourcesTest do end test "fast_index forces the index frequency to be a default value" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -312,7 +312,7 @@ defmodule Pinchflat.SourcesTest do end test "disabling fast index will not change the index frequency" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -327,7 +327,7 @@ defmodule Pinchflat.SourcesTest do end test "creating will kickoff a metadata storage worker" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -344,7 +344,7 @@ defmodule Pinchflat.SourcesTest do describe "create_source/2 when testing options" do test "run_post_commit_tasks: false won't enqueue post-commit tasks" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) valid_attrs = %{ media_profile_id: media_profile_fixture().id, @@ -368,7 +368,7 @@ defmodule Pinchflat.SourcesTest do end test "updates with invalid data fails fast and does not call the runner" do - expect(YtDlpRunnerMock, :run, 0, &channel_mock/3) + expect(YtDlpRunnerMock, :run, 0, &channel_mock/4) source = source_fixture() @@ -376,7 +376,7 @@ defmodule Pinchflat.SourcesTest do end test "updating the original_url will re-fetch the source details for channels" do - expect(YtDlpRunnerMock, :run, &channel_mock/3) + expect(YtDlpRunnerMock, :run, &channel_mock/4) source = source_fixture() update_attrs = %{original_url: "https://www.youtube.com/channel/abc123"} @@ -387,7 +387,7 @@ defmodule Pinchflat.SourcesTest do end test "updating the original_url will re-fetch the source details for playlists" do - expect(YtDlpRunnerMock, :run, &playlist_mock/3) + expect(YtDlpRunnerMock, :run, &playlist_mock/4) source = source_fixture() update_attrs = %{original_url: "https://www.youtube.com/playlist?list=abc123"} @@ -398,7 +398,7 @@ defmodule Pinchflat.SourcesTest do end test "not updating the original_url will not re-fetch the source details" do - expect(YtDlpRunnerMock, :run, 0, &channel_mock/3) + expect(YtDlpRunnerMock, :run, 0, &channel_mock/4) source = source_fixture() update_attrs = %{name: "some updated name"} @@ -519,7 +519,7 @@ defmodule Pinchflat.SourcesTest do end test "updating will kickoff a metadata storage worker if the original_url changes" do - expect(YtDlpRunnerMock, :run, &playlist_mock/3) + expect(YtDlpRunnerMock, :run, &playlist_mock/4) source = source_fixture() update_attrs = %{original_url: "https://www.youtube.com/channel/cba321"} @@ -736,7 +736,7 @@ defmodule Pinchflat.SourcesTest do end end - defp playlist_mock(_url, _opts, _ot) do + defp playlist_mock(_url, _opts, _ot, _addl) do { :ok, Phoenix.json_library().encode!(%{ @@ -748,7 +748,7 @@ defmodule Pinchflat.SourcesTest do } end - defp channel_mock(_url, _opts, _ot) do + defp channel_mock(_url, _opts, _ot, _addl) do channel_id = "some_channel_id_#{:rand.uniform(1_000_000)}" { diff --git a/test/pinchflat/yt_dlp/command_runner_test.exs b/test/pinchflat/yt_dlp/command_runner_test.exs index 6dbb856..5f9749e 100644 --- a/test/pinchflat/yt_dlp/command_runner_test.exs +++ b/test/pinchflat/yt_dlp/command_runner_test.exs @@ -51,18 +51,26 @@ defmodule Pinchflat.YtDlp.CommandRunnerTest do {:ok, cookie_file: cookie_file, yt_dlp_file: yt_dlp_file} end - test "includes cookie options when cookies.txt exists", %{cookie_file: cookie_file} do + test "includes cookie options when cookies.txt exists and enabled", %{cookie_file: cookie_file} do FilesystemUtils.write_p!(cookie_file, "cookie data") - assert {:ok, output} = Runner.run(@media_url, [], "") + assert {:ok, output} = Runner.run(@media_url, [], "", use_cookies: true) assert String.contains?(output, "--cookies #{cookie_file}") end + test "doesn't include cookie options when cookies.txt exists but disabled", %{cookie_file: cookie_file} do + FilesystemUtils.write_p!(cookie_file, "cookie data") + + assert {:ok, output} = Runner.run(@media_url, [], "", use_cookies: false) + + refute String.contains?(output, "--cookies #{cookie_file}") + end + test "doesn't include cookie options when cookies.txt blank", %{cookie_file: cookie_file} do FilesystemUtils.write_p!(cookie_file, " \n \n ") - assert {:ok, output} = Runner.run(@media_url, [], "") + assert {:ok, output} = Runner.run(@media_url, [], "", use_cookies: true) refute String.contains?(output, "--cookies") refute String.contains?(output, cookie_file) diff --git a/test/pinchflat/yt_dlp/media_collection_test.exs b/test/pinchflat/yt_dlp/media_collection_test.exs index f08c649..0b34d0a 100644 --- a/test/pinchflat/yt_dlp/media_collection_test.exs +++ b/test/pinchflat/yt_dlp/media_collection_test.exs @@ -18,7 +18,7 @@ defmodule Pinchflat.YtDlp.MediaCollectionTest do MediaCollection.get_media_attributes_for_collection(@channel_url) end - test "it passes the expected default args" do + test "passes the expected default args" do expect(YtDlpRunnerMock, :run, fn _url, opts, ot, _addl_opts -> assert opts == [:simulate, :skip_download, :ignore_no_formats_error, :no_warnings] assert ot == Media.indexing_output_template() @@ -35,9 +35,10 @@ defmodule Pinchflat.YtDlp.MediaCollectionTest do assert {:error, "Big issue", 1} = MediaCollection.get_media_attributes_for_collection(@channel_url) end - test "passes the explict tmpfile path to runner" do + test "passes additional args to runner" do expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl_opts -> - assert [{:output_filepath, filepath}] = addl_opts + assert [{:output_filepath, filepath} | _] = addl_opts + assert {:use_cookies, false} in addl_opts assert String.ends_with?(filepath, ".json") {:ok, ""} @@ -72,8 +73,8 @@ defmodule Pinchflat.YtDlp.MediaCollectionTest do end describe "get_source_details/1" do - test "it returns a map with data on success" do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> + test "returns a map with data on success" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl_opts -> Phoenix.json_library().encode(%{ channel: "PinchflatTestChannel", channel_id: "UCQH2", @@ -92,8 +93,8 @@ defmodule Pinchflat.YtDlp.MediaCollectionTest do } = res end - test "it passes the expected args to the backend runner" do - expect(YtDlpRunnerMock, :run, fn @channel_url, opts, ot -> + test "passes the expected args to the runner" do + expect(YtDlpRunnerMock, :run, fn @channel_url, opts, ot, _addl_opts -> assert opts == [:simulate, :skip_download, :ignore_no_formats_error, playlist_end: 1] assert ot == "%(.{channel,channel_id,playlist_id,playlist_title,filename})j" @@ -103,55 +104,73 @@ defmodule Pinchflat.YtDlp.MediaCollectionTest do assert {:ok, _} = MediaCollection.get_source_details(@channel_url) end - test "it returns an error if the runner returns an error" do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end) + test "passes custom args to the runner" do + expect(YtDlpRunnerMock, :run, fn @channel_url, opts, _ot, _addl_opts -> + assert {:foo, :bar} in opts + + {:ok, "{}"} + end) + + assert {:ok, _} = MediaCollection.get_source_details(@channel_url, foo: :bar) + end + + test "passes additional args to the runner" do + expect(YtDlpRunnerMock, :run, fn @channel_url, _opts, _ot, addl_opts -> + assert {:use_cookies, true} in addl_opts + + {:ok, "{}"} + end) + + assert {:ok, _} = MediaCollection.get_source_details(@channel_url, [], use_cookies: true) + end + + test "returns an error if the runner returns an error" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl_opts -> {:error, "Big issue", 1} end) assert {:error, "Big issue", 1} = MediaCollection.get_source_details(@channel_url) end - test "it returns an error if the output is not JSON" do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "Not JSON"} end) + test "returns an error if the output is not JSON" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl_opts -> {:ok, "Not JSON"} end) assert {:error, %Jason.DecodeError{}} = MediaCollection.get_source_details(@channel_url) end end describe "get_source_metadata/1" do - test "it returns a map with data on success" do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> + test "returns a map with data on success" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl_opts -> Phoenix.json_library().encode(%{channel: "PinchflatTestChannel"}) end) - assert {:ok, res} = MediaCollection.get_source_metadata(@channel_url) + assert {:ok, res} = MediaCollection.get_source_metadata(@channel_url, playlist_items: 0) assert %{"channel" => "PinchflatTestChannel"} = res end - test "it passes the expected args to the backend runner" do - expect(YtDlpRunnerMock, :run, fn @channel_url, opts, ot -> + test "passes the expected args to the backend runner" do + expect(YtDlpRunnerMock, :run, fn @channel_url, opts, ot, _addl_opts -> assert opts == [:skip_download, playlist_items: 0] assert ot == "playlist:%()j" {:ok, "{}"} end) - assert {:ok, _} = MediaCollection.get_source_metadata(@channel_url) + assert {:ok, _} = MediaCollection.get_source_metadata(@channel_url, playlist_items: 0) end - test "it returns an error if the runner returns an error" do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end) + test "passes additional args to the runner" do + expect(YtDlpRunnerMock, :run, fn @channel_url, _opts, _ot, addl_opts -> + assert {:use_cookies, true} in addl_opts - assert {:error, "Big issue", 1} = MediaCollection.get_source_metadata(@channel_url) + {:ok, "{}"} + end) + + assert {:ok, _} = MediaCollection.get_source_metadata(@channel_url, [playlist_items: 0], use_cookies: true) end - test "it returns an error if the output is not JSON" do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "Not JSON"} end) - - assert {:error, %Jason.DecodeError{}} = MediaCollection.get_source_metadata(@channel_url) - end - - test "allows you to pass additional opts" do - expect(YtDlpRunnerMock, :run, fn _url, opts, _ot -> + test "passes custom args to the runner" do + expect(YtDlpRunnerMock, :run, fn _url, opts, _ot, _addl_opts -> assert opts == [:skip_download, playlist_items: 1, real_opt: :yup] {:ok, "{}"} @@ -165,5 +184,17 @@ defmodule Pinchflat.YtDlp.MediaCollectionTest do MediaCollection.get_source_metadata(@channel_url, real_opt: :yup) end end + + test "returns an error if the runner returns an error" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl_opts -> {:error, "Big issue", 1} end) + + assert {:error, "Big issue", 1} = MediaCollection.get_source_metadata(@channel_url, playlist_items: 0) + end + + test "returns an error if the output is not JSON" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl_opts -> {:ok, "Not JSON"} end) + + assert {:error, %Jason.DecodeError{}} = MediaCollection.get_source_metadata(@channel_url, playlist_items: 0) + end end end diff --git a/test/pinchflat/yt_dlp/media_test.exs b/test/pinchflat/yt_dlp/media_test.exs index 1e8b110..e2b51ba 100644 --- a/test/pinchflat/yt_dlp/media_test.exs +++ b/test/pinchflat/yt_dlp/media_test.exs @@ -20,15 +20,24 @@ defmodule Pinchflat.YtDlp.MediaTest do assert {:ok, _} = Media.download(@media_url) end - test "passes along additional options" do - expect(YtDlpRunnerMock, :run, fn _url, opts, _ot, addl -> + test "passes along custom command args" do + expect(YtDlpRunnerMock, :run, fn _url, opts, _ot, _addl -> assert [:no_simulate, :custom_arg] = opts + + {:ok, "{}"} + end) + + assert {:ok, _} = Media.download(@media_url, [:custom_arg]) + end + + test "passes along additional options" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl -> assert [addl_arg: true] = addl {:ok, "{}"} end) - assert {:ok, _} = Media.download(@media_url, [:custom_arg], addl_arg: true) + assert {:ok, _} = Media.download(@media_url, [], addl_arg: true) end test "parses and returns the generated file as JSON" do @@ -51,7 +60,7 @@ defmodule Pinchflat.YtDlp.MediaTest do describe "download_thumbnail/2" do test "calls the backend runner with the expected arguments" do - expect(YtDlpRunnerMock, :run, fn @media_url, opts, ot -> + expect(YtDlpRunnerMock, :run, fn @media_url, opts, ot, _addl -> assert opts == [:no_simulate, :skip_download, :write_thumbnail, {:convert_thumbnail, "jpg"}] assert ot == "after_move:%()j" @@ -61,8 +70,8 @@ defmodule Pinchflat.YtDlp.MediaTest do assert {:ok, _} = Media.download_thumbnail(@media_url) end - test "passes along additional options" do - expect(YtDlpRunnerMock, :run, fn _url, opts, _ot -> + test "passes along custom command args" do + expect(YtDlpRunnerMock, :run, fn _url, opts, _ot, _addl -> assert :custom_arg in opts {:ok, "{}"} @@ -71,8 +80,18 @@ defmodule Pinchflat.YtDlp.MediaTest do assert {:ok, _} = Media.download_thumbnail(@media_url, [:custom_arg]) end + test "passes along additional options" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl -> + assert [addl_arg: true] = addl + + {:ok, "{}"} + end) + + assert {:ok, _} = Media.download_thumbnail(@media_url, [], addl_arg: true) + end + test "returns errors" do - expect(YtDlpRunnerMock, :run, fn _url, _opt, _ot -> + expect(YtDlpRunnerMock, :run, fn _url, _opt, _ot, _addl -> {:error, "something"} end) @@ -82,7 +101,7 @@ defmodule Pinchflat.YtDlp.MediaTest do describe "get_media_attributes/1" do test "returns a list of video attributes" do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:ok, media_attributes_return_fixture()} end) @@ -91,7 +110,7 @@ defmodule Pinchflat.YtDlp.MediaTest do end test "it passes the expected default args" do - expect(YtDlpRunnerMock, :run, fn _url, opts, ot -> + expect(YtDlpRunnerMock, :run, fn _url, opts, ot, _addl -> assert opts == [:simulate, :skip_download] assert ot == Media.indexing_output_template() @@ -101,8 +120,17 @@ defmodule Pinchflat.YtDlp.MediaTest do assert {:ok, _} = Media.get_media_attributes(@media_url) end + test "passes along additional options" do + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl -> + assert [addl_arg: true] = addl + {:ok, media_attributes_return_fixture()} + end) + + assert {:ok, _} = Media.get_media_attributes(@media_url, addl_arg: true) + end + test "returns the error straight through when the command fails" do - expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end) + expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl -> {:error, "Big issue", 1} end) assert {:error, "Big issue", 1} = Media.get_media_attributes(@media_url) end diff --git a/test/pinchflat_web/controllers/source_controller_test.exs b/test/pinchflat_web/controllers/source_controller_test.exs index a4a19ba..5d532da 100644 --- a/test/pinchflat_web/controllers/source_controller_test.exs +++ b/test/pinchflat_web/controllers/source_controller_test.exs @@ -82,7 +82,7 @@ defmodule PinchflatWeb.SourceControllerTest do describe "create source" do test "redirects to show when data is valid", %{conn: conn, create_attrs: create_attrs} do - expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3) + expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/4) conn = post(conn, ~p"/sources", source: create_attrs) assert %{id: id} = redirected_params(conn) @@ -98,7 +98,7 @@ defmodule PinchflatWeb.SourceControllerTest do end test "redirects to onboarding when onboarding", %{conn: conn, create_attrs: create_attrs} do - expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3) + expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/4) Settings.set(onboarding: true) conn = post(conn, ~p"/sources", source: create_attrs) @@ -127,7 +127,7 @@ defmodule PinchflatWeb.SourceControllerTest do setup [:create_source] test "redirects when data is valid", %{conn: conn, source: source, update_attrs: update_attrs} do - expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3) + expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/4) conn = put(conn, ~p"/sources/#{source}", source: update_attrs) assert redirected_to(conn) == ~p"/sources/#{source}" @@ -275,7 +275,7 @@ defmodule PinchflatWeb.SourceControllerTest do %{source: source, media_item: media_item} end - defp runner_function_mock(_url, _opts, _ot) do + defp runner_function_mock(_url, _opts, _ot, _addl) do { :ok, Phoenix.json_library().encode!(%{