Rename video-related modules to be media-related (#50)

* Added test from before that I forgor

* Renamed video-related modules to media
This commit is contained in:
Kieran
2024-03-04 17:46:33 -08:00
committed by GitHub
parent f55cdc80dd
commit 90a0022d85
21 changed files with 128 additions and 109 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ alias Pinchflat.Media
alias Pinchflat.Profiles alias Pinchflat.Profiles
alias Pinchflat.Sources alias Pinchflat.Sources
alias Pinchflat.MediaClient.{SourceDetails, VideoDownloader} alias Pinchflat.MediaClient.{SourceDetails, MediaDownloader}
alias Pinchflat.Metadata.{Zipper, ThumbnailFetcher} alias Pinchflat.Metadata.{Zipper, ThumbnailFetcher}
alias Pinchflat.Utils.FilesystemUtils.FileFollowerServer alias Pinchflat.Utils.FilesystemUtils.FileFollowerServer
+1 -1
View File
@@ -1,7 +1,7 @@
import Config import Config
config :pinchflat, config :pinchflat,
media_directory: Path.join([File.cwd!(), "tmp", "videos"]), media_directory: Path.join([File.cwd!(), "tmp", "media"]),
metadata_directory: Path.join([File.cwd!(), "tmp", "metadata"]), metadata_directory: Path.join([File.cwd!(), "tmp", "metadata"]),
tmpfile_directory: Path.join([File.cwd!(), "tmp", "tmpfiles"]) tmpfile_directory: Path.join([File.cwd!(), "tmp", "tmpfiles"])
+1 -1
View File
@@ -3,7 +3,7 @@ import Config
config :pinchflat, config :pinchflat,
# Specifying backend data here makes mocking and local testing SUPER easy # Specifying backend data here makes mocking and local testing SUPER easy
yt_dlp_executable: Path.join([File.cwd!(), "/test/support/scripts/yt-dlp-mocks/repeater.sh"]), yt_dlp_executable: Path.join([File.cwd!(), "/test/support/scripts/yt-dlp-mocks/repeater.sh"]),
media_directory: Path.join([System.tmp_dir!(), "test", "videos"]), media_directory: Path.join([System.tmp_dir!(), "test", "media"]),
metadata_directory: Path.join([System.tmp_dir!(), "test", "metadata"]), metadata_directory: Path.join([System.tmp_dir!(), "test", "metadata"]),
tmpfile_directory: Path.join([System.tmp_dir!(), "test", "tmpfiles"]), tmpfile_directory: Path.join([System.tmp_dir!(), "test", "tmpfiles"]),
file_watcher_poll_interval: 50 file_watcher_poll_interval: 50
@@ -1,10 +1,10 @@
defmodule Pinchflat.MediaClient.Backends.YtDlp.Video do defmodule Pinchflat.MediaClient.Backends.YtDlp.Media do
@moduledoc """ @moduledoc """
Contains utilities for working with singular videos Contains utilities for working with singular pieces of media
""" """
@doc """ @doc """
Downloads a single video (and possibly its metadata) directly to its Downloads a single piece of media (and possibly its metadata) directly to its
final destination. Returns the parsed JSON output from yt-dlp. final destination. Returns the parsed JSON output from yt-dlp.
Returns {:ok, map()} | {:error, any, ...}. Returns {:ok, map()} | {:error, any, ...}.
@@ -1,7 +1,7 @@
defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollection do defmodule Pinchflat.MediaClient.Backends.YtDlp.MediaCollection do
@moduledoc """ @moduledoc """
Contains utilities for working with collections of Contains utilities for working with collections of
videos (aka: a source [ie: channels, playlists]). media (aka: a source [ie: channels, playlists]).
""" """
require Logger require Logger
@@ -10,7 +10,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollection do
alias Pinchflat.Utils.FilesystemUtils alias Pinchflat.Utils.FilesystemUtils
@doc """ @doc """
Returns a list of maps representing the videos in the collection. Returns a list of maps representing the media in the collection.
Options: Options:
- :file_listener_handler - a function that will be called with the path to the - :file_listener_handler - a function that will be called with the path to the
@@ -4,7 +4,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.MetadataFileHelpers do
out-of-band of the normal yt-dlp backend process. out-of-band of the normal yt-dlp backend process.
The idea is that I don't want to craft a complicated yt-dlp command, The idea is that I don't want to craft a complicated yt-dlp command,
instead focusing on downloading the video as the user wants it then instead focusing on downloading the media as the user wants it then
I can use the result of that here to grab the additional information I can use the result of that here to grab the additional information
needed needed
""" """
@@ -1,8 +1,8 @@
defmodule Pinchflat.MediaClient.VideoDownloader do defmodule Pinchflat.MediaClient.MediaDownloader do
@moduledoc """ @moduledoc """
This is the integration layer for actually downloading videos. This is the integration layer for actually downloading medias.
It takes into account the media profile's settings in order It takes into account the media profile's settings in order
to download the video with the desired options. to download the media with the desired options.
Technically hardcodes the yt-dlp backend for now, but should leave Technically hardcodes the yt-dlp backend for now, but should leave
it open-ish for future expansion (just in case). it open-ish for future expansion (just in case).
@@ -12,13 +12,13 @@ defmodule Pinchflat.MediaClient.VideoDownloader do
alias Pinchflat.Media alias Pinchflat.Media
alias Pinchflat.Media.MediaItem alias Pinchflat.Media.MediaItem
alias Pinchflat.MediaClient.Backends.YtDlp.Video, as: YtDlpVideo alias Pinchflat.MediaClient.Backends.YtDlp.Media, as: YtDlpMedia
alias Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder, as: YtDlpDownloadOptionBuilder alias Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilder, as: YtDlpDownloadOptionBuilder
alias Pinchflat.MediaClient.Backends.YtDlp.MetadataParser, as: YtDlpMetadataParser alias Pinchflat.MediaClient.Backends.YtDlp.MetadataParser, as: YtDlpMetadataParser
alias Pinchflat.MediaClient.Backends.YtDlp.MetadataFileHelpers, as: YtDlpMetadataHelpers alias Pinchflat.MediaClient.Backends.YtDlp.MetadataFileHelpers, as: YtDlpMetadataHelpers
@doc """ @doc """
Downloads a video for a media item, updating the media item based on the metadata Downloads media for a media item, updating the media item based on the metadata
returned by the backend. Also saves the entire metadata response to the associated returned by the backend. Also saves the entire metadata response to the associated
media_metadata record. media_metadata record.
@@ -57,10 +57,10 @@ defmodule Pinchflat.MediaClient.VideoDownloader do
defp download_with_options(url, item_with_preloads, backend) do defp download_with_options(url, item_with_preloads, backend) do
option_builder = option_builder(backend) option_builder = option_builder(backend)
video_backend = video_backend(backend) media_backend = media_backend(backend)
{:ok, options} = option_builder.build(item_with_preloads) {:ok, options} = option_builder.build(item_with_preloads)
video_backend.download(url, options) media_backend.download(url, options)
end end
defp option_builder(backend) do defp option_builder(backend) do
@@ -69,9 +69,9 @@ defmodule Pinchflat.MediaClient.VideoDownloader do
end end
end end
defp video_backend(backend) do defp media_backend(backend) do
case backend do case backend do
:yt_dlp -> YtDlpVideo :yt_dlp -> YtDlpMedia
end end
end end
+2 -2
View File
@@ -7,7 +7,7 @@ defmodule Pinchflat.MediaClient.SourceDetails do
""" """
alias Pinchflat.Sources.Source alias Pinchflat.Sources.Source
alias Pinchflat.MediaClient.Backends.YtDlp.VideoCollection, as: YtDlpSource alias Pinchflat.MediaClient.Backends.YtDlp.MediaCollection, as: YtDlpSource
@doc """ @doc """
Gets a source's ID and name from its URL using the given backend. Gets a source's ID and name from its URL using the given backend.
@@ -19,7 +19,7 @@ defmodule Pinchflat.MediaClient.SourceDetails do
end end
@doc """ @doc """
Returns a list of basic video data mapsfor the given source URL OR Returns a list of basic media data maps for the given source URL OR
source record using the given backend. source record using the given backend.
Options: Options:
+2 -2
View File
@@ -44,10 +44,10 @@ defmodule Pinchflat.Profiles.MediaProfile do
field :embed_metadata, :boolean, default: true field :embed_metadata, :boolean, default: true
# NOTE: these do NOT speed up indexing - the indexer still has to go # NOTE: these do NOT speed up indexing - the indexer still has to go
# through the entire collection to determine if a video is a short or # through the entire collection to determine if a media is a short or
# a livestream. # a livestream.
# NOTE: these can BOTH be set to :only which will download shorts and # NOTE: these can BOTH be set to :only which will download shorts and
# livestreams _only_ and ignore regular videos. The redundant case # livestreams _only_ and ignore regular media. The redundant case
# is when one is set to :only and the other is set to :exclude. # is when one is set to :only and the other is set to :exclude.
# See `build_format_clauses` in the Media context for more. # See `build_format_clauses` in the Media context for more.
field :shorts_behaviour, Ecto.Enum, values: ~w(include exclude only)a, default: :include field :shorts_behaviour, Ecto.Enum, values: ~w(include exclude only)a, default: :include
+4 -4
View File
@@ -15,7 +15,7 @@ defmodule Pinchflat.Tasks.SourceTasks do
alias Pinchflat.Media.MediaItem alias Pinchflat.Media.MediaItem
alias Pinchflat.MediaClient.SourceDetails alias Pinchflat.MediaClient.SourceDetails
alias Pinchflat.Workers.MediaIndexingWorker alias Pinchflat.Workers.MediaIndexingWorker
alias Pinchflat.Workers.VideoDownloadWorker alias Pinchflat.Workers.MediaDownloadWorker
alias Pinchflat.Utils.FilesystemUtils.FileFollowerServer alias Pinchflat.Utils.FilesystemUtils.FileFollowerServer
@doc """ @doc """
@@ -75,7 +75,7 @@ defmodule Pinchflat.Tasks.SourceTasks do
end end
@doc """ @doc """
Starts tasks for downloading videos for any of a sources _pending_ media items. Starts tasks for downloading media for any of a sources _pending_ media items.
Jobs are not enqueued if the source is set to not download media. This will return :ok. Jobs are not enqueued if the source is set to not download media. This will return :ok.
NOTE: this starts a download for each media item that is pending, NOTE: this starts a download for each media item that is pending,
@@ -91,7 +91,7 @@ defmodule Pinchflat.Tasks.SourceTasks do
|> Enum.each(fn media_item -> |> Enum.each(fn media_item ->
media_item media_item
|> Map.take([:id]) |> Map.take([:id])
|> VideoDownloadWorker.new() |> MediaDownloadWorker.new()
|> Tasks.create_job_with_task(media_item) |> Tasks.create_job_with_task(media_item)
end) end)
end end
@@ -161,7 +161,7 @@ defmodule Pinchflat.Tasks.SourceTasks do
media_item media_item
|> Map.take([:id]) |> Map.take([:id])
|> VideoDownloadWorker.new() |> MediaDownloadWorker.new()
|> Tasks.create_job_with_task(media_item) |> Tasks.create_job_with_task(media_item)
end end
@@ -1,4 +1,4 @@
defmodule Pinchflat.Workers.VideoDownloadWorker do defmodule Pinchflat.Workers.MediaDownloadWorker do
@moduledoc false @moduledoc false
use Oban.Worker, use Oban.Worker,
@@ -9,7 +9,7 @@ defmodule Pinchflat.Workers.VideoDownloadWorker do
alias Pinchflat.Repo alias Pinchflat.Repo
alias Pinchflat.Media alias Pinchflat.Media
alias Pinchflat.Tasks alias Pinchflat.Tasks
alias Pinchflat.MediaClient.VideoDownloader alias Pinchflat.MediaClient.MediaDownloader
alias Pinchflat.Workers.FilesystemDataWorker alias Pinchflat.Workers.FilesystemDataWorker
@impl Oban.Worker @impl Oban.Worker
@@ -34,7 +34,7 @@ defmodule Pinchflat.Workers.VideoDownloadWorker do
end end
defp download_media_and_schedule_jobs(media_item) do defp download_media_and_schedule_jobs(media_item) do
case VideoDownloader.download_for_media_item(media_item) do case MediaDownloader.download_for_media_item(media_item) do
{:ok, _} -> {:ok, _} ->
schedule_filesystem_data_worker(media_item) schedule_filesystem_data_worker(media_item)
{:ok, media_item} {:ok, media_item}
@@ -4,7 +4,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.CommandRunnerTest do
alias Pinchflat.MediaClient.Backends.YtDlp.CommandRunner, as: Runner alias Pinchflat.MediaClient.Backends.YtDlp.CommandRunner, as: Runner
@original_executable Application.compile_env(:pinchflat, :yt_dlp_executable) @original_executable Application.compile_env(:pinchflat, :yt_dlp_executable)
@video_url "https://www.youtube.com/watch?v=-LHXuyzpex0" @media_url "https://www.youtube.com/watch?v=-LHXuyzpex0"
setup do setup do
on_exit(&reset_executable/0) on_exit(&reset_executable/0)
@@ -12,54 +12,54 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.CommandRunnerTest do
describe "run/4" do describe "run/4" do
test "it returns the output and status when the command succeeds" do test "it returns the output and status when the command succeeds" do
assert {:ok, _output} = Runner.run(@video_url, [], "") assert {:ok, _output} = Runner.run(@media_url, [], "")
end end
test "it converts symbol k-v arg keys to kebab case" do test "it converts symbol k-v arg keys to kebab case" do
assert {:ok, output} = Runner.run(@video_url, [buffer_size: 1024], "") assert {:ok, output} = Runner.run(@media_url, [buffer_size: 1024], "")
assert String.contains?(output, "--buffer-size 1024") assert String.contains?(output, "--buffer-size 1024")
end end
test "it keeps string k-v arg keys untouched" do test "it keeps string k-v arg keys untouched" do
assert {:ok, output} = Runner.run(@video_url, [{"--under_score", 1024}], "") assert {:ok, output} = Runner.run(@media_url, [{"--under_score", 1024}], "")
assert String.contains?(output, "--under_score 1024") assert String.contains?(output, "--under_score 1024")
end end
test "it converts symbol arg keys to kebab case" do test "it converts symbol arg keys to kebab case" do
assert {:ok, output} = Runner.run(@video_url, [:ignore_errors], "") assert {:ok, output} = Runner.run(@media_url, [:ignore_errors], "")
assert String.contains?(output, "--ignore-errors") assert String.contains?(output, "--ignore-errors")
end end
test "it keeps string arg keys untouched" do test "it keeps string arg keys untouched" do
assert {:ok, output} = Runner.run(@video_url, ["-v"], "") assert {:ok, output} = Runner.run(@media_url, ["-v"], "")
assert String.contains?(output, "-v") assert String.contains?(output, "-v")
refute String.contains?(output, "--v") refute String.contains?(output, "--v")
end end
test "it includes the video url as the first argument" do test "it includes the media url as the first argument" do
assert {:ok, output} = Runner.run(@video_url, [:ignore_errors], "") assert {:ok, output} = Runner.run(@media_url, [:ignore_errors], "")
assert String.contains?(output, "#{@video_url} --ignore-errors") assert String.contains?(output, "#{@media_url} --ignore-errors")
end end
test "it automatically includes the --print-to-file flag" do test "it automatically includes the --print-to-file flag" do
assert {:ok, output} = Runner.run(@video_url, [], "%(id)s") assert {:ok, output} = Runner.run(@media_url, [], "%(id)s")
assert String.contains?(output, "--print-to-file %(id)s /tmp/") assert String.contains?(output, "--print-to-file %(id)s /tmp/")
end end
test "it returns the output and status when the command fails" do test "it returns the output and status when the command fails" do
wrap_executable("/bin/false", fn -> wrap_executable("/bin/false", fn ->
assert {:error, "", 1} = Runner.run(@video_url, [], "") assert {:error, "", 1} = Runner.run(@media_url, [], "")
end) end)
end end
test "optionally lets you specify an output_filepath" do test "optionally lets you specify an output_filepath" do
assert {:ok, output} = Runner.run(@video_url, [], "%(id)s", output_filepath: "/tmp/yt-dlp-output.json") assert {:ok, output} = Runner.run(@media_url, [], "%(id)s", output_filepath: "/tmp/yt-dlp-output.json")
assert String.contains?(output, "--print-to-file %(id)s /tmp/yt-dlp-output.json") assert String.contains?(output, "--print-to-file %(id)s /tmp/yt-dlp-output.json")
end end
@@ -1,9 +1,9 @@
defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do defmodule Pinchflat.MediaClient.Backends.YtDlp.MediaCollectionTest do
use Pinchflat.DataCase use Pinchflat.DataCase
import Mox import Mox
import Pinchflat.SourcesFixtures import Pinchflat.SourcesFixtures
alias Pinchflat.MediaClient.Backends.YtDlp.VideoCollection alias Pinchflat.MediaClient.Backends.YtDlp.MediaCollection
@channel_url "https://www.youtube.com/c/TheUselessTrials" @channel_url "https://www.youtube.com/c/TheUselessTrials"
@@ -16,7 +16,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
end) end)
assert {:ok, [%{"id" => "video1"}, %{"id" => "video2"}, %{"id" => "video3"}]} = assert {:ok, [%{"id" => "video1"}, %{"id" => "video2"}, %{"id" => "video3"}]} =
VideoCollection.get_media_attributes(@channel_url) MediaCollection.get_media_attributes(@channel_url)
end end
test "it passes the expected default args" do test "it passes the expected default args" do
@@ -27,13 +27,13 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
{:ok, ""} {:ok, ""}
end) end)
assert {:ok, _} = VideoCollection.get_media_attributes(@channel_url) assert {:ok, _} = MediaCollection.get_media_attributes(@channel_url)
end end
test "returns the error straight through when the command fails" do test "returns the error straight through when the command fails" do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl_opts -> {:error, "Big issue", 1} end) expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot, _addl_opts -> {:error, "Big issue", 1} end)
assert {:error, "Big issue", 1} = VideoCollection.get_media_attributes(@channel_url) assert {:error, "Big issue", 1} = MediaCollection.get_media_attributes(@channel_url)
end end
test "passes the explict tmpfile path to runner" do test "passes the explict tmpfile path to runner" do
@@ -44,7 +44,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
{:ok, ""} {:ok, ""}
end) end)
assert {:ok, _} = VideoCollection.get_media_attributes(@channel_url) assert {:ok, _} = MediaCollection.get_media_attributes(@channel_url)
end end
test "supports an optional file_listener_handler that gets passed a filename" do test "supports an optional file_listener_handler that gets passed a filename" do
@@ -55,7 +55,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
send(current_self, {:handler, filename}) send(current_self, {:handler, filename})
end end
assert {:ok, _} = VideoCollection.get_media_attributes(@channel_url, file_listener_handler: handler) assert {:ok, _} = MediaCollection.get_media_attributes(@channel_url, file_listener_handler: handler)
assert_receive {:handler, filename} assert_receive {:handler, filename}
assert String.ends_with?(filename, ".json") assert String.ends_with?(filename, ".json")
@@ -73,7 +73,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
}) })
end) end)
assert {:ok, res} = VideoCollection.get_source_details(@channel_url) assert {:ok, res} = MediaCollection.get_source_details(@channel_url)
assert %{ assert %{
channel_id: "UCQH2", channel_id: "UCQH2",
@@ -91,19 +91,19 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoCollectionTest do
{:ok, "{}"} {:ok, "{}"}
end) end)
assert {:ok, _} = VideoCollection.get_source_details(@channel_url) assert {:ok, _} = MediaCollection.get_source_details(@channel_url)
end end
test "it returns an error if the runner returns an error" do test "it returns an error if the runner returns an error" do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end) expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "Big issue", 1} end)
assert {:error, "Big issue", 1} = VideoCollection.get_source_details(@channel_url) assert {:error, "Big issue", 1} = MediaCollection.get_source_details(@channel_url)
end end
test "it returns an error if the output is not JSON" do test "it returns an error if the output is not JSON" do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "Not JSON"} end) expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "Not JSON"} end)
assert {:error, %Jason.DecodeError{}} = VideoCollection.get_source_details(@channel_url) assert {:error, %Jason.DecodeError{}} = MediaCollection.get_source_details(@channel_url)
end end
end end
end end
@@ -1,10 +1,10 @@
defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoTest do defmodule Pinchflat.MediaClient.Backends.YtDlp.MediaTest do
use Pinchflat.DataCase use Pinchflat.DataCase
import Mox import Mox
alias Pinchflat.MediaClient.Backends.YtDlp.Video alias Pinchflat.MediaClient.Backends.YtDlp.Media
@video_url "https://www.youtube.com/watch?v=TiZPUDkDYbk" @media_url "https://www.youtube.com/watch?v=TiZPUDkDYbk"
setup :verify_on_exit! setup :verify_on_exit!
@@ -16,14 +16,14 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoTest do
describe "download/2" do describe "download/2" do
test "it calls the backend runner with the expected arguments" do test "it calls the backend runner with the expected arguments" do
expect(YtDlpRunnerMock, :run, fn @video_url, opts, ot -> expect(YtDlpRunnerMock, :run, fn @media_url, opts, ot ->
assert [:no_simulate] = opts assert [:no_simulate] = opts
assert "after_move:%()j" = ot assert "after_move:%()j" = ot
{:ok, render_metadata(:media_metadata)} {:ok, render_metadata(:media_metadata)}
end) end)
assert {:ok, _} = Video.download(@video_url) assert {:ok, _} = Media.download(@media_url)
end end
test "it passes along additional options" do test "it passes along additional options" do
@@ -33,7 +33,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoTest do
{:ok, "{}"} {:ok, "{}"}
end) end)
assert {:ok, _} = Video.download(@video_url, [:custom_arg]) assert {:ok, _} = Media.download(@media_url, [:custom_arg])
end end
test "it parses and returns the generated file as JSON" do test "it parses and returns the generated file as JSON" do
@@ -42,7 +42,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoTest do
end) end)
assert {:ok, %{"title" => "Trying to Wheelie Without the Rear Brake"}} = assert {:ok, %{"title" => "Trying to Wheelie Without the Rear Brake"}} =
Video.download(@video_url) Media.download(@media_url)
end end
test "it returns errors" do test "it returns errors" do
@@ -50,7 +50,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.VideoTest do
{:error, "something"} {:error, "something"}
end) end)
assert {:error, "something"} = Video.download(@video_url) assert {:error, "something"} = Media.download(@media_url)
end end
end end
end end
@@ -23,7 +23,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.MediaParserTest do
end end
describe "parse_for_media_item/1 when testing media metadata" do describe "parse_for_media_item/1 when testing media metadata" do
test "it extracts the video filepath", %{metadata: metadata} do test "it extracts the media filepath", %{metadata: metadata} do
result = Parser.parse_for_media_item(metadata) result = Parser.parse_for_media_item(metadata)
assert String.contains?(result.media_filepath, "bwRHIkYqYJo") assert String.contains?(result.media_filepath, "bwRHIkYqYJo")
@@ -67,7 +67,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.MediaParserTest do
assert [["al", _], ["de", _], ["en", _], ["za", _]] = result.subtitle_filepaths assert [["al", _], ["de", _], ["en", _], ["za", _]] = result.subtitle_filepaths
end end
test "doesn't freak out if the video has no subtitles", %{metadata: metadata} do test "doesn't freak out if the media has no subtitles", %{metadata: metadata} do
metadata = Map.put(metadata, "requested_subtitles", %{}) metadata = Map.put(metadata, "requested_subtitles", %{})
result = Parser.parse_for_media_item(metadata) result = Parser.parse_for_media_item(metadata)
@@ -91,7 +91,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.MediaParserTest do
assert String.ends_with?(result.thumbnail_filepath, ".webp") assert String.ends_with?(result.thumbnail_filepath, ".webp")
end end
test "doesn't freak out if the video has no thumbnails", %{metadata: metadata} do test "doesn't freak out if the media has no thumbnails", %{metadata: metadata} do
metadata = Map.put(metadata, "thumbnails", %{}) metadata = Map.put(metadata, "thumbnails", %{})
result = Parser.parse_for_media_item(metadata) result = Parser.parse_for_media_item(metadata)
@@ -115,7 +115,7 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.MediaParserTest do
assert String.ends_with?(result.metadata_filepath, ".info.json") assert String.ends_with?(result.metadata_filepath, ".info.json")
end end
test "doesn't freak out if the video has no infojson", %{metadata: metadata} do test "doesn't freak out if the media has no infojson", %{metadata: metadata} do
metadata = Map.put(metadata, "infojson_filename", nil) metadata = Map.put(metadata, "infojson_filename", nil)
result = Parser.parse_for_media_item(metadata) result = Parser.parse_for_media_item(metadata)
@@ -1,9 +1,9 @@
defmodule Pinchflat.MediaClient.VideoDownloaderTest do defmodule Pinchflat.MediaClient.MediaDownloaderTest do
use Pinchflat.DataCase use Pinchflat.DataCase
import Mox import Mox
import Pinchflat.MediaFixtures import Pinchflat.MediaFixtures
alias Pinchflat.MediaClient.VideoDownloader alias Pinchflat.MediaClient.MediaDownloader
setup :verify_on_exit! setup :verify_on_exit!
@@ -30,7 +30,7 @@ defmodule Pinchflat.MediaClient.VideoDownloaderTest do
{:ok, render_metadata(:media_metadata)} {:ok, render_metadata(:media_metadata)}
end) end)
assert {:ok, _} = VideoDownloader.download_for_media_item(media_item) assert {:ok, _} = MediaDownloader.download_for_media_item(media_item)
end end
test "it saves the metadata filepatha to the database", %{media_item: media_item} do test "it saves the metadata filepatha to the database", %{media_item: media_item} do
@@ -39,7 +39,7 @@ defmodule Pinchflat.MediaClient.VideoDownloaderTest do
end) end)
assert is_nil(media_item.metadata) assert is_nil(media_item.metadata)
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item) assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert updated_media_item.metadata.metadata_filepath =~ "media_items/#{media_item.id}/metadata.json.gz" assert updated_media_item.metadata.metadata_filepath =~ "media_items/#{media_item.id}/metadata.json.gz"
assert updated_media_item.metadata.thumbnail_filepath =~ "media_items/#{media_item.id}/maxresdefault.jpg" assert updated_media_item.metadata.thumbnail_filepath =~ "media_items/#{media_item.id}/maxresdefault.jpg"
@@ -50,7 +50,7 @@ defmodule Pinchflat.MediaClient.VideoDownloaderTest do
{:error, :some_error} {:error, :some_error}
end) end)
assert {:error, :some_error} = VideoDownloader.download_for_media_item(media_item) assert {:error, :some_error} = MediaDownloader.download_for_media_item(media_item)
end end
end end
@@ -65,41 +65,41 @@ defmodule Pinchflat.MediaClient.VideoDownloaderTest do
test "it sets the media_downloaded_at", %{media_item: media_item} do test "it sets the media_downloaded_at", %{media_item: media_item} do
assert media_item.media_downloaded_at == nil assert media_item.media_downloaded_at == nil
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item) 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 assert DateTime.diff(DateTime.utc_now(), updated_media_item.media_downloaded_at) < 2
end end
test "it extracts the title", %{media_item: media_item} do test "it extracts the title", %{media_item: media_item} do
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item) assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert updated_media_item.title == "Trying to Wheelie Without the Rear Brake" assert updated_media_item.title == "Trying to Wheelie Without the Rear Brake"
end end
test "it extracts the description", %{media_item: media_item} do test "it extracts the description", %{media_item: media_item} do
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item) assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert is_binary(updated_media_item.description) assert is_binary(updated_media_item.description)
end end
test "it extracts the media_filepath", %{media_item: media_item} do test "it extracts the media_filepath", %{media_item: media_item} do
assert media_item.media_filepath == nil assert media_item.media_filepath == nil
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item) assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert String.ends_with?(updated_media_item.media_filepath, ".mkv") assert String.ends_with?(updated_media_item.media_filepath, ".mkv")
end end
test "it extracts the subtitle_filepaths", %{media_item: media_item} do test "it extracts the subtitle_filepaths", %{media_item: media_item} do
assert media_item.subtitle_filepaths == [] assert media_item.subtitle_filepaths == []
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item) assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert [["de", _], ["en", _] | _rest] = updated_media_item.subtitle_filepaths assert [["de", _], ["en", _] | _rest] = updated_media_item.subtitle_filepaths
end end
test "it extracts the thumbnail_filepath", %{media_item: media_item} do test "it extracts the thumbnail_filepath", %{media_item: media_item} do
assert media_item.thumbnail_filepath == nil assert media_item.thumbnail_filepath == nil
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item) assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert String.ends_with?(updated_media_item.thumbnail_filepath, ".webp") assert String.ends_with?(updated_media_item.thumbnail_filepath, ".webp")
end end
test "it extracts the metadata_filepath", %{media_item: media_item} do test "it extracts the metadata_filepath", %{media_item: media_item} do
assert media_item.metadata_filepath == nil assert media_item.metadata_filepath == nil
assert {:ok, updated_media_item} = VideoDownloader.download_for_media_item(media_item) assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
assert String.ends_with?(updated_media_item.metadata_filepath, ".info.json") assert String.ends_with?(updated_media_item.metadata_filepath, ".info.json")
end end
end end
@@ -19,7 +19,7 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilderTest do
test "it generates an expanded output path based on the given template", %{media_item: media_item} 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 {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:output, "/tmp/test/videos/%(title)S.%(ext)s"} in res assert {:output, "/tmp/test/media/%(title)S.%(ext)s"} in res
end end
test "it respects custom output path options", %{media_item: media_item} do test "it respects custom output path options", %{media_item: media_item} do
@@ -28,7 +28,7 @@ defmodule Pinchflat.Profiles.Options.YtDlp.DownloadOptionBuilderTest do
assert {:ok, res} = DownloadOptionBuilder.build(media_item) assert {:ok, res} = DownloadOptionBuilder.build(media_item)
assert {:output, "/tmp/test/videos/#{media_item.source.custom_name}.%(ext)s"} in res assert {:output, "/tmp/test/media/#{media_item.source.custom_name}.%(ext)s"} in res
end end
end end
+5 -5
View File
@@ -10,7 +10,7 @@ defmodule Pinchflat.SourcesTest do
alias Pinchflat.Tasks.SourceTasks alias Pinchflat.Tasks.SourceTasks
alias Pinchflat.Sources.Source alias Pinchflat.Sources.Source
alias Pinchflat.Workers.MediaIndexingWorker alias Pinchflat.Workers.MediaIndexingWorker
alias Pinchflat.Workers.VideoDownloadWorker alias Pinchflat.Workers.MediaDownloadWorker
@invalid_source_attrs %{name: nil, collection_id: nil} @invalid_source_attrs %{name: nil, collection_id: nil}
@@ -269,9 +269,9 @@ defmodule Pinchflat.SourcesTest do
media_item = media_item_fixture(source_id: source.id, media_filepath: nil) media_item = media_item_fixture(source_id: source.id, media_filepath: nil)
update_attrs = %{download_media: true} update_attrs = %{download_media: true}
refute_enqueued(worker: VideoDownloadWorker) refute_enqueued(worker: MediaDownloadWorker)
assert {:ok, %Source{}} = Sources.update_source(source, update_attrs) assert {:ok, %Source{}} = Sources.update_source(source, update_attrs)
assert_enqueued(worker: VideoDownloadWorker, args: %{"id" => media_item.id}) assert_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id})
end end
test "disabling the download_media attribute will cancel the download task" do test "disabling the download_media attribute will cancel the download task" do
@@ -280,9 +280,9 @@ defmodule Pinchflat.SourcesTest do
update_attrs = %{download_media: false} update_attrs = %{download_media: false}
SourceTasks.enqueue_pending_media_tasks(source) SourceTasks.enqueue_pending_media_tasks(source)
assert_enqueued(worker: VideoDownloadWorker, args: %{"id" => media_item.id}) assert_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id})
assert {:ok, %Source{}} = Sources.update_source(source, update_attrs) assert {:ok, %Source{}} = Sources.update_source(source, update_attrs)
refute_enqueued(worker: VideoDownloadWorker) refute_enqueued(worker: MediaDownloadWorker)
end end
test "updates with invalid data returns error changeset" do test "updates with invalid data returns error changeset" do
+30 -11
View File
@@ -12,7 +12,7 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
alias Pinchflat.Tasks.SourceTasks alias Pinchflat.Tasks.SourceTasks
alias Pinchflat.Media.MediaItem alias Pinchflat.Media.MediaItem
alias Pinchflat.Workers.MediaIndexingWorker alias Pinchflat.Workers.MediaIndexingWorker
alias Pinchflat.Workers.VideoDownloadWorker alias Pinchflat.Workers.MediaDownloadWorker
setup :verify_on_exit! setup :verify_on_exit!
@@ -116,7 +116,7 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
SourceTasks.index_and_enqueue_download_for_media_items(source) SourceTasks.index_and_enqueue_download_for_media_items(source)
assert_enqueued(worker: VideoDownloadWorker, args: %{"id" => media_item.id}) assert_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id})
end end
test "it does not attach tasks if the source is set to not download" do test "it does not attach tasks if the source is set to not download" do
@@ -167,9 +167,9 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
{:ok, ""} {:ok, ""}
end) end)
refute_enqueued(worker: VideoDownloadWorker) refute_enqueued(worker: MediaDownloadWorker)
SourceTasks.index_and_enqueue_download_for_media_items(source) SourceTasks.index_and_enqueue_download_for_media_items(source)
assert_enqueued(worker: VideoDownloadWorker) assert_enqueued(worker: MediaDownloadWorker)
end end
test "does not enqueue downloads if the source is set to not download" do test "does not enqueue downloads if the source is set to not download" do
@@ -188,7 +188,7 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
end) end)
SourceTasks.index_and_enqueue_download_for_media_items(source) SourceTasks.index_and_enqueue_download_for_media_items(source)
refute_enqueued(worker: VideoDownloadWorker) refute_enqueued(worker: MediaDownloadWorker)
end end
test "does not enqueue downloads for media that doesn't match the profile's format options" do test "does not enqueue downloads for media that doesn't match the profile's format options" do
@@ -218,7 +218,26 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
end) end)
SourceTasks.index_and_enqueue_download_for_media_items(source) SourceTasks.index_and_enqueue_download_for_media_items(source)
refute_enqueued(worker: VideoDownloadWorker) refute_enqueued(worker: MediaDownloadWorker)
end
test "does not enqueue multiple download jobs for the same media items", %{source: source} do
watcher_poll_interval = Application.get_env(:pinchflat, :file_watcher_poll_interval)
stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot, addl_opts ->
filepath = Keyword.get(addl_opts, :output_filepath)
File.write(filepath, source_attributes_return_fixture())
# Need to add a delay to ensure the file watcher has time to read the file
:timer.sleep(watcher_poll_interval * 2)
# This also returns the final result to the yt-dlp call (like the real usage actually would do)
# so it'll attempt to create the media items and enqueue the download jobs based on this as well
{:ok, source_attributes_return_fixture()}
end)
SourceTasks.index_and_enqueue_download_for_media_items(source)
assert Repo.aggregate(MediaItem, :count, :id) == 3
assert [_, _, _] = all_enqueued(worker: MediaDownloadWorker)
end end
end end
@@ -229,7 +248,7 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
assert :ok = SourceTasks.enqueue_pending_media_tasks(source) assert :ok = SourceTasks.enqueue_pending_media_tasks(source)
assert_enqueued(worker: VideoDownloadWorker, args: %{"id" => media_item.id}) assert_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id})
end end
test "it does not enqueue a job for media items with a filepath" do test "it does not enqueue a job for media items with a filepath" do
@@ -238,7 +257,7 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
assert :ok = SourceTasks.enqueue_pending_media_tasks(source) assert :ok = SourceTasks.enqueue_pending_media_tasks(source)
refute_enqueued(worker: VideoDownloadWorker) refute_enqueued(worker: MediaDownloadWorker)
end end
test "it attaches a task to each enqueued job" do test "it attaches a task to each enqueued job" do
@@ -257,7 +276,7 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
assert :ok = SourceTasks.enqueue_pending_media_tasks(source) assert :ok = SourceTasks.enqueue_pending_media_tasks(source)
refute_enqueued(worker: VideoDownloadWorker) refute_enqueued(worker: MediaDownloadWorker)
end end
test "it does not attach tasks if the source is set to not download" do test "it does not attach tasks if the source is set to not download" do
@@ -275,11 +294,11 @@ defmodule Pinchflat.Tasks.SourceTasksTest do
media_item = media_item_fixture(source_id: source.id, media_filepath: nil) media_item = media_item_fixture(source_id: source.id, media_filepath: nil)
SourceTasks.enqueue_pending_media_tasks(source) SourceTasks.enqueue_pending_media_tasks(source)
assert_enqueued(worker: VideoDownloadWorker, args: %{"id" => media_item.id}) assert_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id})
assert :ok = SourceTasks.dequeue_pending_media_tasks(source) assert :ok = SourceTasks.dequeue_pending_media_tasks(source)
refute_enqueued(worker: VideoDownloadWorker) refute_enqueued(worker: MediaDownloadWorker)
assert [] = Tasks.list_tasks_for(:media_item_id, media_item.id) assert [] = Tasks.list_tasks_for(:media_item_id, media_item.id)
end end
end end
@@ -1,11 +1,11 @@
defmodule Pinchflat.Workers.VideoDownloadWorkerTest do defmodule Pinchflat.Workers.MediaDownloadWorkerTest do
use Pinchflat.DataCase use Pinchflat.DataCase
import Mox import Mox
import Pinchflat.MediaFixtures import Pinchflat.MediaFixtures
alias Pinchflat.Sources alias Pinchflat.Sources
alias Pinchflat.Workers.VideoDownloadWorker alias Pinchflat.Workers.MediaDownloadWorker
alias Pinchflat.Workers.FilesystemDataWorker alias Pinchflat.Workers.FilesystemDataWorker
setup :verify_on_exit! setup :verify_on_exit!
@@ -31,7 +31,7 @@ defmodule Pinchflat.Workers.VideoDownloadWorkerTest do
end) end)
assert media_item.media_filepath == nil assert media_item.media_filepath == nil
perform_job(VideoDownloadWorker, %{id: media_item.id}) perform_job(MediaDownloadWorker, %{id: media_item.id})
assert Repo.reload(media_item).media_filepath != nil assert Repo.reload(media_item).media_filepath != nil
end end
@@ -41,22 +41,22 @@ defmodule Pinchflat.Workers.VideoDownloadWorkerTest do
end) end)
assert media_item.metadata == nil assert media_item.metadata == nil
perform_job(VideoDownloadWorker, %{id: media_item.id}) perform_job(MediaDownloadWorker, %{id: media_item.id})
assert Repo.reload(media_item).metadata != nil assert Repo.reload(media_item).metadata != nil
end end
test "it won't double-schedule downloading jobs", %{media_item: media_item} do test "it won't double-schedule downloading jobs", %{media_item: media_item} do
Oban.insert(VideoDownloadWorker.new(%{id: media_item.id})) Oban.insert(MediaDownloadWorker.new(%{id: media_item.id}))
Oban.insert(VideoDownloadWorker.new(%{id: media_item.id})) Oban.insert(MediaDownloadWorker.new(%{id: media_item.id}))
assert [_] = all_enqueued(worker: VideoDownloadWorker) assert [_] = all_enqueued(worker: MediaDownloadWorker)
end end
test "it sets the job to retryable if the download fails", %{media_item: media_item} do test "it sets the job to retryable if the download fails", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "error"} end) expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:error, "error"} end)
Oban.Testing.with_testing_mode(:inline, fn -> Oban.Testing.with_testing_mode(:inline, fn ->
{:ok, job} = Oban.insert(VideoDownloadWorker.new(%{id: media_item.id})) {:ok, job} = Oban.insert(MediaDownloadWorker.new(%{id: media_item.id}))
assert job.state == "retryable" assert job.state == "retryable"
end) end)
@@ -67,7 +67,7 @@ defmodule Pinchflat.Workers.VideoDownloadWorkerTest do
Sources.update_source(media_item.source, %{download_media: false}) Sources.update_source(media_item.source, %{download_media: false})
perform_job(VideoDownloadWorker, %{id: media_item.id}) perform_job(MediaDownloadWorker, %{id: media_item.id})
end end
test "it schedules a filesystem data worker", %{media_item: media_item} do test "it schedules a filesystem data worker", %{media_item: media_item} do
@@ -77,7 +77,7 @@ defmodule Pinchflat.Workers.VideoDownloadWorkerTest do
assert [] = all_enqueued(worker: FilesystemDataWorker) assert [] = all_enqueued(worker: FilesystemDataWorker)
perform_job(VideoDownloadWorker, %{id: media_item.id}) perform_job(MediaDownloadWorker, %{id: media_item.id})
assert [_] = all_enqueued(worker: FilesystemDataWorker) assert [_] = all_enqueued(worker: FilesystemDataWorker)
end end
@@ -7,7 +7,7 @@ defmodule Pinchflat.Workers.MediaIndexingWorkerTest do
alias Pinchflat.Tasks alias Pinchflat.Tasks
alias Pinchflat.Workers.MediaIndexingWorker alias Pinchflat.Workers.MediaIndexingWorker
alias Pinchflat.Workers.VideoDownloadWorker alias Pinchflat.Workers.MediaDownloadWorker
setup :verify_on_exit! setup :verify_on_exit!
@@ -53,7 +53,7 @@ defmodule Pinchflat.Workers.MediaIndexingWorkerTest do
source = source_fixture(index_frequency_minutes: 10) source = source_fixture(index_frequency_minutes: 10)
perform_job(MediaIndexingWorker, %{id: source.id}) perform_job(MediaIndexingWorker, %{id: source.id})
assert length(all_enqueued(worker: VideoDownloadWorker)) == 3 assert length(all_enqueued(worker: MediaDownloadWorker)) == 3
end end
test "it starts a job for any pending media item even if it's from another run" do test "it starts a job for any pending media item even if it's from another run" do
@@ -65,7 +65,7 @@ defmodule Pinchflat.Workers.MediaIndexingWorkerTest do
media_item_fixture(%{source_id: source.id, media_filepath: nil}) media_item_fixture(%{source_id: source.id, media_filepath: nil})
perform_job(MediaIndexingWorker, %{id: source.id}) perform_job(MediaIndexingWorker, %{id: source.id})
assert length(all_enqueued(worker: VideoDownloadWorker)) == 4 assert length(all_enqueued(worker: MediaDownloadWorker)) == 4
end end
test "it does not kick off a job for media items that could not be saved" do test "it does not kick off a job for media items that could not be saved" do
@@ -78,7 +78,7 @@ defmodule Pinchflat.Workers.MediaIndexingWorkerTest do
perform_job(MediaIndexingWorker, %{id: source.id}) perform_job(MediaIndexingWorker, %{id: source.id})
# Only 3 jobs should be enqueued, since the first video is a duplicate # Only 3 jobs should be enqueued, since the first video is a duplicate
assert length(all_enqueued(worker: VideoDownloadWorker)) assert length(all_enqueued(worker: MediaDownloadWorker))
end end
test "it reschedules the job based on the index frequency" do test "it reschedules the job based on the index frequency" do