From 750bec81fabaa09c9edc9fecfcee1e63365cea2d Mon Sep 17 00:00:00 2001 From: Kieran Eglin Date: Tue, 19 Mar 2024 13:22:51 -0700 Subject: [PATCH] Added new attributes for source images --- .../source_metadata_storage_worker.ex | 5 +- lib/pinchflat/profiles/media_profile.ex | 2 + lib/pinchflat/sources/source.ex | 8 +- ...0240319200823_add_source_photos_fields.exs | 15 ++++ .../source_metadata_storage_worker_test.exs | 75 +++++++++++++++++++ 5 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 priv/repo/migrations/20240319200823_add_source_photos_fields.exs diff --git a/lib/pinchflat/metadata/source_metadata_storage_worker.ex b/lib/pinchflat/metadata/source_metadata_storage_worker.ex index d131f2b..2a883f7 100644 --- a/lib/pinchflat/metadata/source_metadata_storage_worker.ex +++ b/lib/pinchflat/metadata/source_metadata_storage_worker.ex @@ -35,6 +35,7 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do - JSON metadata for internal use - The series directory for the source - The NFO file for the source (if specified) + - Downloads and stores source images (if specified) The worker is kicked off after a source is inserted/updated - this can take an unknown amount of time so don't rely on this data being here @@ -71,10 +72,10 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do end defp fetch_source_metadata_and_images(series_directory, source) do - # This is a proxy for checking whether we should download images - if :rand.uniform() > 0 do + if source.media_profile.download_source_images && series_directory do output_path = "#{tmp_directory()}/#{StringUtils.random_string(16)}/source_image.%(ext)S" opts = [:write_all_thumbnails, convert_thumbnails: "jpg", output: output_path] + {:ok, metadata} = MediaCollection.get_source_metadata(source.original_url, opts) image_attrs = SourceImageParser.store_source_images(series_directory, metadata) diff --git a/lib/pinchflat/profiles/media_profile.ex b/lib/pinchflat/profiles/media_profile.ex index ef60b02..e33568c 100644 --- a/lib/pinchflat/profiles/media_profile.ex +++ b/lib/pinchflat/profiles/media_profile.ex @@ -17,6 +17,7 @@ defmodule Pinchflat.Profiles.MediaProfile do sub_langs download_thumbnail embed_thumbnail + download_source_images download_metadata embed_metadata download_nfo @@ -40,6 +41,7 @@ defmodule Pinchflat.Profiles.MediaProfile do field :download_thumbnail, :boolean, default: false field :embed_thumbnail, :boolean, default: false + field :download_source_images, :boolean, default: false field :download_metadata, :boolean, default: false field :embed_metadata, :boolean, default: false diff --git a/lib/pinchflat/sources/source.ex b/lib/pinchflat/sources/source.ex index 56bcb91..ec3075f 100644 --- a/lib/pinchflat/sources/source.ex +++ b/lib/pinchflat/sources/source.ex @@ -18,6 +18,9 @@ defmodule Pinchflat.Sources.Source do collection_type custom_name nfo_filepath + poster_filepath + fanart_filepath + banner_filepath series_directory index_frequency_minutes fast_index @@ -55,6 +58,9 @@ defmodule Pinchflat.Sources.Source do field :collection_id, :string field :collection_type, Ecto.Enum, values: [:channel, :playlist] field :nfo_filepath, :string + field :poster_filepath, :string + field :fanart_filepath, :string + field :banner_filepath, :string field :series_directory, :string field :index_frequency_minutes, :integer, default: 60 * 24 field :fast_index, :boolean, default: false @@ -106,6 +112,6 @@ defmodule Pinchflat.Sources.Source do @doc false def filepath_attributes do - ~w(nfo_filepath)a + ~w(nfo_filepath fanart_filepath poster_filepath banner_filepath)a end end diff --git a/priv/repo/migrations/20240319200823_add_source_photos_fields.exs b/priv/repo/migrations/20240319200823_add_source_photos_fields.exs new file mode 100644 index 0000000..a3fd8ec --- /dev/null +++ b/priv/repo/migrations/20240319200823_add_source_photos_fields.exs @@ -0,0 +1,15 @@ +defmodule Pinchflat.Repo.Migrations.AddSourcePhotosFields do + use Ecto.Migration + + def change do + alter table(:sources) do + add :fanart_filepath, :string + add :poster_filepath, :string + add :banner_filepath, :string + end + + alter table(:media_profiles) do + add :download_source_images, :boolean, default: false, null: false + end + end +end diff --git a/test/pinchflat/metadata/source_metadata_storage_worker_test.exs b/test/pinchflat/metadata/source_metadata_storage_worker_test.exs index c8a096e..6177499 100644 --- a/test/pinchflat/metadata/source_metadata_storage_worker_test.exs +++ b/test/pinchflat/metadata/source_metadata_storage_worker_test.exs @@ -4,6 +4,7 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do import Pinchflat.SourcesFixtures import Pinchflat.ProfilesFixtures + alias Pinchflat.Sources alias Pinchflat.Metadata.MetadataFileHelpers alias Pinchflat.Metadata.SourceMetadataStorageWorker @@ -84,6 +85,80 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do end end + 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 -> + 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 -> + {:ok, render_metadata(:channel_source_metadata)} + end) + + profile = media_profile_fixture(%{download_source_images: true}) + source = source_fixture(media_profile_id: profile.id) + + perform_job(SourceMetadataStorageWorker, %{id: source.id}) + source = Repo.reload(source) + + assert source.fanart_filepath + assert source.poster_filepath + assert source.banner_filepath + + assert File.exists?(source.fanart_filepath) + assert File.exists?(source.poster_filepath) + assert File.exists?(source.banner_filepath) + + Sources.delete_source(source, delete_files: true) + end + + 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 -> + 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 -> + {:ok, render_metadata(:channel_source_metadata)} + end) + + profile = media_profile_fixture(%{download_source_images: false}) + source = source_fixture(media_profile_id: profile.id) + + perform_job(SourceMetadataStorageWorker, %{id: source.id}) + source = Repo.reload(source) + + refute source.fanart_filepath + refute source.poster_filepath + refute source.banner_filepath + end + + 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 -> + 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 -> + {:ok, render_metadata(:channel_source_metadata)} + end) + + profile = media_profile_fixture(%{download_source_images: true}) + source = source_fixture(media_profile_id: profile.id) + + perform_job(SourceMetadataStorageWorker, %{id: source.id}) + source = Repo.reload(source) + + refute source.fanart_filepath + refute source.poster_filepath + refute source.banner_filepath + 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