Merge pull request #131 from PR0M3TH3AN/codex/update-edit-video-modal-form

Add comment toggle and magnet hint editing to video forms
This commit is contained in:
thePR0M3TH3AN
2025-09-27 22:57:35 -04:00
committed by GitHub
5 changed files with 387 additions and 125 deletions

View File

@@ -94,6 +94,48 @@
</div>
</div>
<div class="space-y-1">
<label for="editVideoWs" class="block text-sm font-medium text-gray-200">
Web seed (ws=)
</label>
<div class="flex flex-col gap-2 sm:flex-row">
<input
type="url"
id="editVideoWs"
class="flex-1 rounded-md border border-gray-700 bg-gray-800 text-gray-100 focus:border-blue-500 focus:ring-blue-500"
placeholder="https://cdn.example.com/video.mp4"
/>
<button
type="button"
class="edit-field-button hidden"
data-edit-target="editVideoWs"
>
Edit field
</button>
</div>
</div>
<div class="space-y-1">
<label for="editVideoXs" class="block text-sm font-medium text-gray-200">
.torrent URL (xs=)
</label>
<div class="flex flex-col gap-2 sm:flex-row">
<input
type="url"
id="editVideoXs"
class="flex-1 rounded-md border border-gray-700 bg-gray-800 text-gray-100 focus:border-blue-500 focus:ring-blue-500"
placeholder="https://cdn.example.com/video.torrent"
/>
<button
type="button"
class="edit-field-button hidden"
data-edit-target="editVideoXs"
>
Edit field
</button>
</div>
</div>
<div class="space-y-1">
<label for="editVideoMagnet" class="block text-sm font-medium text-gray-200">
Magnet link
@@ -157,6 +199,33 @@
</div>
</div>
<div class="space-y-1">
<label for="editEnableComments" class="block text-sm font-medium text-gray-200">
Enable comments
</label>
<div
class="flex flex-col gap-2 rounded-md border border-gray-800 bg-black/30 p-3 sm:flex-row sm:items-center sm:justify-between"
>
<div class="flex items-center gap-3">
<input
type="checkbox"
id="editEnableComments"
class="h-5 w-5 rounded border-gray-600 bg-gray-800 text-blue-500 focus:ring-blue-500"
/>
<span class="text-sm text-gray-300">
Allow replies once comment threads are available.
</span>
</div>
<button
type="button"
class="edit-field-button hidden"
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"

View File

