Added function for updating a media item's filepaths on-disk
This commit is contained in:
parent
0163e85e76
commit
a3d3ff91ba
3 changed files with 85 additions and 12 deletions
|
|
@ -12,7 +12,7 @@ defmodule Pinchflat.Downloading.MediaDownloadWorker do
|
|||
alias Pinchflat.Tasks
|
||||
alias Pinchflat.Repo
|
||||
alias Pinchflat.Media
|
||||
alias Pinchflat.Media.FileDeletion
|
||||
alias Pinchflat.Media.FileSyncing
|
||||
alias Pinchflat.Downloading.MediaDownloader
|
||||
|
||||
alias Pinchflat.Lifecycle.UserScripts.CommandRunner, as: UserScriptRunner
|
||||
|
|
@ -86,7 +86,7 @@ defmodule Pinchflat.Downloading.MediaDownloadWorker do
|
|||
media_redownloaded_at: get_redownloaded_at(is_quality_upgrade)
|
||||
})
|
||||
|
||||
:ok = FileDeletion.delete_outdated_files(media_item, updated_media_item)
|
||||
:ok = FileSyncing.delete_outdated_files(media_item, updated_media_item)
|
||||
run_user_script(:media_downloaded, updated_media_item)
|
||||
|
||||
:ok
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
defmodule Pinchflat.Media.FileDeletion do
|
||||
defmodule Pinchflat.Media.FileSyncing do
|
||||
@moduledoc """
|
||||
Functions for deleting files that are no longer needed by media items.
|
||||
Functions for ensuring file state is accurately reflected in the database.
|
||||
"""
|
||||
|
||||
alias Pinchflat.Media
|
||||
alias Pinchflat.Utils.MapUtils
|
||||
alias Pinchflat.Media.MediaItem
|
||||
alias Pinchflat.Utils.FilesystemUtils, as: FSUtils
|
||||
|
|
@ -34,6 +35,22 @@ defmodule Pinchflat.Media.FileDeletion do
|
|||
:ok
|
||||
end
|
||||
|
||||
@doc """
|
||||
Nillifies any media item filepaths that don't exist on disk for a list of media items
|
||||
|
||||
returns [%MediaItem{}]
|
||||
"""
|
||||
def sync_file_presence_on_disk(media_items) do
|
||||
Enum.map(media_items, fn media_item ->
|
||||
new_attributes = sync_media_item_files(media_item)
|
||||
# Doing this one-by-one instead of batching since this process
|
||||
# can take time and a batch could let MediaItem state get out of sync
|
||||
{:ok, updated_media_item} = Media.update_media_item(media_item, new_attributes)
|
||||
|
||||
updated_media_item
|
||||
end)
|
||||
end
|
||||
|
||||
defp handle_file_deletion(old_attributes, new_attributes) do
|
||||
# The logic:
|
||||
# - A file should only be deleted if it exists and the new file is different
|
||||
|
|
@ -51,4 +68,26 @@ defmodule Pinchflat.Media.FileDeletion do
|
|||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp sync_media_item_files(media_item) do
|
||||
non_subtitle_keys = MediaItem.filepath_attributes() -- [:subtitle_filepaths]
|
||||
subtitle_keys = MapUtils.from_nested_list(media_item.subtitle_filepaths)
|
||||
non_subtitles = Map.take(media_item, non_subtitle_keys)
|
||||
|
||||
# This one is checking for the negative (ie: only update if the file doesn't exist)
|
||||
new_non_subtitle_attrs =
|
||||
Enum.reduce(non_subtitles, %{}, fn {key, filepath}, acc ->
|
||||
if filepath && File.exists?(filepath), do: acc, else: Map.put(acc, key, nil)
|
||||
end)
|
||||
|
||||
# This one is checking for the positive (ie: only update if the file exists)
|
||||
# This is because subtitles, being an array type in the DB, are most easily updated
|
||||
# by a full replacement rather than finding the actual diff
|
||||
new_subtitle_attrs =
|
||||
Enum.reduce(subtitle_keys, [], fn {key, filepath}, acc ->
|
||||
if filepath && File.exists?(filepath), do: acc ++ [[key, filepath]], else: acc
|
||||
end)
|
||||
|
||||
Map.put(new_non_subtitle_attrs, :subtitle_filepaths, new_subtitle_attrs)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
defmodule Pinchflat.Media.FileDeletionTest do
|
||||
defmodule Pinchflat.Media.FileSyncingTest do
|
||||
use Pinchflat.DataCase
|
||||
|
||||
import Pinchflat.MediaFixtures
|
||||
|
||||
alias Pinchflat.Media.FileDeletion
|
||||
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 = FileDeletion.delete_outdated_files(old_media_item, new_media_item)
|
||||
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)
|
||||
|
|
@ -20,7 +20,7 @@ defmodule Pinchflat.Media.FileDeletionTest 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 :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)
|
||||
|
|
@ -30,7 +30,7 @@ defmodule Pinchflat.Media.FileDeletionTest 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 :ok = FileSyncing.delete_outdated_files(old_media_item, new_media_item)
|
||||
|
||||
assert File.exists?(old_media_item.media_filepath)
|
||||
end
|
||||
|
|
@ -39,7 +39,7 @@ defmodule Pinchflat.Media.FileDeletionTest 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 :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"))
|
||||
|
|
@ -49,7 +49,7 @@ defmodule Pinchflat.Media.FileDeletionTest 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 :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"))
|
||||
|
|
@ -59,12 +59,46 @@ defmodule Pinchflat.Media.FileDeletionTest 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 :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 "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
|
||||
Loading…
Reference in a new issue