Ensured metadata is deleted when other files are deleted

This commit is contained in:
Kieran Eglin 2024-02-24 12:28:05 -08:00
parent dc264897d6
commit 3ae4ddf822
No known key found for this signature in database
GPG key ID: 193984967FCF432D
4 changed files with 78 additions and 6 deletions

View file

@ -9,6 +9,7 @@ defmodule Pinchflat.Media do
alias Pinchflat.Tasks
alias Pinchflat.Media.MediaItem
alias Pinchflat.Sources.Source
alias Pinchflat.Media.MediaMetadata
@doc """
Returns the list of media_items. Returns [%MediaItem{}, ...].
@ -103,6 +104,21 @@ defmodule Pinchflat.Media do
|> Enum.filter(&is_binary/1)
end
@doc """
Produces a flat list of the filesystem paths for a media_item's metadata files.
Returns an empty list if the media_item has no metadata.
Returns [binary()] | []
"""
def metadata_filepaths(media_item) do
metadata = Repo.preload(media_item, :metadata).metadata || %MediaMetadata{}
mapped_struct = Map.from_struct(metadata)
MediaMetadata.filepath_attributes()
|> Enum.map(fn field -> mapped_struct[field] end)
|> Enum.filter(&is_binary/1)
end
@doc """
Creates a media_item. Returns {:ok, %MediaItem{}} | {:error, %Ecto.Changeset{}}.
"""
@ -137,15 +153,23 @@ defmodule Pinchflat.Media do
Returns {:ok, %MediaItem{}}
"""
def delete_attachments(media_item) do
media_item = Repo.preload(media_item, :metadata)
media_item
|> media_filepaths()
|> Enum.concat(metadata_filepaths(media_item))
|> Enum.each(&File.rm/1)
# Fails if the directory is not empty
case File.rmdir(Path.dirname(media_item.media_filepath)) do
:ok -> {:ok, media_item}
{:error, :eexist} -> {:ok, media_item}
# rmdir will attempt to delete the directory, but only if it is empty
if media_item.media_filepath do
File.rmdir(Path.dirname(media_item.media_filepath))
end
if media_item.metadata && media_item.metadata.metadata_filepath do
File.rmdir(Path.dirname(media_item.metadata.metadata_filepath))
end
{:ok, media_item}
end
@doc """

View file

@ -29,4 +29,9 @@ defmodule Pinchflat.Media.MediaMetadata do
|> validate_required(@required_fields)
|> unique_constraint([:media_item_id])
end
@doc false
def filepath_attributes do
~w(metadata_filepath thumbnail_filepath)a
end
end

View file

@ -9,8 +9,6 @@ defmodule Pinchflat.MediaClient.Backends.YtDlp.MetadataFileHelpers do
needed
"""
# TODO: ensure media metadata is deleted when the media item is deleted
@doc """
Compresses and stores metadata for a media item, returning the filepath.

View file

@ -1,6 +1,7 @@
defmodule Pinchflat.MediaTest do
use Pinchflat.DataCase
import Mox
import Pinchflat.TasksFixtures
import Pinchflat.MediaFixtures
import Pinchflat.ProfilesFixtures
@ -8,6 +9,9 @@ defmodule Pinchflat.MediaTest do
alias Pinchflat.Media
alias Pinchflat.Media.MediaItem
alias Pinchflat.MediaClient.Backends.YtDlp.MetadataFileHelpers
setup :verify_on_exit!
@invalid_attrs %{title: nil, media_id: nil, media_filepath: nil}
@ -261,6 +265,27 @@ defmodule Pinchflat.MediaTest do
end
end
describe "metadata_filepaths" do
test "returns filepaths in a flat list" do
filepaths = %{
metadata_filepath: "/metadata.json.gz",
thumbnail_filepath: "/thumbnail.jpg"
}
media_item = media_item_fixture(%{metadata: filepaths})
assert Media.metadata_filepaths(media_item) == [
"/metadata.json.gz",
"/thumbnail.jpg"
]
end
test "returns an empty list when there is no metadata" do
media_item = media_item_fixture()
assert Media.metadata_filepaths(media_item) == []
end
end
describe "create_media_item/1" do
test "creating with valid data creates a media_item" do
valid_attrs = %{
@ -330,6 +355,26 @@ defmodule Pinchflat.MediaTest do
refute File.exists?(media_item.media_filepath)
end
test "deletes the media item's metadata files" do
stub(HTTPClientMock, :get, fn _url, _headers, _opts -> {:ok, ""} end)
media_item = Repo.preload(media_item_with_attachments(), :metadata)
update_attrs = %{
metadata: %{
metadata_filepath: MetadataFileHelpers.compress_and_store_metadata_for(media_item, %{}),
thumbnail_filepath:
MetadataFileHelpers.download_and_store_thumbnail_for(media_item, %{
"thumbnail" => "https://example.com/thumbnail.jpg"
})
}
}
{:ok, updated_media_item} = Media.update_media_item(media_item, update_attrs)
assert {:ok, _} = Media.delete_attachments(updated_media_item)
refute File.exists?(updated_media_item.metadata.metadata_filepath)
end
test "does not delete the media item" do
media_item = media_item_with_attachments()