@@ -147,106 +147,6 @@
cost control.
</p>
</div>
<details
id="quickR2Section"
class="rounded-md border border-gray-800 bg-gray-900/60 p-4"
>
<summary class="cursor-pointer text-sm font-semibold text-gray-200">
Optional: Upload directly to Cloudflare R2
</summary>
<div class="mt-3 space-y-4 text-sm text-gray-300">
<p class="text-xs text-gray-400">
Supply your Cloudflare credentials to upload in-browser. Keys
stay on this device unless you opt in to remember them.
</p>
<div class="grid gap-3 md:grid-cols-2">
<label class="block text-xs font-medium text-gray-300">
Account ID
<input
id="quickR2AccountId"
type="text"
autocomplete="off"
class="mt-1 w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-gray-100 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="023e105f4ecef8ad9ca31a8372d0c353"
/>
</label>
<label class="block text-xs font-medium text-gray-300">
S3 Access Key ID
<input
id="quickR2AccessKeyId"
type="text"
autocomplete="off"
class="mt-1 w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-gray-100 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</label>
<label class="block text-xs font-medium text-gray-300">
S3 Secret Access Key
<input
id="quickR2SecretAccessKey"
type="password"
autocomplete="off"
class="mt-1 w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-gray-100 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</label>
<label class="block text-xs font-medium text-gray-300">
Cloudflare API Token (R2 write)
<input
id="quickR2ApiToken"
type="password"
autocomplete="off"
class="mt-1 w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-gray-100 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Token with Workers R2 Storage Write"
/>
</label>
<label class="block text-xs font-medium text-gray-300">
Custom domain (optional)
<input
id="quickR2CustomDomain"
type="text"
class="mt-1 w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-gray-100 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="media.example.com"
/>
</label>
<label class="block text-xs font-medium text-gray-300">
Zone ID (for custom domain)
<input
id="quickR2ZoneId"
type="text"
autocomplete="off"
class="mt-1 w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-gray-100 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</label>
</div>
<div class="flex flex-wrap items-center gap-4 text-xs text-gray-300">
<label class="inline-flex items-center gap-2">
<input id="quickR2Remember" type="checkbox" class="h-4 w-4 rounded border-gray-600 bg-gray-800 text-blue-500 focus:ring-blue-500" />
Remember keys on this device
</label>
<label class="inline-flex items-center gap-2">
<input id="quickR2AllowManaged" type="checkbox" class="h-4 w-4 rounded border-gray-600 bg-gray-800 text-blue-500 focus:ring-blue-500" checked />
Allow r2.dev fallback when no custom domain
</label>
</div>
<div class="flex flex-wrap items-center gap-3">
<input
id="quickR2File"
type="file"
class="w-full max-w-xs rounded-md border border-dashed border-gray-600 bg-gray-900 px-3 py-2 text-xs text-gray-300 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
accept="video/*,application/vnd.apple.mpegurl,application/dash+xml"
/>
<button
id="quickR2UploadButton"
type="button"
class="rounded-md bg-blue-500 px-4 py-2 text-xs font-semibold text-white transition hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
>
Upload to R2
</button>
</div>
<p id="quickR2Status" class="text-xs text-gray-400" role="status"></p>
</div>
</details>
<div>
<label
for="uploadThumbnail"
@@ -272,6 +172,23 @@
class="mt-1 block w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 focus:border-blue-500 focus:ring-blue-500"
></textarea>
</div>
<div class="flex items-start gap-3 rounded-md border border-gray-800 bg-black/30 p-3">
<input
type="checkbox"
id="uploadEnableComments"
class="mt-1 h-5 w-5 rounded border-gray-600 bg-gray-800 text-blue-500 focus:ring-blue-500"
checked
/>
<div>
<label for="uploadEnableComments" class="text-sm font-medium text-gray-200"
>Enable comments</label
>
<p class="mt-1 text-xs text-gray-400">
Keep this on to let viewers discuss the video once comment threads launch.
</p>
</div>
</div>
<!--
<div class="flex items-center space-x-2">
<input
@@ -519,6 +436,22 @@
class="w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-gray-100 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<div class="flex items-start gap-3 rounded-md border border-gray-800 bg-black/30 p-3">
<input
type="checkbox"
id="cloudflareEnableComments"
class="mt-1 h-5 w-5 rounded border-gray-600 bg-gray-800 text-blue-500 focus:ring-blue-500"
checked
/>
<div>
<label for="cloudflareEnableComments" class="text-sm font-medium text-gray-200"
>Enable comments</label
>
<p class="mt-1 text-xs text-gray-400">
Publish with comments switched on. Toggle off to quietly disable replies on this video.
</p>
</div>
</div>
<div>
<label for="cloudflareFile" class="block text-sm font-medium text-gray-200"
>Video or HLS file</label

198
js/app.js
View File

