Source NFO downloads (#95)
* Hooked up series directory finding to source metadata runner * Fixed aired NFO tag for episodes * Updated MI NFO builder to take in a filepath * Hooked up NFO generation to the source worker * Added NFO controls to form * Improved the way the source metadata worker updates the source * Consolidated NFO selection options in media profile instead of source
This commit is contained in:
@@ -92,4 +92,52 @@ defmodule Pinchflat.Metadata.MetadataFileHelpersTest do
|
||||
assert Helpers.parse_upload_date(upload_date) == ~D[2021-01-01]
|
||||
end
|
||||
end
|
||||
|
||||
describe "series_directory_from_media_filepath/1" do
|
||||
test "returns base series directory if filepaths are setup as expected" do
|
||||
good_filepaths = [
|
||||
"/media/season1/episode.mp4",
|
||||
"/media/season 1/episode.mp4",
|
||||
"/media/season.1/episode.mp4",
|
||||
"/media/season_1/episode.mp4",
|
||||
"/media/season-1/episode.mp4",
|
||||
"/media/SEASON 1/episode.mp4",
|
||||
"/media/SEASON.1/episode.mp4",
|
||||
"/media/s1/episode.mp4",
|
||||
"/media/s.1/episode.mp4",
|
||||
"/media/s_1/episode.mp4",
|
||||
"/media/s-1/episode.mp4",
|
||||
"/media/s 1/episode.mp4",
|
||||
"/media/S1/episode.mp4",
|
||||
"/media/S.1/episode.mp4"
|
||||
]
|
||||
|
||||
for filepath <- good_filepaths do
|
||||
assert {:ok, "/media"} = Helpers.series_directory_from_media_filepath(filepath)
|
||||
end
|
||||
end
|
||||
|
||||
test "returns an error if the season filepath can't be determined" do
|
||||
bad_filepaths = [
|
||||
"/media/1/episode.mp4",
|
||||
"/media/(s1)/episode.mp4",
|
||||
"/media/episode.mp4",
|
||||
"/media/s1e1/episode.mp4",
|
||||
"/media/s1 e1/episode.mp4",
|
||||
"/media/s1 (something else)/episode.mp4",
|
||||
"/media/season1e1/episode.mp4",
|
||||
"/media/season1 e1/episode.mp4",
|
||||
"/media/seasoning1/episode.mp4",
|
||||
"/media/season/episode.mp4",
|
||||
"/media/series1/episode.mp4",
|
||||
"/media/s/episode.mp4",
|
||||
"/media/foo",
|
||||
"/media/bar/"
|
||||
]
|
||||
|
||||
for filepath <- bad_filepaths do
|
||||
assert {:error, :indeterminable} = Helpers.series_directory_from_media_filepath(filepath)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,37 +2,49 @@ defmodule Pinchflat.Metadata.NfoBuilderTest do
|
||||
use Pinchflat.DataCase
|
||||
|
||||
alias Pinchflat.Metadata.NfoBuilder
|
||||
alias Pinchflat.Filesystem.FilesystemHelpers
|
||||
|
||||
setup do
|
||||
{:ok, %{metadata: render_parsed_metadata(:media_metadata)}}
|
||||
filepath = FilesystemHelpers.generate_metadata_tmpfile(:json)
|
||||
|
||||
on_exit(fn -> File.rm!(filepath) end)
|
||||
|
||||
{:ok,
|
||||
%{
|
||||
metadata: render_parsed_metadata(:media_metadata),
|
||||
filepath: filepath
|
||||
}}
|
||||
end
|
||||
|
||||
describe "build_and_store_for_media_item/1" do
|
||||
test "returns the filepath", %{metadata: metadata} do
|
||||
result = NfoBuilder.build_and_store_for_media_item(metadata)
|
||||
describe "build_and_store_for_media_item/2" do
|
||||
test "returns the filepath", %{metadata: metadata, filepath: filepath} do
|
||||
result = NfoBuilder.build_and_store_for_media_item(filepath, metadata)
|
||||
|
||||
assert File.exists?(result)
|
||||
|
||||
File.rm!(result)
|
||||
end
|
||||
|
||||
test "builds filepath based on media location", %{metadata: metadata} do
|
||||
result = NfoBuilder.build_and_store_for_media_item(metadata)
|
||||
|
||||
assert String.contains?(result, Path.rootname(metadata["filepath"]))
|
||||
assert String.ends_with?(result, ".nfo")
|
||||
|
||||
File.rm!(result)
|
||||
end
|
||||
|
||||
test "builds an NFO file", %{metadata: metadata} do
|
||||
result = NfoBuilder.build_and_store_for_media_item(metadata)
|
||||
test "builds an NFO file", %{metadata: metadata, filepath: filepath} do
|
||||
result = NfoBuilder.build_and_store_for_media_item(filepath, metadata)
|
||||
nfo = File.read!(result)
|
||||
|
||||
assert String.contains?(nfo, ~S(<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>))
|
||||
assert String.contains?(nfo, "<title>#{metadata["title"]}</title>")
|
||||
end
|
||||
end
|
||||
|
||||
File.rm!(result)
|
||||
describe "build_and_store_for_source/2" do
|
||||
test "returns the filepath", %{metadata: metadata, filepath: filepath} do
|
||||
result = NfoBuilder.build_and_store_for_source(filepath, metadata)
|
||||
|
||||
assert File.exists?(result)
|
||||
end
|
||||
|
||||
test "builds an NFO file", %{metadata: metadata, filepath: filepath} do
|
||||
result = NfoBuilder.build_and_store_for_source(filepath, metadata)
|
||||
nfo = File.read!(result)
|
||||
|
||||
assert String.contains?(nfo, ~S(<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>))
|
||||
assert String.contains?(nfo, "<title>#{metadata["title"]}</title>")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,10 +2,14 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do
|
||||
use Pinchflat.DataCase
|
||||
import Mox
|
||||
import Pinchflat.SourcesFixtures
|
||||
import Pinchflat.ProfilesFixtures
|
||||
|
||||
alias Pinchflat.Metadata.MetadataFileHelpers
|
||||
alias Pinchflat.Metadata.SourceMetadataStorageWorker
|
||||
|
||||
@source_details_ot "%(.{channel,channel_id,playlist_id,playlist_title,filename})j"
|
||||
@metadata_ot "playlist:%()j"
|
||||
|
||||
setup :verify_on_exit!
|
||||
|
||||
describe "kickoff_with_task/1" do
|
||||
@@ -27,8 +31,31 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do
|
||||
end
|
||||
|
||||
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, "{}"}
|
||||
end)
|
||||
|
||||
source = source_fixture()
|
||||
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source.id})
|
||||
|
||||
assert [] = all_enqueued(worker: SourceMetadataStorageWorker)
|
||||
end
|
||||
|
||||
test "does not blow up if the record doesn't exist" do
|
||||
assert :ok = perform_job(SourceMetadataStorageWorker, %{id: 0})
|
||||
end
|
||||
end
|
||||
|
||||
describe "perform/1 when testing metadata storage" do
|
||||
test "sets metadata location for source" do
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "{}"} end)
|
||||
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, "{}"}
|
||||
end)
|
||||
|
||||
source = Repo.preload(source_fixture(), :metadata)
|
||||
|
||||
refute source.metadata
|
||||
@@ -43,7 +70,11 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do
|
||||
test "fetches and stores returned metadata for source" do
|
||||
source = source_fixture()
|
||||
file_contents = Phoenix.json_library().encode!(%{"title" => "test"})
|
||||
expect(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, file_contents} end)
|
||||
|
||||
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}
|
||||
end)
|
||||
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source.id})
|
||||
source = Repo.preload(Repo.reload(source), :metadata)
|
||||
@@ -51,32 +82,106 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do
|
||||
|
||||
assert metadata == %{"title" => "test"}
|
||||
end
|
||||
end
|
||||
|
||||
test "won't call itself in an infinite loop" do
|
||||
stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "{}"} end)
|
||||
source = source_fixture()
|
||||
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 ->
|
||||
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, "{}"}
|
||||
end)
|
||||
|
||||
source = source_fixture(%{series_directory: nil})
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source.id})
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source.id})
|
||||
source = Repo.reload(source)
|
||||
|
||||
assert [_] = all_enqueued(worker: SourceMetadataStorageWorker)
|
||||
assert source.series_directory
|
||||
end
|
||||
|
||||
test "doesn't prevent over source jobs from running" do
|
||||
stub(YtDlpRunnerMock, :run, fn _url, _opts, _ot -> {:ok, "{}"} end)
|
||||
source_1 = source_fixture()
|
||||
source_2 = source_fixture()
|
||||
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 ->
|
||||
filename = Path.join([Application.get_env(:pinchflat, :media_directory), "foo", "bar.mp4"])
|
||||
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source_1.id})
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source_1.id})
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source_2.id})
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source_2.id})
|
||||
{:ok, source_details_return_fixture(%{filename: filename})}
|
||||
|
||||
assert [_, _] = all_enqueued(worker: SourceMetadataStorageWorker)
|
||||
_url, _opts, ot when ot == @metadata_ot ->
|
||||
{:ok, "{}"}
|
||||
end)
|
||||
|
||||
source = source_fixture(%{series_directory: nil})
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source.id})
|
||||
source = Repo.reload(source)
|
||||
|
||||
refute source.series_directory
|
||||
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 ->
|
||||
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, "{}"}
|
||||
end)
|
||||
|
||||
profile = media_profile_fixture(%{download_nfo: true})
|
||||
source = source_fixture(%{nfo_filepath: nil, media_profile_id: profile.id})
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source.id})
|
||||
source = Repo.reload(source)
|
||||
|
||||
assert source.nfo_filepath
|
||||
assert source.nfo_filepath == Path.join([source.series_directory, "tvshow.nfo"])
|
||||
assert File.exists?(source.nfo_filepath)
|
||||
|
||||
File.rm!(source.nfo_filepath)
|
||||
end
|
||||
|
||||
test "does not blow up if the record doesn't exist" do
|
||||
assert :ok = perform_job(SourceMetadataStorageWorker, %{id: 0})
|
||||
test "does not store the NFO if not specified" 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, "{}"}
|
||||
end)
|
||||
|
||||
profile = media_profile_fixture(%{download_nfo: false})
|
||||
source = source_fixture(%{nfo_filepath: nil, media_profile_id: profile.id})
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source.id})
|
||||
source = Repo.reload(source)
|
||||
|
||||
refute source.nfo_filepath
|
||||
end
|
||||
|
||||
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 ->
|
||||
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, "{}"}
|
||||
end)
|
||||
|
||||
profile = media_profile_fixture(%{download_nfo: true})
|
||||
source = source_fixture(%{nfo_filepath: nil, media_profile_id: profile.id})
|
||||
perform_job(SourceMetadataStorageWorker, %{id: source.id})
|
||||
source = Repo.reload(source)
|
||||
|
||||
refute source.nfo_filepath
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user