bitvid authors kind-30078 and MIRRORS to NIP-71; it never authors NIP-71 directly.
Verified before removing: the My Videos mirror (buildNip71MirrorEvent) derives
everything from the bitvid note itself (duration/dims are auto-captured at upload,
contentWarning comes from the NSFW toggle, imeta is built from the video), and the
only consumer of the form's NIP-71 metadata (publishNip71Video) is gated behind
FEATURE_PUBLISH_NIP71: false — the fields fed a dead path and confused uploaders.
Removed from the upload modal: "NIP-71 Technical" (content warning, duration,
summary + Customize toggle) and the IMETA variant editor. Removed from the edit
modal: kind (21/22) selector, published_at, alt, duration, content warning,
summary, IMETA, text tracks, segments, participants, references. KEPT in both:
hashtags (they feed hashtag feeds, the suggestion chips, and the mirror's t tags)
and the web seeds / torrent (xs) inputs (bitvid-note fields, not NIP-71). All the
JS plumbing is missing-DOM tolerant, so no wiring changes were needed to collect.
Compatibility: existing videos' NIP-71 extras survive a save. EditModal keeps the
video's full stored metadata (storedNip71Metadata) and merges the edited hashtags
into it on submit instead of replacing it with the reduced form's empty output
(t mirror key kept in sync).
Also fixes a latent pre-existing bug the reduction exposed: nip71Edited compared
the submit-side copy AFTER publishedAt normalization (string→timestamp,
delete-empty) against an UN-normalized original, so any video with publishedAt
made every save look "edited". Both sides now share normalizeCollectedNip71.
Tests: +2 in edit-modal-submit-state (stored extras survive a hashtag edit;
untouched save keeps nip71Edited false). Modal/payload/mirror suites green
(39 + 7). Lint + build green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Brings the Edit modal to upload parity with the Upload modal: re-upload a
thumbnail or video file instead of only pasting URLs.
- Wire storage services (r2/s3/storageService) + pubkey/npub accessors into
EditModal via ModalManager/initEditModal; EditModal constructs a shared
MediaUploader.
- New editModalUpload.js holds all the upload glue (file-picker wiring, progress,
storage-unlock checks, field write-back) to keep EditModal under its file-size
budget. EditModal calls initEditModalUpload(this, context) in one line.
- edit-video-modal.html: "Replace video file…" (under the URL field) and
"Replace thumbnail file…" (under the thumbnail field), each with a hidden file
input + status line.
- On thumbnail upload: writes the new URL into the thumbnail field. On video
upload: writes url + magnet (+ ws/xs hints). All written via setFieldUnlocked,
which marks the field edited so EditModal.collect actually persists it (gated
behind storage being configured + unlocked).
setFieldUnlocked is unit-tested (mutation-verified): without the unlock, the
re-upload would silently not save. Build + full lint + unit suite green.
NOTE: the upload/storage flow itself can't be unit-tested (browser + R2/S3);
pending manual verification of editing a video's thumbnail/file.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Completes end-to-end multi-webseed support: the editor can now see, add, and
remove every web seed a video carries.
- magnetShared: promote normalizeWebSeedList to a shared export (videoNotePayload
now imports it) and add setMagnetWebSeeds(), which replaces a magnet's COMPLETE
ws= set with exactly the requested list. ensureWebSeeds is append-only, so
without set-semantics a webseed a user deleted would linger in the magnet;
setMagnetWebSeeds strips the existing ws= params first, making removal stick.
- edit-video-modal.html: the single "Web seed (ws=)" input becomes a "Web seeds
(one per line)" textarea with backup-origin help text.
- EditModal: open() populates the field from extractAllWebSeeds() (every seed,
not just the first). On save, when the field was manually edited the magnet's
ws set is rebuilt from the field via setMagnetWebSeeds (true add/remove);
otherwise existing seeds are preserved untouched. The content `ws` field still
stores the primary (first) seed while the magnet carries the full set.
Mutation-verified (no-strip and no-add both fail the removal/add tests); build,
relevant lints (inline-styles, tokens, innerHTML), and full unit suite green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>