Skip to content

Commit 92b6210

Browse files
mjcCopilot
andcommitted
Preserve space-saved data on same-size upserts
Protect encoded savings calculations by preserving the current size when an existing video already has original_size and an incoming upsert reports the same file size. This keeps sync and webhook upserts from disturbing actual space-saved metrics unless the file size really changes. Also add regression coverage for encoded videos and same-size updates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent e7eeea2 commit 92b6210

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

lib/reencodarr/media/video_upsert.ex

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,34 @@ defmodule Reencodarr.Media.VideoUpsert do
216216
# These are set by the encoding pipeline and must never be reset by sync.
217217
base = [:id, :inserted_at, :state, :failed, :chosen_vmaf_id, :original_size]
218218

219+
base =
220+
if preserve_saved_space_size?(attrs) do
221+
[:size | base]
222+
else
223+
base
224+
end
225+
219226
if Map.has_key?(attrs, "bitrate") do
220227
base
221228
else
222229
[:bitrate | base]
223230
end
224231
end
225232

233+
defp preserve_saved_space_size?(%{"path" => path, "size" => new_size})
234+
when is_binary(path) and is_integer(new_size) do
235+
case Repo.one(
236+
from v in Video,
237+
where: v.path == ^path and not is_nil(v.original_size),
238+
select: %{size: v.size}
239+
) do
240+
%{size: ^new_size} -> true
241+
_ -> false
242+
end
243+
end
244+
245+
defp preserve_saved_space_size?(_), do: false
246+
226247
@spec build_on_conflict_query(%{String.t() => any()}, [atom()]) ::
227248
{:replace_all_except, [atom()]} | Ecto.Query.t()
228249
defp build_on_conflict_query(attrs, conflict_except) do

test/reencodarr/media/video_upsert_test.exs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,11 +497,49 @@ defmodule Reencodarr.Media.VideoUpsertTest do
497497
{:ok, video} = VideoUpsert.upsert(attrs)
498498
assert video.state == :encoded
499499

500+
video =
501+
video
502+
|> Ecto.Changeset.change(%{original_size: 1_500_000})
503+
|> Repo.update!()
504+
500505
# Should not query for metadata comparison when encoded
501506
updated_attrs = Map.merge(attrs, %{"size" => 2_000_000})
502507
{:ok, updated_video} = VideoUpsert.upsert(updated_attrs)
503508

504509
assert updated_video.id == video.id
510+
assert updated_video.size == 2_000_000
511+
assert updated_video.original_size == 1_500_000
512+
end
513+
514+
test "preserves encoded size data on same-size upserts", %{library: library} do
515+
attrs = %{
516+
"path" => "/mnt/test/show/episode.mkv",
517+
"size" => 1_000_000,
518+
"duration" => 3600.0,
519+
"bitrate" => 8_000_000,
520+
"width" => 1920,
521+
"height" => 1080,
522+
"video_codecs" => ["av1"],
523+
"audio_codecs" => ["opus"],
524+
"library_id" => library.id,
525+
"state" => "encoded",
526+
"service_id" => "file-1"
527+
}
528+
529+
{:ok, video} = VideoUpsert.upsert(attrs)
530+
531+
video =
532+
video
533+
|> Ecto.Changeset.change(%{original_size: 1_500_000})
534+
|> Repo.update!()
535+
536+
updated_attrs = Map.merge(attrs, %{"service_id" => "file-2"})
537+
{:ok, updated_video} = VideoUpsert.upsert(updated_attrs)
538+
539+
assert updated_video.id == video.id
540+
assert updated_video.size == 1_000_000
541+
assert updated_video.original_size == 1_500_000
542+
assert updated_video.service_id == "file-2"
505543
end
506544

507545
test "handles update when video is in failed state", %{library: library} do

0 commit comments

Comments
 (0)