[Enhancement] Added ability to detect when files have been deleted (#399)
* Added function for updating a media item's filepaths on-disk * Added placeholder action to source page * Turned the file sync into a job and properly hooked it up to the controller
This commit is contained in:
@@ -1,77 +0,0 @@
|
||||
defmodule Pinchflat.Media.FileDeletionTest do
|
||||
use Pinchflat.DataCase
|
||||
|
||||
import Pinchflat.MediaFixtures
|
||||
|
||||
alias Pinchflat.Media.FileDeletion
|
||||
|
||||
describe "delete_outdated_files/2" do
|
||||
test "deletes outdated non-subtitle files" do
|
||||
new_media_item = media_item_with_attachments()
|
||||
old_media_item = media_item_with_attachments()
|
||||
|
||||
assert :ok = FileDeletion.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(new_media_item.media_filepath)
|
||||
refute File.exists?(old_media_item.media_filepath)
|
||||
end
|
||||
|
||||
test "doesn't delete non-subtitle files if the new file is the same" do
|
||||
new_media_item = media_item_with_attachments()
|
||||
old_media_item = media_item_fixture(%{media_filepath: new_media_item.media_filepath})
|
||||
|
||||
assert :ok = FileDeletion.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(new_media_item.media_filepath)
|
||||
assert File.exists?(old_media_item.media_filepath)
|
||||
end
|
||||
|
||||
test "doesn't delete the old file if the new file is missing that key" do
|
||||
new_media_item = media_item_fixture(%{media_filepath: nil})
|
||||
old_media_item = media_item_with_attachments()
|
||||
|
||||
assert :ok = FileDeletion.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(old_media_item.media_filepath)
|
||||
end
|
||||
|
||||
test "deletes outdated subtitle files" do
|
||||
new_media_item = media_item_with_attachments()
|
||||
old_media_item = media_item_with_attachments()
|
||||
|
||||
assert :ok = FileDeletion.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(get_subtitle_filepath(new_media_item, "en"))
|
||||
refute File.exists?(get_subtitle_filepath(old_media_item, "en"))
|
||||
end
|
||||
|
||||
test "keeps old subtitle files if the new file is the same" do
|
||||
new_media_item = media_item_with_attachments()
|
||||
old_media_item = media_item_fixture(%{subtitle_filepaths: new_media_item.subtitle_filepaths})
|
||||
|
||||
assert :ok = FileDeletion.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(get_subtitle_filepath(new_media_item, "en"))
|
||||
assert File.exists?(get_subtitle_filepath(old_media_item, "en"))
|
||||
end
|
||||
|
||||
test "doesn't delete old subtitle files if the new file is missing that key" do
|
||||
new_media_item = media_item_fixture(%{subtitle_filepaths: []})
|
||||
old_media_item = media_item_with_attachments()
|
||||
|
||||
assert :ok = FileDeletion.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(get_subtitle_filepath(old_media_item, "en"))
|
||||
end
|
||||
end
|
||||
|
||||
defp get_subtitle_filepath(media_item, language) do
|
||||
Enum.reduce_while(media_item.subtitle_filepaths, nil, fn [lang, filepath], acc ->
|
||||
if lang == language do
|
||||
{:halt, filepath}
|
||||
else
|
||||
{:cont, acc}
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,122 @@
|
||||
defmodule Pinchflat.Media.FileSyncingTest do
|
||||
use Pinchflat.DataCase
|
||||
|
||||
import Pinchflat.MediaFixtures
|
||||
|
||||
alias Pinchflat.Media.FileSyncing
|
||||
|
||||
describe "delete_outdated_files/2" do
|
||||
test "deletes outdated non-subtitle files" do
|
||||
new_media_item = media_item_with_attachments()
|
||||
old_media_item = media_item_with_attachments()
|
||||
|
||||
assert :ok = FileSyncing.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(new_media_item.media_filepath)
|
||||
refute File.exists?(old_media_item.media_filepath)
|
||||
end
|
||||
|
||||
test "doesn't delete non-subtitle files if the new file is the same" do
|
||||
new_media_item = media_item_with_attachments()
|
||||
old_media_item = media_item_fixture(%{media_filepath: new_media_item.media_filepath})
|
||||
|
||||
assert :ok = FileSyncing.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(new_media_item.media_filepath)
|
||||
assert File.exists?(old_media_item.media_filepath)
|
||||
end
|
||||
|
||||
test "doesn't delete the old file if the new file is missing that key" do
|
||||
new_media_item = media_item_fixture(%{media_filepath: nil})
|
||||
old_media_item = media_item_with_attachments()
|
||||
|
||||
assert :ok = FileSyncing.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(old_media_item.media_filepath)
|
||||
end
|
||||
|
||||
test "deletes outdated subtitle files" do
|
||||
new_media_item = media_item_with_attachments()
|
||||
old_media_item = media_item_with_attachments()
|
||||
|
||||
assert :ok = FileSyncing.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(get_subtitle_filepath(new_media_item, "en"))
|
||||
refute File.exists?(get_subtitle_filepath(old_media_item, "en"))
|
||||
end
|
||||
|
||||
test "keeps old subtitle files if the new file is the same" do
|
||||
new_media_item = media_item_with_attachments()
|
||||
old_media_item = media_item_fixture(%{subtitle_filepaths: new_media_item.subtitle_filepaths})
|
||||
|
||||
assert :ok = FileSyncing.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(get_subtitle_filepath(new_media_item, "en"))
|
||||
assert File.exists?(get_subtitle_filepath(old_media_item, "en"))
|
||||
end
|
||||
|
||||
test "doesn't delete old subtitle files if the new file is missing that key" do
|
||||
new_media_item = media_item_fixture(%{subtitle_filepaths: []})
|
||||
old_media_item = media_item_with_attachments()
|
||||
|
||||
assert :ok = FileSyncing.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(get_subtitle_filepath(old_media_item, "en"))
|
||||
end
|
||||
end
|
||||
|
||||
describe "sync_file_presence_on_disk/1" do
|
||||
test "removes attributes whose files are missing" do
|
||||
media_item = media_item_fixture(%{media_filepath: "/tmp/missing_file.mp4"})
|
||||
|
||||
assert media_item.media_filepath
|
||||
assert [updated_media_item] = FileSyncing.sync_file_presence_on_disk([media_item])
|
||||
refute updated_media_item.media_filepath
|
||||
end
|
||||
|
||||
test "doesn't remove attributes where the files still exist" do
|
||||
media_item = media_item_with_attachments()
|
||||
|
||||
assert media_item.media_filepath
|
||||
assert [updated_media_item] = FileSyncing.sync_file_presence_on_disk([media_item])
|
||||
assert updated_media_item.media_filepath
|
||||
end
|
||||
|
||||
test "doesn't touch other attributes if some are missing and some aren't" do
|
||||
media_item = media_item_with_attachments()
|
||||
File.rm(media_item.media_filepath)
|
||||
|
||||
assert media_item.thumbnail_filepath
|
||||
assert media_item.media_filepath
|
||||
assert [updated_media_item] = FileSyncing.sync_file_presence_on_disk([media_item])
|
||||
assert updated_media_item.thumbnail_filepath
|
||||
refute updated_media_item.media_filepath
|
||||
end
|
||||
|
||||
test "removes subtitle files that are missing" do
|
||||
media_item = media_item_fixture(%{subtitle_filepaths: [["en", "/tmp/missing_file.srt"]]})
|
||||
|
||||
assert get_subtitle_filepath(media_item, "en")
|
||||
assert [updated_media_item] = FileSyncing.sync_file_presence_on_disk([media_item])
|
||||
refute get_subtitle_filepath(updated_media_item, "en")
|
||||
end
|
||||
|
||||
test "doesn't remove subtitle files that still exist" do
|
||||
media_item = media_item_with_attachments()
|
||||
|
||||
assert get_subtitle_filepath(media_item, "en")
|
||||
assert [updated_media_item] = FileSyncing.sync_file_presence_on_disk([media_item])
|
||||
assert get_subtitle_filepath(updated_media_item, "en")
|
||||
end
|
||||
end
|
||||
|
||||
defp get_subtitle_filepath(media_item, language) do
|
||||
Enum.reduce_while(media_item.subtitle_filepaths, nil, fn [lang, filepath], acc ->
|
||||
if lang == language do
|
||||
{:halt, filepath}
|
||||
else
|
||||
{:cont, acc}
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
defmodule Pinchflat.Media.FileSyncingWorkerTest do
|
||||
use Pinchflat.DataCase
|
||||
|
||||
import Pinchflat.MediaFixtures
|
||||
import Pinchflat.SourcesFixtures
|
||||
|
||||
alias Pinchflat.Media.FileSyncingWorker
|
||||
|
||||
describe "kickoff_with_task/3" do
|
||||
test "starts the worker" do
|
||||
source = source_fixture()
|
||||
|
||||
assert [] = all_enqueued(worker: FileSyncingWorker)
|
||||
assert {:ok, _} = FileSyncingWorker.kickoff_with_task(source)
|
||||
assert [_] = all_enqueued(worker: FileSyncingWorker)
|
||||
end
|
||||
|
||||
test "attaches a task" do
|
||||
source = source_fixture()
|
||||
|
||||
assert {:ok, task} = FileSyncingWorker.kickoff_with_task(source)
|
||||
assert task.source_id == source.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "perform/1" do
|
||||
test "syncs file presence on disk" do
|
||||
source = source_fixture()
|
||||
media_item = media_item_fixture(%{media_filepath: "/tmp/missing.mp4", source_id: source.id})
|
||||
|
||||
perform_job(FileSyncingWorker, %{"id" => source.id})
|
||||
updated_media_item = Repo.reload!(media_item)
|
||||
|
||||
refute updated_media_item.media_filepath
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -7,6 +7,7 @@ defmodule PinchflatWeb.SourceControllerTest do
|
||||
|
||||
alias Pinchflat.Repo
|
||||
alias Pinchflat.Settings
|
||||
alias Pinchflat.Media.FileSyncingWorker
|
||||
alias Pinchflat.Sources.SourceDeletionWorker
|
||||
alias Pinchflat.Downloading.MediaDownloadWorker
|
||||
alias Pinchflat.Metadata.SourceMetadataStorageWorker
|
||||
@@ -268,6 +269,23 @@ defmodule PinchflatWeb.SourceControllerTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "sync_files_on_disk" do
|
||||
test "forces a file sync", %{conn: conn} do
|
||||
source = source_fixture()
|
||||
|
||||
assert [] = all_enqueued(worker: FileSyncingWorker)
|
||||
post(conn, ~p"/sources/#{source.id}/sync_files_on_disk")
|
||||
assert [_] = all_enqueued(worker: FileSyncingWorker)
|
||||
end
|
||||
|
||||
test "redirects to the source page", %{conn: conn} do
|
||||
source = source_fixture()
|
||||
|
||||
conn = post(conn, ~p"/sources/#{source.id}/sync_files_on_disk")
|
||||
assert redirected_to(conn) == ~p"/sources/#{source.id}"
|
||||
end
|
||||
end
|
||||
|
||||
defp create_source(_) do
|
||||
source = source_fixture()
|
||||
media_item = media_item_with_attachments(%{source_id: source.id})
|
||||
|
||||
Reference in New Issue
Block a user