mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Previously editing a video deleted the old hosted video + its .torrent when the
URL changed, but intentionally left the old thumbnail orphaned in the bucket.
Now that the Edit modal can replace a thumbnail (and we have a clear "thumbnail
changed" signal), also delete the superseded thumbnail: build an orphan list with
the old video ({url}) and/or old thumbnail ({thumbnail}) and pass both to
deleteVideoStorage. Each guarded on old & new being non-empty and different, so we
never delete an object the new note still references. Best-effort; never blocks
the edit.
Tests (collectVideoStorageKeys): a {url} orphan yields the video key + sibling
.torrent; a {thumbnail} orphan yields the thumbnail key; both collect together;
objects under a different publicBaseUrl are never collected (bucket-switch safety).
Also documents the pre-existing uploadModal-reset.test.mjs flake in KNOWN_ISSUES
(reproduced on 1b11cb1b; not from this work).
Build + full lint green; full unit suite green except the documented pre-existing
flake.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
57 lines
2.1 KiB
JavaScript
57 lines
2.1 KiB
JavaScript
// On edit, superseded R2/S3 objects are removed by passing orphan descriptors to
|
|
// deleteVideoStorage, which derives the bucket keys via collectVideoStorageKeys.
|
|
// This guards the descriptors the edit-cleanup builds map to the right keys:
|
|
// - a replaced video entry -> the video key AND its sibling .torrent
|
|
// - a replaced thumbnail entry -> the thumbnail key
|
|
// and that only objects under the configured publicBaseUrl are ever collected.
|
|
|
|
import "./test-helpers/setup-localstorage.mjs";
|
|
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { collectVideoStorageKeys } from "../js/utils/storagePointer.js";
|
|
|
|
const BASE = "https://pub-abc.r2.dev";
|
|
|
|
test("a replaced video entry yields the video key + its .torrent", () => {
|
|
const keys = collectVideoStorageKeys({
|
|
videos: [{ url: `${BASE}/u/npub1x/deadbeef/my-clip.mp4` }],
|
|
publicBaseUrl: BASE,
|
|
});
|
|
assert.deepEqual(
|
|
keys.sort(),
|
|
["u/npub1x/deadbeef/my-clip.mp4", "u/npub1x/deadbeef/my-clip.torrent"].sort(),
|
|
);
|
|
});
|
|
|
|
test("a replaced thumbnail entry yields the thumbnail key", () => {
|
|
const keys = collectVideoStorageKeys({
|
|
videos: [{ thumbnail: `${BASE}/npub1x/thumbnails/123-old.png` }],
|
|
publicBaseUrl: BASE,
|
|
});
|
|
assert.deepEqual(keys, ["npub1x/thumbnails/123-old.png"]);
|
|
});
|
|
|
|
test("both video and thumbnail orphans collect together", () => {
|
|
const keys = collectVideoStorageKeys({
|
|
videos: [
|
|
{ url: `${BASE}/u/npub1x/hash/clip.mp4` },
|
|
{ thumbnail: `${BASE}/npub1x/thumbnails/9-old.jpg` },
|
|
],
|
|
publicBaseUrl: BASE,
|
|
});
|
|
assert.ok(keys.includes("u/npub1x/hash/clip.mp4"));
|
|
assert.ok(keys.includes("u/npub1x/hash/clip.torrent"));
|
|
assert.ok(keys.includes("npub1x/thumbnails/9-old.jpg"));
|
|
});
|
|
|
|
test("objects under a DIFFERENT base are never collected (bucket switch safety)", () => {
|
|
const keys = collectVideoStorageKeys({
|
|
videos: [
|
|
{ url: "https://other-bucket.r2.dev/u/npub1x/hash/clip.mp4" },
|
|
{ thumbnail: "https://other-bucket.r2.dev/npub1x/thumbnails/9.jpg" },
|
|
],
|
|
publicBaseUrl: BASE,
|
|
});
|
|
assert.deepEqual(keys, []);
|
|
});
|