mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-02 19:02:28 +00:00
Add thumbnail upload support to UploadModal and R2Service
- Added file input and browse button for thumbnails in `upload-modal.html`. - Updated `UploadModal.js` to handle thumbnail file selection and UI toggling. - Updated `r2Service.js` to upload thumbnail file (if present) to R2 and update metadata. - Ensured thumbnail keys are derived from video keys for consistent naming.
This commit is contained in:
1 parent
77fba07fc3
commit
44aed00b5e
3 files changed
+76
-1
No files matched your search
@@ -199,7 +199,18 @@
|
||||
|
||||
<div class="space-y-2">
|
||||
<label for="input-thumbnail" class="block text-sm font-medium text-text">Thumbnail URL</label>
|
||||
<input id="input-thumbnail" type="url" class="input" placeholder="https://example.com/thumbnail.jpg" />
|
||||
<div class="flex gap-2">
|
||||
<input id="input-thumbnail" type="url" class="input flex-1" placeholder="https://example.com/thumbnail.jpg" />
|
||||
<input id="input-thumbnail-file" type="file" class="hidden" accept="image/*" />
|
||||
<button
|
||||
type="button"
|
||||
id="btn-thumbnail-file"
|
||||
class="btn-secondary px-3 text-sm whitespace-nowrap"
|
||||
aria-label="Upload thumbnail image"
|
||||
>
|
||||
Browse...
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hashtags -->
|
||||
|
||||
@@ -636,6 +636,7 @@ class R2Service {
|
||||
async handleCloudflareUploadSubmit({
|
||||
npub = "",
|
||||
file = null,
|
||||
thumbnailFile = null,
|
||||
metadata = {},
|
||||
settingsInput = null,
|
||||
publishVideoNote,
|
||||
@@ -748,6 +749,33 @@ class R2Service {
|
||||
try {
|
||||
const s3 = makeR2Client({ accountId, accessKeyId, secretAccessKey });
|
||||
|
||||
if (thumbnailFile) {
|
||||
this.setCloudflareUploadStatus("Uploading thumbnail...", "info");
|
||||
const thumbExt = thumbnailFile.name.split('.').pop() || 'jpg';
|
||||
const thumbKey = key.replace(/\.[^/.]+$/, "") + `.thumb.${thumbExt}`;
|
||||
|
||||
try {
|
||||
await multipartUpload({
|
||||
s3,
|
||||
bucket: bucketEntry.bucket,
|
||||
key: thumbKey,
|
||||
file: thumbnailFile,
|
||||
contentType: thumbnailFile.type || "image/jpeg",
|
||||
});
|
||||
const thumbUrl = buildPublicUrl(bucketEntry.publicBaseUrl, thumbKey);
|
||||
if (typeof metadata === "object") {
|
||||
metadata.thumbnail = thumbUrl;
|
||||
}
|
||||
} catch (err) {
|
||||
userLogger.warn("Thumbnail upload failed, continuing with video...", err);
|
||||
}
|
||||
}
|
||||
|
||||
this.setCloudflareUploadStatus(
|
||||
statusMessage,
|
||||
bucketResult?.usedManagedFallback ? "warning" : "info"
|
||||
);
|
||||
|
||||
await multipartUpload({
|
||||
s3,
|
||||
bucket: bucketEntry.bucket,
|
||||
|
||||
@@ -146,6 +146,7 @@ export class UploadModal {
|
||||
title: $("#input-title"),
|
||||
description: $("#input-description"),
|
||||
thumbnail: $("#input-thumbnail"),
|
||||
thumbnailFile: $("#input-thumbnail-file"),
|
||||
file: $("#input-file"),
|
||||
url: $("#input-url"),
|
||||
magnet: $("#input-magnet"),
|
||||
@@ -180,6 +181,7 @@ export class UploadModal {
|
||||
storageSettings: $("#btn-storage-settings"),
|
||||
r2Advanced: $("#btn-r2-advanced"),
|
||||
saveSettings: $("#btn-save-settings"),
|
||||
browseThumbnail: $("#btn-thumbnail-file"),
|
||||
};
|
||||
|
||||
// Status text
|
||||
@@ -217,6 +219,7 @@ export class UploadModal {
|
||||
this.setupDescriptionMirror();
|
||||
this.setupMutuallyExclusiveCheckboxes(this.toggles.nsfw, this.toggles.kids);
|
||||
this.setupNsfwToContentWarning();
|
||||
this.setupThumbnailInput();
|
||||
|
||||
// Close
|
||||
this.closeButton.addEventListener("click", () => this.close());
|
||||
@@ -329,6 +332,27 @@ export class UploadModal {
|
||||
});
|
||||
}
|
||||
|
||||
setupThumbnailInput() {
|
||||
const { thumbnailFile, thumbnail } = this.inputs;
|
||||
const { browseThumbnail } = this.toggles;
|
||||
|
||||
if (!thumbnailFile || !browseThumbnail) return;
|
||||
|
||||
browseThumbnail.addEventListener("click", () => thumbnailFile.click());
|
||||
|
||||
thumbnailFile.addEventListener("change", () => {
|
||||
const file = thumbnailFile.files?.[0];
|
||||
if (file) {
|
||||
thumbnail.value = ""; // Clear explicit URL
|
||||
thumbnail.placeholder = `Selected: ${file.name}`;
|
||||
thumbnail.disabled = true;
|
||||
} else {
|
||||
thumbnail.placeholder = "https://example.com/thumbnail.jpg";
|
||||
thumbnail.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- R2 Integration ---
|
||||
|
||||
async loadR2Settings() {
|
||||
@@ -481,6 +505,8 @@ export class UploadModal {
|
||||
const file = this.inputs.file?.files?.[0];
|
||||
if (!file) throw new Error("Please select a video file to upload.");
|
||||
|
||||
const thumbnailFile = this.inputs.thumbnailFile?.files?.[0];
|
||||
|
||||
if (!this.hasValidR2Settings()) throw new Error("Please configure R2 storage credentials.");
|
||||
|
||||
const pubkey = this.getCurrentPubkey ? this.getCurrentPubkey() : null;
|
||||
@@ -491,6 +517,7 @@ export class UploadModal {
|
||||
await this.r2Service.uploadVideo({
|
||||
npub,
|
||||
file,
|
||||
thumbnailFile,
|
||||
metadata,
|
||||
settingsInput: this.collectSettingsForm(),
|
||||
publishVideoNote: this.publishVideoNote,
|
||||
@@ -546,6 +573,15 @@ export class UploadModal {
|
||||
this.toggles.nsfw.checked = false;
|
||||
this.toggles.kids.checked = false;
|
||||
this.updateProgress(null);
|
||||
|
||||
// Reset thumbnail UI
|
||||
if (this.inputs.thumbnail) {
|
||||
this.inputs.thumbnail.disabled = false;
|
||||
this.inputs.thumbnail.placeholder = "https://example.com/thumbnail.jpg";
|
||||
}
|
||||
if (this.inputs.thumbnailFile) {
|
||||
this.inputs.thumbnailFile.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
// --- Modal Control ---
|
||||
|
||||
Reference in new issue
Block a user