diff --git a/lib/pinchflat/media_client/video_downloader.ex b/lib/pinchflat/media_client/video_downloader.ex
index 4ab205f..d1028e9 100644
--- a/lib/pinchflat/media_client/video_downloader.ex
+++ b/lib/pinchflat/media_client/video_downloader.ex
@@ -11,7 +11,6 @@ defmodule Pinchflat.MediaClient.VideoDownloader do
alias Pinchflat.Repo
alias Pinchflat.Media
alias Pinchflat.Media.MediaItem
- alias Pinchflat.Profiles.MediaProfile
alias Pinchflat.MediaClient.Backends.YtDlp.Video, as: YtDlpVideo
alias Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder, as: YtDlpDownloadOptionBuilder
@@ -31,9 +30,8 @@ defmodule Pinchflat.MediaClient.VideoDownloader do
"""
def download_for_media_item(%MediaItem{} = media_item, backend \\ :yt_dlp) do
item_with_preloads = Repo.preload(media_item, [:metadata, source: :media_profile])
- media_profile = item_with_preloads.source.media_profile
- case download_for_media_profile(media_item.original_url, media_profile, backend) do
+ case download_with_options(media_item.original_url, item_with_preloads, backend) do
{:ok, parsed_json} ->
{parser, helpers} = metadata_parsers(backend)
@@ -57,10 +55,10 @@ defmodule Pinchflat.MediaClient.VideoDownloader do
end
end
- defp download_for_media_profile(url, %MediaProfile{} = media_profile, backend) do
+ defp download_with_options(url, item_with_preloads, backend) do
option_builder = option_builder(backend)
video_backend = video_backend(backend)
- {:ok, options} = option_builder.build(media_profile)
+ {:ok, options} = option_builder.build(item_with_preloads)
video_backend.download(url, options)
end
diff --git a/lib/pinchflat/media_source/source.ex b/lib/pinchflat/media_source/source.ex
index ed77c7b..6282e28 100644
--- a/lib/pinchflat/media_source/source.ex
+++ b/lib/pinchflat/media_source/source.ex
@@ -15,7 +15,7 @@ defmodule Pinchflat.Sources.Source do
collection_name
collection_id
collection_type
- friendly_name
+ custom_name
index_frequency_minutes
download_media
last_indexed_at
@@ -27,7 +27,7 @@ defmodule Pinchflat.Sources.Source do
collection_name
collection_id
collection_type
- friendly_name
+ custom_name
index_frequency_minutes
download_media
original_url
@@ -35,7 +35,7 @@ defmodule Pinchflat.Sources.Source do
)a
schema "sources" do
- field :friendly_name, :string
+ field :custom_name, :string
field :collection_name, :string
field :collection_id, :string
field :collection_type, Ecto.Enum, values: [:channel, :playlist]
@@ -58,7 +58,7 @@ defmodule Pinchflat.Sources.Source do
def changeset(source, attrs) do
source
|> cast(attrs, @allowed_fields)
- |> dynamic_default(:friendly_name, fn cs -> get_field(cs, :collection_name) end)
+ |> dynamic_default(:custom_name, fn cs -> get_field(cs, :collection_name) end)
|> validate_required(@required_fields)
|> unique_constraint([:collection_id, :media_profile_id])
end
diff --git a/lib/pinchflat/profiles/media_profile.ex b/lib/pinchflat/profiles/media_profile.ex
index 848eae6..db3f888 100644
--- a/lib/pinchflat/profiles/media_profile.ex
+++ b/lib/pinchflat/profiles/media_profile.ex
@@ -29,7 +29,8 @@ defmodule Pinchflat.Profiles.MediaProfile do
schema "media_profiles" do
field :name, :string
- field :output_path_template, :string, default: "/{{ channel }}/{{ title }}/{{ title }} [{{ id }}].{{ ext }}"
+ field :output_path_template, :string,
+ default: "/{{ source_custom_name }}/{{ title }}/{{ title }} [{{ id }}].{{ ext }}"
field :download_subs, :boolean, default: true
field :download_auto_subs, :boolean, default: true
diff --git a/lib/pinchflat/profiles/options/yt_dlp/download_option_builder.ex b/lib/pinchflat/profiles/options/yt_dlp/download_option_builder.ex
index 02d735b..e9b37cf 100644
--- a/lib/pinchflat/profiles/options/yt_dlp/download_option_builder.ex
+++ b/lib/pinchflat/profiles/options/yt_dlp/download_option_builder.ex
@@ -5,21 +5,17 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder do
IDEA: consider making this a behaviour so I can add other backends later
"""
- alias Pinchflat.Profiles.MediaProfile
+ alias Pinchflat.Media.MediaItem
alias Pinchflat.Profiles.Options.YtDlp.OutputPathBuilder
@doc """
- Builds the options for yt-dlp to download media based on the given media profile.
+ Builds the options for yt-dlp to download media based on the given media's profile.
IDEA: consider adding the ability to pass in a second argument to override
these options
"""
- def build(%MediaProfile{} = media_profile) do
- # NOTE: I'll be hardcoding most things for now (esp. options to help me test) -
- # add more configuration later as I build out the models. Walk before you can run!
-
- # NOTE: Looks like you can put different media types in different directories.
- # see: https://github.com/yt-dlp/yt-dlp#output-template
+ def build(%MediaItem{} = media_item_with_preloads) do
+ media_profile = media_item_with_preloads.source.media_profile
built_options =
default_options() ++
@@ -27,12 +23,11 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder do
thumbnail_options(media_profile) ++
metadata_options(media_profile) ++
quality_options(media_profile) ++
- output_options(media_profile)
+ output_options(media_item_with_preloads)
{:ok, built_options}
end
- # This will be updated a lot as I add new options to profiles
defp default_options do
[:no_progress, :windows_filenames]
end
@@ -101,14 +96,25 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder do
end
end
- defp output_options(media_profile) do
- {:ok, output_path} = OutputPathBuilder.build(media_profile.output_path_template)
+ defp output_options(media_item_with_preloads) do
+ media_profile = media_item_with_preloads.source.media_profile
+ additional_options_map = output_options_map(media_item_with_preloads)
+ {:ok, output_path} = OutputPathBuilder.build(media_profile.output_path_template, additional_options_map)
[
output: Path.join(base_directory(), output_path)
]
end
+ defp output_options_map(media_item_with_preloads) do
+ source = media_item_with_preloads.source
+
+ %{
+ "source_custom_name" => source.custom_name,
+ "source_collection_type" => source.collection_type
+ }
+ end
+
defp base_directory do
Application.get_env(:pinchflat, :media_directory)
end
diff --git a/lib/pinchflat/profiles/options/yt_dlp/output_path_builder.ex b/lib/pinchflat/profiles/options/yt_dlp/output_path_builder.ex
index dadb9fe..4f76eb2 100644
--- a/lib/pinchflat/profiles/options/yt_dlp/output_path_builder.ex
+++ b/lib/pinchflat/profiles/options/yt_dlp/output_path_builder.ex
@@ -8,13 +8,16 @@ defmodule Pinchflat.Profiles.Options.YtDlp.OutputPathBuilder do
alias Pinchflat.RenderedString.Parser, as: TemplateParser
@doc """
- Builds the actual final filepath from a given template.
+ Builds the actual final filepath from a given template. Optionally, you can pass in
+ a map of additional options to be used in the template.
Translates liquid-style templates into yt-dlp-style templates,
leaving yt-dlp syntax intact.
"""
- def build(template_string) do
- TemplateParser.parse(template_string, custom_yt_dlp_option_map(), &identifier_fn/2)
+ def build(template_string, additional_template_options \\ %{}) do
+ combined_options = Map.merge(custom_yt_dlp_option_map(), additional_template_options)
+
+ TemplateParser.parse(template_string, combined_options, &identifier_fn/2)
end
# The `nil` case simply wraps the identifier in yt-dlp-style syntax. This assumes that
@@ -30,6 +33,9 @@ defmodule Pinchflat.Profiles.Options.YtDlp.OutputPathBuilder do
end
end
+ # This isn't the only source for custom options, since they can be passed in my the caller.
+ # `download_option_builder` is the most likely place for other custom options to be added,
+ # but if in doubt just search the codebase for `OutputPathBuilder.build`.
defp custom_yt_dlp_option_map do
%{
# Individual parts of the upload date
diff --git a/lib/pinchflat/workers/media_indexing_worker.ex b/lib/pinchflat/workers/media_indexing_worker.ex
index 6dc0c32..ae54ac1 100644
--- a/lib/pinchflat/workers/media_indexing_worker.ex
+++ b/lib/pinchflat/workers/media_indexing_worker.ex
@@ -15,8 +15,9 @@ defmodule Pinchflat.Workers.MediaIndexingWorker do
@doc """
The ID is that of a source _record_, not a YouTube channel/playlist ID. Indexes
the provided source, kicks off downloads for each new MediaItem, and
- reschedules the job to run again in the future (as determined by the
- souce's `index_frequency_minutes` field).
+ reschedules the job to run again in the future. It will ALWAYS index a source
+ if it's never been indexed before, but rescheduling is determined by the
+ `index_frequency_minutes` field.
README: Re-scheduling here works a little different than you may expect.
The reschedule time is relative to the time the job has actually _completed_.
@@ -39,18 +40,31 @@ defmodule Pinchflat.Workers.MediaIndexingWorker do
def perform(%Oban.Job{args: %{"id" => source_id}}) do
source = Sources.get_source!(source_id)
- if source.index_frequency_minutes <= 0 do
- :ok
- else
- index_media_and_reschedule(source)
+ case {source.index_frequency_minutes, source.last_indexed_at} do
+ {index_freq, _} when index_freq > 0 ->
+ # If the indexing is on a schedule simply run indexing and reschedule
+ index_media(source)
+ reschedule_indexing(source)
+
+ {_, nil} ->
+ # If the source has never been indexed, index it once
+ # even if it's not meant to reschedule
+ index_media(source)
+
+ _ ->
+ # If the source HAS been indexed and is not meant to reschedule,
+ # perform a no-op
+ :ok
end
end
- defp index_media_and_reschedule(source) do
+ defp index_media(source) do
SourceTasks.index_media_items(source)
# This method handles the case where a source is set to not download media
SourceTasks.enqueue_pending_media_tasks(source)
+ end
+ defp reschedule_indexing(source) do
source
|> Map.take([:id])
|> MediaIndexingWorker.new(schedule_in: source.index_frequency_minutes * 60)
diff --git a/lib/pinchflat_web/controllers/media_items/media_item_html/show.html.heex b/lib/pinchflat_web/controllers/media_items/media_item_html/show.html.heex
index 95da677..8056359 100644
--- a/lib/pinchflat_web/controllers/media_items/media_item_html/show.html.heex
+++ b/lib/pinchflat_web/controllers/media_items/media_item_html/show.html.heex
@@ -17,7 +17,7 @@
Source:
<.inline_link href={~p"/sources/#{@media_item.source_id}"}>
- <%= @media_item.source.friendly_name %>
+ <%= @media_item.source.custom_name %>
diff --git a/lib/pinchflat_web/controllers/media_profiles/media_profile_html.ex b/lib/pinchflat_web/controllers/media_profiles/media_profile_html.ex
index 41840f0..a313002 100644
--- a/lib/pinchflat_web/controllers/media_profiles/media_profile_html.ex
+++ b/lib/pinchflat_web/controllers/media_profiles/media_profile_html.ex
@@ -30,7 +30,13 @@ defmodule PinchflatWeb.MediaProfiles.MediaProfileHTML do
end
def custom_output_template_options do
- ~w(upload_day upload_month upload_year)a
+ %{
+ upload_day: nil,
+ upload_month: nil,
+ upload_year: nil,
+ source_custom_name: "the name of the sources that use this profile",
+ source_collection_type: "the collection type of the sources that use this profile. Either 'channel' or 'playlist'"
+ }
end
def common_output_template_options do
diff --git a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/output_template_help.html.heex b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/output_template_help.html.heex
index 7b11b1d..7dd6df2 100644
--- a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/output_template_help.html.heex
+++ b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/output_template_help.html.heex
@@ -46,8 +46,8 @@
Template Options
-
-
+
+
Any single-word yt-dlp
option
<.inline_link href="https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#output-template">
@@ -58,8 +58,9 @@
Custom Aliases
- -
- <.inline_code>{{ <%= opt %> }}
+
-
+ <.inline_code>{{ <%= k %> }}
+ - <%= v %>
Common Options
diff --git a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/show.html.heex b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/show.html.heex
index 7cdb2df..a7e5b1f 100644
--- a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/show.html.heex
+++ b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/show.html.heex
@@ -50,7 +50,7 @@
<:tab title="Sources">
<.table rows={@media_profile.sources} table_class="text-black dark:text-white">
<:col :let={source} label="Name">
- <%= source.friendly_name || source.collection_name %>
+ <%= source.custom_name || source.collection_name %>
<:col :let={source} label="Type"><%= source.collection_type %>
<:col :let={source} label="Should Download?">
diff --git a/lib/pinchflat_web/controllers/sources/source_html/index.html.heex b/lib/pinchflat_web/controllers/sources/source_html/index.html.heex
index 3dbfec2..0b3f743 100644
--- a/lib/pinchflat_web/controllers/sources/source_html/index.html.heex
+++ b/lib/pinchflat_web/controllers/sources/source_html/index.html.heex
@@ -14,7 +14,7 @@
<.table rows={@sources} table_class="text-black dark:text-white">
<:col :let={source} label="Name">
- <%= source.friendly_name || source.collection_name %>
+ <%= source.custom_name || source.collection_name %>
<:col :let={source} label="Type"><%= source.collection_type %>
<:col :let={source} label="Should Download?">
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 c4f8f70..f7f5fe0 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
@@ -4,7 +4,7 @@
<.input
- field={f[:friendly_name]}
+ field={f[:custom_name]}
type="text"
label="Custom Name"
help="Something descriptive. Does not impact indexing or downloading"
diff --git a/priv/repo/migrations/20240302194115_rename_friendly_name_to_custom_name.exs b/priv/repo/migrations/20240302194115_rename_friendly_name_to_custom_name.exs
new file mode 100644
index 0000000..16bfba5
--- /dev/null
+++ b/priv/repo/migrations/20240302194115_rename_friendly_name_to_custom_name.exs
@@ -0,0 +1,7 @@
+defmodule Pinchflat.Repo.Migrations.RenameFriendlyNameToCustomName do
+ use Ecto.Migration
+
+ def change do
+ rename table(:sources), :friendly_name, to: :custom_name
+ end
+end
diff --git a/test/pinchflat/media_client/backends/yt_dlp/output_path_builder_test.exs b/test/pinchflat/media_client/backends/yt_dlp/output_path_builder_test.exs
index 8915639..f924981 100644
--- a/test/pinchflat/media_client/backends/yt_dlp/output_path_builder_test.exs
+++ b/test/pinchflat/media_client/backends/yt_dlp/output_path_builder_test.exs
@@ -3,7 +3,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.OutputPathBuilderTest do
alias Pinchflat.Profiles.Options.YtDlp.OutputPathBuilder
- describe "build/1" do
+ describe "build/2" do
test "it expands 'standard' curly brace variables in the template" do
assert {:ok, res} = OutputPathBuilder.build("/videos/{{ title }}.{{ ext }}")
@@ -16,6 +16,12 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.OutputPathBuilderTest do
assert res == "/videos/%(upload_date>%Y)S.%(ext)S"
end
+ test "it respects additional options" do
+ assert {:ok, res} = OutputPathBuilder.build("/videos/{{ custom }}.{{ ext }}", %{"custom" => "test"})
+
+ assert res == "/videos/test.%(ext)S"
+ end
+
test "it leaves yt-dlp variables alone" do
assert {:ok, res} = OutputPathBuilder.build("/videos/%(title)s.%(ext)s")
diff --git a/test/pinchflat/profiles/options/yt_dlp/download_option_builder_test.exs b/test/pinchflat/profiles/options/yt_dlp/download_option_builder_test.exs
index 69e7f12..38e1ea0 100644
--- a/test/pinchflat/profiles/options/yt_dlp/download_option_builder_test.exs
+++ b/test/pinchflat/profiles/options/yt_dlp/download_option_builder_test.exs
@@ -1,24 +1,40 @@
defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilderTest do
- use ExUnit.Case, async: true
+ use Pinchflat.DataCase
+ import Pinchflat.MediaFixtures
+ import Pinchflat.ProfilesFixtures
+ import Pinchflat.SourcesFixtures
- alias Pinchflat.Profiles.MediaProfile
+ alias Pinchflat.Profiles
alias Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder
- @media_profile %MediaProfile{
- output_path_template: "{{ title }}.%(ext)s"
- }
+ 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)
- describe "build/1" do
- test "it generates an expanded output path based on the given template" do
- assert {:ok, res} = DownloadOptionBuilder.build(@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/videos/%(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/videos/#{media_item.source.custom_name}.%(ext)s"} in res
+ end
end
describe "build/1 when testing default options" do
- test "it includes default options" do
- assert {:ok, res} = DownloadOptionBuilder.build(@media_profile)
+ 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
@@ -26,109 +42,93 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilderTest do
end
describe "build/1 when testing subtitle options" do
- test "includes :write_subs option when specified" do
- media_profile = %MediaProfile{@media_profile | download_subs: true}
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :write_subs in res
end
- test "forces SRT format when download_subs is true" do
- media_profile = %MediaProfile{@media_profile | download_subs: true}
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:convert_subs, "srt"} in res
end
- test "includes :write_auto_subs option when specified" do
- media_profile = %MediaProfile{@media_profile | download_subs: true, download_auto_subs: true}
+ 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_profile)
+ 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" do
- media_profile = %MediaProfile{@media_profile | download_subs: false, download_auto_subs: true}
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
refute :write_auto_subs in res
end
- test "includes :embed_subs option when specified" do
- media_profile = %MediaProfile{@media_profile | embed_subs: true}
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :embed_subs in res
end
- test "includes sub_langs option when download_subs is true" do
- media_profile = %MediaProfile{@media_profile | download_subs: true, sub_langs: "en"}
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:sub_langs, "en"} in res
end
- test "includes sub_langs option when embed_subs is true" do
- media_profile = %MediaProfile{@media_profile | embed_subs: true, sub_langs: "en"}
+ 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_profile)
+ 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" do
- media_profile = %MediaProfile{
- @media_profile
- | embed_subs: false,
- download_subs: false,
- sub_langs: "en"
- }
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
refute {:sub_langs, "en"} in res
end
-
- test "other struct attributes are ignored" do
- media_profile = %MediaProfile{@media_profile | id: -1}
-
- assert {:ok, res} = DownloadOptionBuilder.build(media_profile)
-
- refute {:id, -1} in res
- end
end
describe "build/1 when testing thumbnail options" do
- test "includes :write_thumbnail option when specified" do
- media_profile = %MediaProfile{@media_profile | download_thumbnail: true}
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :write_thumbnail in res
end
- test "includes :embed_thumbnail option when specified" do
- media_profile = %MediaProfile{@media_profile | embed_thumbnail: true}
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :embed_thumbnail in res
end
- test "doesn't include these options when not specified" do
- media_profile = %MediaProfile{
- @media_profile
- | embed_thumbnail: false,
- download_thumbnail: false
- }
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
refute :write_thumbnail in res
refute :embed_thumbnail in res
@@ -136,31 +136,27 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilderTest do
end
describe "build/1 when testing metadata options" do
- test "includes :write_info_json option when specified" do
- media_profile = %MediaProfile{@media_profile | download_metadata: true}
+ 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_profile)
+ 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" do
- media_profile = %MediaProfile{@media_profile | embed_metadata: true}
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert :embed_metadata in res
end
- test "doesn't include these options when not specified" do
- media_profile = %MediaProfile{
- @media_profile
- | embed_metadata: false,
- download_metadata: false
- }
+ 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_profile)
+ assert {:ok, res} = DownloadOptionBuilder.build(media_item)
refute :write_info_json in res
refute :clean_info_json in res
@@ -169,10 +165,22 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilderTest do
end
describe "build/1 when testing quality options" do
- test "it includes quality options" do
- assert {:ok, res} = DownloadOptionBuilder.build(@media_profile)
+ 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
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
diff --git a/test/pinchflat/sources_test.exs b/test/pinchflat/sources_test.exs
index 9fccb70..2426c52 100644
--- a/test/pinchflat/sources_test.exs
+++ b/test/pinchflat/sources_test.exs
@@ -66,18 +66,18 @@ defmodule Pinchflat.SourcesTest do
assert String.starts_with?(source.collection_id, "some_playlist_id_")
end
- test "you can specify a custom friendly_name" do
+ test "you can specify a custom custom_name" do
expect(YtDlpRunnerMock, :run, &channel_mock/3)
valid_attrs = %{
media_profile_id: media_profile_fixture().id,
original_url: "https://www.youtube.com/channel/abc123",
- friendly_name: "some custom name"
+ custom_name: "some custom name"
}
assert {:ok, %Source{} = source} = Sources.create_source(valid_attrs)
- assert source.friendly_name == "some custom name"
+ assert source.custom_name == "some custom name"
end
test "friendly name is pulled from collection_name if not specified" do
@@ -90,7 +90,7 @@ defmodule Pinchflat.SourcesTest do
assert {:ok, %Source{} = source} = Sources.create_source(valid_attrs)
- assert source.friendly_name == "some channel name"
+ assert source.custom_name == "some channel name"
end
test "collection_type is inferred from source details" do
diff --git a/test/pinchflat/workers/media_indexing_worker_test.exs b/test/pinchflat/workers/media_indexing_worker_test.exs
index 176fa56..9fdc00a 100644
--- a/test/pinchflat/workers/media_indexing_worker_test.exs
+++ b/test/pinchflat/workers/media_indexing_worker_test.exs
@@ -12,23 +12,6 @@ defmodule Pinchflat.Workers.MediaIndexingWorkerTest do
setup :verify_on_exit!
describe "perform/1" do
- test "it does not do any indexing if the source shouldn't be indexed" do
- expect(YtDlpRunnerMock, :run, 0, fn _url, _opts, _ot -> {:ok, ""} end)
-
- source = source_fixture(index_frequency_minutes: -1)
-
- perform_job(MediaIndexingWorker, %{id: source.id})
- end
-
- test "it does not reschedule if the source shouldn't be indexed" do
- expect(YtDlpRunnerMock, :run, 0, fn _url, _opts, _ot -> {:ok, ""} end)
-
- source = source_fixture(index_frequency_minutes: -1)
- perform_job(MediaIndexingWorker, %{id: source.id})
-
- refute_enqueued(worker: MediaIndexingWorker, args: %{"id" => source.id})
- end
-
test "it indexes the source if it should be indexed" do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end)
@@ -37,6 +20,31 @@ defmodule Pinchflat.Workers.MediaIndexingWorkerTest do
perform_job(MediaIndexingWorker, %{id: source.id})
end
+ test "it indexes the source no matter what if the source has never been indexed before" do
+ expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end)
+
+ source = source_fixture(index_frequency_minutes: 0, last_indexed_at: nil)
+
+ perform_job(MediaIndexingWorker, %{id: source.id})
+ end
+
+ test "it does not do any indexing if the source has been indexed and shouldn't be rescheduled" do
+ expect(YtDlpRunnerMock, :run, 0, fn _url, _opts, _ot -> {:ok, ""} end)
+
+ source = source_fixture(index_frequency_minutes: -1, last_indexed_at: DateTime.utc_now())
+
+ perform_job(MediaIndexingWorker, %{id: source.id})
+ end
+
+ test "it does not reschedule if the source shouldn't be indexed" do
+ stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, ""} end)
+
+ source = source_fixture(index_frequency_minutes: -1)
+ perform_job(MediaIndexingWorker, %{id: source.id})
+
+ refute_enqueued(worker: MediaIndexingWorker, args: %{"id" => source.id})
+ end
+
test "it kicks off a download job for each pending media item" do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, source_attributes_return_fixture()} end)
diff --git a/test/support/fixtures/sources_fixtures.ex b/test/support/fixtures/sources_fixtures.ex
index 2a8d8ad..5c25ffc 100644
--- a/test/support/fixtures/sources_fixtures.ex
+++ b/test/support/fixtures/sources_fixtures.ex
@@ -19,7 +19,7 @@ defmodule Pinchflat.SourcesFixtures do
collection_name: "Source ##{:rand.uniform(1_000_000)}",
collection_id: Base.encode16(:crypto.hash(:md5, "#{:rand.uniform(1_000_000)}")),
collection_type: "channel",
- friendly_name: "Cool and good internal name!",
+ custom_name: "Cool and good internal name!",
original_url: "https://www.youtube.com/channel/#{Faker.String.base64(12)}",
media_profile_id: ProfilesFixtures.media_profile_fixture().id,
index_frequency_minutes: 60