@@ -6,7 +6,7 @@ import { torrentClient } from "./webtorrent.js";
import { isDevMode } from "./config.js";
import { isWhitelistEnabled } from "./config.js";
import { safeDecodeMagnet } from "./magnetUtils.js";
import { normalizeAndAugmentMagnet } from "./magnet.js";
import { extractMagnetHints, normalizeAndAugmentMagnet } from "./magnet.js";
import { deriveTorrentPlaybackConfig } from "./playbackUtils.js";
import { URL_FIRST_ENABLED } from "./constants.js";
import { trackVideoView } from "./analytics.js";
@@ -506,6 +506,7 @@ class bitvidApp {
this.closeUploadModalBtn =
document.getElementById("closeUploadModal") || null;
this.uploadForm = document.getElementById("uploadForm") || null;
this.uploadEnableCommentsInput = null;
this.uploadModeToggleButtons = [];
this.customUploadSection = null;
this.cloudflareUploadSection = null;
@@ -527,6 +528,7 @@ class bitvidApp {
this.cloudflareMagnetInput = null;
this.cloudflareWsInput = null;
this.cloudflareXsInput = null;
this.cloudflareEnableCommentsInput = null;
this.cloudflareAdvancedToggle = null;
this.cloudflareAdvancedToggleLabel = null;
this.cloudflareAdvancedToggleIcon = null;
@@ -1186,6 +1188,8 @@ class bitvidApp {
this.closeUploadModalBtn =
document.getElementById("closeUploadModal") || null;
this.uploadForm = document.getElementById("uploadForm") || null;
this.uploadEnableCommentsInput =
document.getElementById("uploadEnableComments") || null;
this.uploadModeToggleButtons = Array.from(
document.querySelectorAll(".upload-mode-toggle[data-upload-mode]")
);
@@ -1225,6 +1229,8 @@ class bitvidApp {
document.getElementById("cloudflareWs") || null;
this.cloudflareXsInput =
document.getElementById("cloudflareXs") || null;
this.cloudflareEnableCommentsInput =
document.getElementById("cloudflareEnableComments") || null;
this.cloudflareAdvancedToggle =
document.getElementById("cloudflareAdvancedToggle") || null;
this.cloudflareAdvancedToggleLabel =
@@ -1407,16 +1413,24 @@ class bitvidApp {
"editVideoTitle",
"editVideoUrl",
"editVideoMagnet",
"editVideoWs",
"editVideoXs",
"editVideoThumbnail",
"editVideoDescription",
"editEnableComments",
];
fieldIds.forEach((id) => {
const input = this.editVideoModal.querySelector(`#${id}`);
if (input) {
input.value = "";
input.readOnly = false;
input.classList.remove("locked-input");
if (input.type === "checkbox") {
input.checked = true;
input.disabled = false;
} else {
input.value = "";
input.readOnly = false;
input.classList.remove("locked-input");
}
delete input.dataset.originalValue;
}
const button = this.editVideoModal.querySelector(
@@ -2225,12 +2239,31 @@ class bitvidApp {
this.resetEditVideoForm();
const magnetSource = video.magnet || video.rawMagnet || "";
const magnetHints = extractMagnetHints(magnetSource);
const effectiveWs = video.ws || magnetHints.ws || "";
const effectiveXs = video.xs || magnetHints.xs || "";
const enableCommentsValue =
typeof video.enableComments === "boolean"
? video.enableComments
: true;
const editContext = {
...video,
ws: effectiveWs,
xs: effectiveXs,
enableComments: enableCommentsValue,
};
const fieldMap = {
editVideoTitle: video.title || "",
editVideoUrl: video.url || "",
editVideoMagnet: video.magnet || "",
editVideoThumbnail: video.thumbnail || "",
editVideoDescription: video.description || "",
editVideoTitle: editContext.title || "",
editVideoUrl: editContext.url || "",
editVideoMagnet: editContext.magnet || "",
editVideoWs: editContext.ws || "",
editVideoXs: editContext.xs || "",
editVideoThumbnail: editContext.thumbnail || "",
editVideoDescription: editContext.description || "",
editEnableComments: editContext.enableComments,
};
Object.entries(fieldMap).forEach(([id, rawValue]) => {
@@ -2238,19 +2271,47 @@ class bitvidApp {
const button = this.editVideoModal.querySelector(
`[data-edit-target="${id}"]`
);
if (!input) {
if (button) {
button.classList.add("hidden");
button.dataset.mode = "locked";
button.textContent = "Edit field";
}
return;
}
const isCheckbox = input.type === "checkbox";
if (isCheckbox) {
const hasValue = rawValue !== undefined;
const boolValue = rawValue === true;
input.checked = boolValue;
input.disabled = hasValue;
input.dataset.originalValue = boolValue ? "true" : "false";
if (button) {
if (hasValue) {
button.classList.remove("hidden");
button.dataset.mode = "locked";
button.textContent = "Edit field";
} else {
button.classList.add("hidden");
button.dataset.mode = "locked";
button.textContent = "Edit field";
}
}
return;
}
const value = typeof rawValue === "string" ? rawValue : "";
const hasValue = value.trim().length > 0;
if (input) {
input.value = value;
input.dataset.originalValue = value;
if (hasValue) {
input.readOnly = true;
input.classList.add("locked-input");
} else {
input.readOnly = false;
input.classList.remove("locked-input");
}
input.value = value;
input.dataset.originalValue = value;
if (hasValue) {
input.readOnly = true;
input.classList.add("locked-input");
} else {
input.readOnly = false;
input.classList.remove("locked-input");
}
if (button) {
@@ -2266,7 +2327,7 @@ class bitvidApp {
}
});
this.activeEditVideo = video;
this.activeEditVideo = editContext;
}
handleEditFieldToggle(event) {
@@ -2286,12 +2347,18 @@ class bitvidApp {
}
const mode = button.dataset.mode || "locked";
const isCheckbox = input.type === "checkbox";
if (mode === "locked") {
input.readOnly = false;
input.classList.remove("locked-input");
if (isCheckbox) {
input.disabled = false;
} else {
input.readOnly = false;
input.classList.remove("locked-input");
}
button.dataset.mode = "editing";
button.textContent = "Restore original";
if (typeof input.focus === "function") {
if (!isCheckbox && typeof input.focus === "function") {
input.focus();
if (typeof input.setSelectionRange === "function") {
const length = input.value.length;
@@ -2306,6 +2373,15 @@ class bitvidApp {
}
const originalValue = input.dataset?.originalValue || "";
if (isCheckbox) {
input.checked = originalValue === "true";
input.disabled = true;
button.dataset.mode = "locked";
button.textContent = "Edit field";
return;
}
input.value = originalValue;
if (originalValue) {
@@ -2461,6 +2537,10 @@ class bitvidApp {
if (this.cloudflareFileInput) {
this.cloudflareFileInput.disabled = Boolean(isUploading);
}
if (this.cloudflareEnableCommentsInput) {
this.cloudflareEnableCommentsInput.disabled = Boolean(isUploading);
}
}
updateCloudflareProgress(fraction) {
@@ -2488,6 +2568,8 @@ class bitvidApp {
if (this.cloudflareMagnetInput) this.cloudflareMagnetInput.value = "";
if (this.cloudflareWsInput) this.cloudflareWsInput.value = "";
if (this.cloudflareXsInput) this.cloudflareXsInput.value = "";
if (this.cloudflareEnableCommentsInput)
this.cloudflareEnableCommentsInput.checked = true;
if (this.cloudflareFileInput) this.cloudflareFileInput.value = "";
this.updateCloudflareProgress(Number.NaN);
}
@@ -2981,6 +3063,9 @@ class bitvidApp {
const magnet = (this.cloudflareMagnetInput?.value || "").trim();
const ws = (this.cloudflareWsInput?.value || "").trim();
const xs = (this.cloudflareXsInput?.value || "").trim();
const enableComments = this.cloudflareEnableCommentsInput
? this.cloudflareEnableCommentsInput.checked
: true;
const accountId = (this.cloudflareSettings?.accountId || "").trim();
const accessKeyId = (this.cloudflareSettings?.accessKeyId || "").trim();
@@ -3076,6 +3161,7 @@ class bitvidApp {
description,
ws,
xs,
enableComments,
};
const published = await this.publishVideoNote(payload, {
@@ -3536,6 +3622,12 @@ class bitvidApp {
const description = (payload?.description || "").trim();
const ws = (payload?.ws || "").trim();
const xs = (payload?.xs || "").trim();
const enableComments =
payload?.enableComments === false
? false
: payload?.enableComments === true
? true
: true;
const formData = {
version: 3,
@@ -3545,6 +3637,7 @@ class bitvidApp {
thumbnail,
description,
mode: isDevMode ? "dev" : "live",
enableComments,
};
if (!formData.title || (!formData.url && !formData.magnet)) {
@@ -3558,10 +3651,17 @@ class bitvidApp {
}
if (formData.magnet) {
formData.magnet = normalizeAndAugmentMagnet(formData.magnet, {
const normalizedMagnet = normalizeAndAugmentMagnet(formData.magnet, {
ws,
xs,
});
formData.magnet = normalizedMagnet;
const hints = extractMagnetHints(normalizedMagnet);
formData.ws = hints.ws;
formData.xs = hints.xs;
} else {
formData.ws = "";
formData.xs = "";
}
try {
@@ -3601,14 +3701,38 @@ class bitvidApp {
const newTitle = fieldValue("editVideoTitle");
const newUrl = fieldValue("editVideoUrl");
const newMagnet = fieldValue("editVideoMagnet");
const newWs = fieldValue("editVideoWs");
const newXs = fieldValue("editVideoXs");
const wsInput = this.editVideoModal.querySelector("#editVideoWs");
const xsInput = this.editVideoModal.querySelector("#editVideoXs");
const newThumbnail = fieldValue("editVideoThumbnail");
const newDescription = fieldValue("editVideoDescription");
const commentsEl = this.editVideoModal.querySelector(
"#editEnableComments"
);
const finalTitle = newTitle || original.title || "";
const finalUrl = newUrl || original.url || "";
const finalMagnet = newMagnet || original.magnet || "";
const shouldUseOriginalWs = wsInput ? wsInput.readOnly !== false : true;
const shouldUseOriginalXs = xsInput ? xsInput.readOnly !== false : true;
let finalWs = shouldUseOriginalWs ? original.ws || "" : newWs;
let finalXs = shouldUseOriginalXs ? original.xs || "" : newXs;
let finalMagnet = newMagnet || original.magnet || "";
const finalThumbnail = newThumbnail || original.thumbnail || "";
const finalDescription = newDescription || original.description || "";
const originalEnableComments =
typeof original.enableComments === "boolean"
? original.enableComments
: true;
let finalEnableComments = originalEnableComments;
if (commentsEl) {
if (commentsEl.disabled) {
finalEnableComments = commentsEl.dataset.originalValue === "true";
} else {
finalEnableComments = commentsEl.checked;
}
}
if (!finalTitle || (!finalUrl && !finalMagnet)) {
this.showError("Title and at least one of URL or Magnet is required.");
@@ -3620,6 +3744,20 @@ class bitvidApp {
return;
}
if (finalMagnet) {
const normalizedMagnet = normalizeAndAugmentMagnet(finalMagnet, {
ws: finalWs,
xs: finalXs,
});
finalMagnet = normalizedMagnet;
const hints = extractMagnetHints(normalizedMagnet);
finalWs = hints.ws;
finalXs = hints.xs;
} else {
finalWs = "";
finalXs = "";
}
const updatedData = {
version: original.version || 2,
title: finalTitle,
@@ -3628,6 +3766,11 @@ class bitvidApp {
thumbnail: finalThumbnail,
description: finalDescription,
mode: isDevMode ? "dev" : "live",
ws: finalWs,
xs: finalXs,
wsEdited: !shouldUseOriginalWs,
xsEdited: !shouldUseOriginalXs,
enableComments: finalEnableComments,
};
const originalEvent = {
@@ -3661,6 +3804,7 @@ class bitvidApp {
const thumbEl = document.getElementById("uploadThumbnail");
const descEl = document.getElementById("uploadDescription");
const privEl = document.getElementById("uploadIsPrivate");
const commentsEl = document.getElementById("uploadEnableComments");
const title = titleEl?.value.trim() || "";
const url = urlEl?.value.trim() || "";
@@ -3669,6 +3813,7 @@ class bitvidApp {
const xs = xsEl?.value.trim() || "";
const thumbnail = thumbEl?.value.trim() || "";
const description = descEl?.value.trim() || "";
const enableComments = commentsEl ? commentsEl.checked : true;
const payload = {
title,
@@ -3678,6 +3823,7 @@ class bitvidApp {
description,
ws,
xs,
enableComments,
};
await this.publishVideoNote(payload, {
@@ -3690,6 +3836,7 @@ class bitvidApp {
if (thumbEl) thumbEl.value = "";
if (descEl) descEl.value = "";
if (privEl) privEl.checked = false;
if (commentsEl) commentsEl.checked = true;
},
});
}
@@ -4655,6 +4802,7 @@ class bitvidApp {
thumbnail: typeof video.thumbnail === "string" ? video.thumbnail : "",
url: typeof video.url === "string" ? video.url : "",
magnet: typeof video.magnet === "string" ? video.magnet : "",
enableComments: video.enableComments === false ? false : true,
}));
const signature = JSON.stringify(signaturePayload);

View File

@@ -168,3 +168,57 @@ export function normalizeAndAugmentMagnet(rawValue, { ws = "", xs = "" } = {}) {
return `${normalizedScheme}${queryString ? `?${queryString}` : ""}${fragment}`;
}
export function extractMagnetHints(rawValue) {
const hints = { ws: "", xs: "" };
if (typeof rawValue !== "string") {
return hints;
}
const trimmed = rawValue.trim();
if (!trimmed || !trimmed.toLowerCase().startsWith("magnet:")) {
return hints;
}
const queryIndex = trimmed.indexOf("?");
if (queryIndex === -1 || queryIndex === trimmed.length - 1) {
return hints;
}
const query = trimmed.slice(queryIndex + 1);
if (!query) {
return hints;
}
const parts = query.split("&");
for (const part of parts) {
if (!part) {
continue;
}
const [rawKey, rawValue = ""] = part.split("=", 2);
if (!rawKey) {
continue;
}
const lowerKey = rawKey.trim().toLowerCase();
if (lowerKey !== "ws" && lowerKey !== "xs") {
continue;
}
if (hints[lowerKey]) {
continue;
}
let decoded = rawValue;
try {
decoded = decodeURIComponent(rawValue);
} catch (err) {
// Ignore decode errors and use the raw value.
}
const clean = typeof decoded === "string" ? decoded.trim() : "";
if (!clean) {
continue;
}
hints[lowerKey] = clean;
}
return hints;
}

View File

@@ -5,6 +5,7 @@ import { ACCEPT_LEGACY_V1 } from "./constants.js";
import { accessControl } from "./accessControl.js";
// 🔧 merged conflicting changes from codex/update-video-publishing-and-parsing-logic vs unstable
import { deriveTitleFromEvent, magnetFromText } from "./videoEventUtils.js";
import { extractMagnetHints } from "./magnet.js";
/**
* The usual relays
@@ -196,6 +197,10 @@ function convertEventToVideo(event = {}) {
const deleted = parsedContent.deleted === true;
const isPrivate = parsedContent.isPrivate === true;
const videoRootId = safeTrim(parsedContent.videoRootId) || event.id;
const wsField = safeTrim(parsedContent.ws);
const xsField = safeTrim(parsedContent.xs);
const enableComments =
parsedContent.enableComments === false ? false : true;
let infoHash = "";
const pushInfoHash = (candidate) => {
@@ -282,6 +287,12 @@ function convertEventToVideo(event = {}) {
};
}
const magnetHints = magnet
? extractMagnetHints(magnet)
: { ws: "", xs: "" };
const ws = wsField || magnetHints.ws || "";
const xs = xsField || magnetHints.xs || "";
return {
id: event.id,
videoRootId,
@@ -296,6 +307,9 @@ function convertEventToVideo(event = {}) {
description,
mode,
deleted,
ws,
xs,
enableComments,
pubkey: event.pubkey,
created_at: event.created_at,
tags,
@@ -612,6 +626,13 @@ class NostrClient {
const videoRootId = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
const dTagValue = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
const finalEnableComments =
videoData.enableComments === false ? false : true;
const finalWs =
typeof videoData.ws === "string" ? videoData.ws.trim() : "";
const finalXs =
typeof videoData.xs === "string" ? videoData.xs.trim() : "";
const contentObject = {
version: 3,
title: finalTitle,
@@ -623,8 +644,17 @@ class NostrClient {
videoRootId,
deleted: false,
isPrivate: videoData.isPrivate ?? false,
enableComments: finalEnableComments,
};
if (finalWs) {
contentObject.ws = finalWs;
}
if (finalXs) {
contentObject.xs = finalXs;
}
const event = {
kind: 30078,
pubkey,
@@ -799,6 +829,25 @@ class NostrClient {
typeof updatedData.url === "string" ? updatedData.url.trim() : "";
const finalUrl = newUrlValue || oldUrl;
const wsEdited = updatedData.wsEdited === true;
const xsEdited = updatedData.xsEdited === true;
const newWsValue =
typeof updatedData.ws === "string" ? updatedData.ws.trim() : "";
const newXsValue =
typeof updatedData.xs === "string" ? updatedData.xs.trim() : "";
const baseWs =
typeof baseEvent.ws === "string" ? baseEvent.ws.trim() : "";
const baseXs =
typeof baseEvent.xs === "string" ? baseEvent.xs.trim() : "";
const finalWs = wsEdited ? newWsValue : baseWs;
const finalXs = xsEdited ? newXsValue : baseXs;
const finalEnableComments =
typeof updatedData.enableComments === "boolean"
? updatedData.enableComments
: baseEvent.enableComments === false
? false
: true;
// Use the existing videoRootId (or fall back to the base event's ID)
const oldRootId = baseEvent.videoRootId || baseEvent.id;
@@ -817,8 +866,17 @@ class NostrClient {
thumbnail: updatedData.thumbnail ?? baseEvent.thumbnail,
description: updatedData.description ?? baseEvent.description,
mode: updatedData.mode ?? baseEvent.mode ?? "live",
enableComments: finalEnableComments,
};
if (finalWs) {
contentObject.ws = finalWs;
}
if (finalXs) {
contentObject.xs = finalXs;
}
const event = {
kind: 30078,
// Use the provided userPubkey (or you can also force it to lowercase here if desired)