mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
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]>
448 lines
16 KiB
HTML
448 lines
16 KiB
HTML
<!-- components/edit-video-modal.html -->
|
|
<div
|
|
id="editVideoModal"
|
|
class="bv-modal hidden items-start md:items-center"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
tabindex="-1"
|
|
data-ds="new"
|
|
>
|
|
<div id="editVideoModalOverlay" class="bv-modal-backdrop"></div>
|
|
|
|
<div class="bv-modal__panel modal-sheet max-h-modal-shell overflow-y-auto" tabindex="-1">
|
|
<div class="modal-header">
|
|
<h2 class="text-xl font-bold text-text">Edit Video Note</h2>
|
|
<button id="closeEditVideoModal" class="modal-close">
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="h-6 w-6"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M6 18L18 6M6 6l12 12"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="modal-body space-y-6">
|
|
<p class="text-sm text-muted">
|
|
Fields that already have values are locked. Click <strong>Edit field</strong> to make changes.
|
|
</p>
|
|
|
|
<form id="editVideoForm" class="space-y-5">
|
|
<div class="space-y-1">
|
|
<label for="editVideoTitle" class="block text-sm font-medium text-text">
|
|
Title
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<input
|
|
type="text"
|
|
id="editVideoTitle"
|
|
class="flex-1 input"
|
|
placeholder="Video title"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoTitle"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hashtags (kept from the old NIP-71 section: they feed bitvid's hashtag
|
|
feeds and the NIP-71 mirror; everything else in that section fed the
|
|
disabled FEATURE_PUBLISH_NIP71 path and was removed for a cleaner UI.
|
|
Existing videos' extra NIP-71 metadata is preserved on save. -->
|
|
<div class="space-y-4 rounded-lg border border-border/70 bg-overlay-black/30 p-4">
|
|
<section class="space-y-4" aria-labelledby="editNip71HashtagsLabel" data-nip71-repeater="t">
|
|
<div class="flex items-center justify-between">
|
|
<h3 id="editNip71HashtagsLabel" class="text-sm font-medium text-text">Hashtags</h3>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-xs font-semibold"
|
|
data-nip71-add="t"
|
|
>
|
|
Add hashtag
|
|
</button>
|
|
</div>
|
|
<p class="text-xs text-muted">
|
|
Tag your video so it shows up in hashtag feeds. Leading <code>#</code> characters are stripped automatically.
|
|
</p>
|
|
<div id="editNip71HashtagList" class="space-y-2" data-nip71-list="t"></div>
|
|
<template id="editNip71HashtagTemplate" data-nip71-template="t">
|
|
<div class="flex items-center gap-2" data-nip71-entry="t">
|
|
<input
|
|
type="text"
|
|
data-nip71-field="value"
|
|
placeholder="#nostr"
|
|
class="flex-1 input"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-remove="t"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</template>
|
|
</section>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoUrl" class="block text-sm font-medium text-text">
|
|
Hosted video URL (https)
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<input
|
|
type="url"
|
|
id="editVideoUrl"
|
|
class="flex-1 input"
|
|
placeholder="https://cdn.example.com/video.mp4"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoUrl"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
<div class="flex items-center gap-2 flex-wrap">
|
|
<input type="file" id="editVideoFile" accept="video/*" class="hidden" />
|
|
<button
|
|
type="button"
|
|
id="editVideoFileBtn"
|
|
class="btn-ghost focus-ring text-xs"
|
|
>
|
|
Replace video file…
|
|
</button>
|
|
<p
|
|
id="editVideoUploadStatus"
|
|
class="text-2xs text-muted empty:hidden"
|
|
role="status"
|
|
aria-live="polite"
|
|
></p>
|
|
</div>
|
|
<p class="text-xs text-muted">
|
|
Uploading a new file replaces the URL, magnet, and torrent hints.
|
|
Requires unlocked storage.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoWs" class="block text-sm font-medium text-text">
|
|
Web seeds (ws=, one per line)
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<textarea
|
|
id="editVideoWs"
|
|
rows="2"
|
|
class="flex-1 textarea"
|
|
placeholder="https://cdn.example.com/video.mp4 https://backup.example.com/video.mp4"
|
|
></textarea>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoWs"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
<p class="text-xs text-muted">
|
|
Add a backup origin so the swarm keeps streaming if the primary is
|
|
overloaded. Each must serve the exact same file.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoXs" class="block text-sm font-medium text-text">
|
|
.torrent URL (xs=)
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<input
|
|
type="url"
|
|
id="editVideoXs"
|
|
class="flex-1 input"
|
|
placeholder="https://cdn.example.com/video.torrent"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoXs"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoMagnet" class="block text-sm font-medium text-text">
|
|
Magnet link
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<input
|
|
type="text"
|
|
id="editVideoMagnet"
|
|
class="flex-1 input"
|
|
placeholder="magnet:?xt=urn:btih:..."
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoMagnet"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoThumbnail" class="block text-sm font-medium text-text">
|
|
Thumbnail URL
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<input
|
|
type="url"
|
|
id="editVideoThumbnail"
|
|
class="flex-1 input"
|
|
placeholder="https://cdn.example.com/preview.jpg"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoThumbnail"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
<div class="flex items-center gap-2 flex-wrap">
|
|
<input type="file" id="editThumbnailFile" accept="image/*" class="hidden" />
|
|
<button
|
|
type="button"
|
|
id="editThumbnailFileBtn"
|
|
class="btn-ghost focus-ring text-xs"
|
|
>
|
|
Replace thumbnail file…
|
|
</button>
|
|
<p
|
|
id="editThumbnailUploadStatus"
|
|
class="text-2xs text-muted empty:hidden"
|
|
role="status"
|
|
aria-live="polite"
|
|
></p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoDescription" class="block text-sm font-medium text-text">
|
|
Description
|
|
</label>
|
|
<div class="flex flex-col gap-2">
|
|
<textarea
|
|
id="editVideoDescription"
|
|
rows="4"
|
|
class="textarea"
|
|
placeholder="What is this video about?"
|
|
></textarea>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden self-start text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoDescription"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<span id="editVideoVisibilityLabel" class="block text-sm font-medium text-text">
|
|
Visibility
|
|
</span>
|
|
<div
|
|
class="space-y-3 rounded-md border border-border/70 bg-overlay-black/30 p-3"
|
|
role="group"
|
|
aria-labelledby="editVideoVisibilityLabel"
|
|
data-visibility-toggle
|
|
>
|
|
<div class="flex flex-wrap items-center gap-2 sm:justify-between">
|
|
<div
|
|
class="video-visibility-toggle"
|
|
data-visibility-options
|
|
>
|
|
<button
|
|
type="button"
|
|
class="video-visibility-toggle__option focus-ring"
|
|
data-visibility-option="public"
|
|
aria-pressed="false"
|
|
>
|
|
Public
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="video-visibility-toggle__option focus-ring"
|
|
data-visibility-option="private"
|
|
aria-pressed="false"
|
|
>
|
|
Private
|
|
</button>
|
|
</div>
|
|
<input
|
|
type="checkbox"
|
|
id="editVideoIsPrivate"
|
|
class="hidden"
|
|
data-default-checked="false"
|
|
aria-hidden="true"
|
|
/>
|
|
</div>
|
|
<p class="text-xs text-muted" data-visibility-helper>
|
|
Private notes stay visible only to you. Switch back to public when you're ready to share.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoIsPrivate"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<label
|
|
for="editVideoIsNsfw"
|
|
id="editVideoIsNsfwLabel"
|
|
class="block text-sm font-medium text-text"
|
|
>
|
|
NSFW content
|
|
</label>
|
|
<div
|
|
class="form-control"
|
|
role="group"
|
|
aria-labelledby="editVideoIsNsfwLabel"
|
|
>
|
|
<label class="menu__item gap-3 px-0 py-0 text-left" for="editVideoIsNsfw">
|
|
<input
|
|
type="checkbox"
|
|
id="editVideoIsNsfw"
|
|
class="checkbox"
|
|
data-default-checked="false"
|
|
/>
|
|
<span class="text-sm text-muted-strong">
|
|
Mark as sensitive to blur previews and gate playback.
|
|
</span>
|
|
</label>
|
|
</div>
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoIsNsfw"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<label
|
|
for="editVideoIsForKids"
|
|
id="editVideoIsForKidsLabel"
|
|
class="block text-sm font-medium text-text"
|
|
>
|
|
Made for kids
|
|
</label>
|
|
<div
|
|
class="form-control"
|
|
role="group"
|
|
aria-labelledby="editVideoIsForKidsLabel"
|
|
>
|
|
<label class="menu__item gap-3 px-0 py-0 text-left" for="editVideoIsForKids">
|
|
<input
|
|
type="checkbox"
|
|
id="editVideoIsForKids"
|
|
class="checkbox"
|
|
data-default-checked="false"
|
|
/>
|
|
<span class="text-sm text-muted-strong">
|
|
Flag kid-friendly videos to adjust recommendations and controls.
|
|
</span>
|
|
</label>
|
|
</div>
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoIsForKids"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<label
|
|
for="editEnableComments"
|
|
id="editEnableCommentsLabel"
|
|
class="block text-sm font-medium text-text"
|
|
>
|
|
Enable comments
|
|
</label>
|
|
<div
|
|
class="form-control"
|
|
role="group"
|
|
aria-labelledby="editEnableCommentsLabel"
|
|
>
|
|
<label class="menu__item gap-3 px-0 py-0 text-left" for="editEnableComments">
|
|
<input
|
|
type="checkbox"
|
|
id="editEnableComments"
|
|
class="checkbox"
|
|
data-default-checked="true"
|
|
checked
|
|
/>
|
|
<span class="text-sm text-muted-strong">
|
|
Allow replies once comment threads are available.
|
|
</span>
|
|
</label>
|
|
</div>
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editEnableComments"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-col gap-3 sm:flex-row sm:justify-end">
|
|
<button
|
|
type="button"
|
|
id="cancelEditVideo"
|
|
class="btn-ghost focus-ring w-full sm:w-auto"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
id="submitEditVideo"
|
|
class="btn focus-ring w-full sm:w-auto"
|
|
>
|
|
Save changes
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|