diff --git a/thrimbletrimmer/edit.html b/thrimbletrimmer/edit.html index c2ab6f6..3a3e5c8 100644 --- a/thrimbletrimmer/edit.html +++ b/thrimbletrimmer/edit.html @@ -190,6 +190,43 @@ + +
+
+ +
+
+ +
+
+ + Set video thumbnail frame to current video time + Set video time to video thumbnail frame +
+ +
diff --git a/thrimbletrimmer/scripts/edit.js b/thrimbletrimmer/scripts/edit.js index 7c5a022..ae5ce9f 100644 --- a/thrimbletrimmer/scripts/edit.js +++ b/thrimbletrimmer/scripts/edit.js @@ -195,6 +195,40 @@ window.addEventListener("DOMContentLoaded", async (event) => { document.getElementById("video-info-description").addEventListener("input", (_event) => { validateVideoDescription(); }); + document.getElementById("video-info-thumbnail-mode").addEventListener("change", () => { + const newValue = document.getElementById("video-info-thumbnail-mode").value; + const unhideIDs = []; + + if (newValue === "BARE") { + unhideIDs.push("video-info-thumbnail-time-options"); + } else if (newValue === "TEMPLATE") { + unhideIDs.push("video-info-thumbnail-template-options"); + unhideIDs.push("video-info-thumbnail-time-options"); + } else if (newValue === "CUSTOM") { + unhideIDs.push("video-info-thumbnail-custom-options"); + } + + document.getElementsByClassName("video-info-thumbnail-mode-options").classList.add("hidden"); + for (elemID of unhideIDs) { + document.getElementById(elemID).classList.remove("hidden"); + } + }); + document.getElementById("video-info-thumbnail-time-set").addEventListener("click", (_event) => { + const field = document.getElementById("video-info-thumbnail-time"); + const videoPlayer = document.getElementById("video"); + const videoPlayerTime = videoPlayer.currentTime; + field.value = videoHumanTimeFromVideoPlayerTime(videoPlayerTime); + }); + document.getElementById("video-info-thumbnail-time-play").addEventListener("click", (_event) => { + const field = document.getElementById("video-info-thumbnail-time"); + const thumbnailTime = videoPlayerTimeFromVideoHumanTime(field.value); + if (thumbnailTime === null) { + addError("Couldn't play from thumbnail frame; failed to parse time"); + return; + } + const videoPlayer = document.getElementById("video"); + videoPlayer.currentTime = thumbnailTime; + }); document.getElementById("submit-button").addEventListener("click", (_event) => { submitVideo(); @@ -789,6 +823,53 @@ async function sendVideoData(newState, overrideChanges) { videoDescription = videoDescription + CHAPTER_MARKER_DELIMITER + chapterTextList.join("\n"); } + const thumbnailMode = document.getElementById("video-info-thumbnail-mode").value; + let thumbnailTemplate = null; + let thumbnailTime = null; + let thumbnailImage = null; + if (thumbnailMode === "BARE" || thumbnailMode === "TEMPLATE") { + thumbnailTime = wubloaderTimeFromVideoHumanTime( + document.getElementById("video-info-thumbnail-time").value + ); + if (thumbnailTime === null) { + submissionResponseElem.innerText = "The thumbnail time is invalid"; + submissionResponseElem.classList.value = ["submission-response-error"]; + return; + } + } + if (thumbnailMode === "TEMPLATE") { + thumbnailTemplate = document.getElementById("video-info-thumbnail-template").value; + } + if (thumbnailMode === "CUSTOM") { + const fileInput = document.getElementById("video-info-thumbnail-custom"); + if (fileInput.files.length === 0) { + submissionResponseElem.innerText = + "A thumbnail file was not provided for the custom thumbnail"; + submissionResponseElem.classList.value = ["submission-response-error"]; + return; + } + const fileHandle = fileInput.files[0]; + const fileReader = new FileReader(); + let loadPromiseResolve; + const loadPromise = new Promise((resolve, _reject) => { + loadPromiseResolve = resolve; + }); + fileReader.addEventListener("loadend", (event) => { + loadPromiseResolve(event.target); + }); + fileReader.readAsArrayBuffer(fileHandle); + const fileLoadData = await loadPromise; + if (fileLoadData.error) { + submissionResponseElem.innerText = `An error (${fileLoadData.error.name}) occurred loading the custom thumbnail: ${fileLoadData.error.message}`; + submissionResponseElem.classList.value = ["submission-response-error"]; + return; + } + const fileData = fileLoadData.result; + const fileBytes = new Uint8Array(fileData); + const fileBinaryString = String.fromCharCode(...fileBytes); + thumbnailImage = btoa(fileBinaryString); + } + const videoTitle = document.getElementById("video-info-title").value; const videoTags = document.getElementById("video-info-tags").value.split(","); const allowHoles = document.getElementById("advanced-submission-option-allow-holes").checked; @@ -814,6 +895,10 @@ async function sendVideoData(newState, overrideChanges) { video_quality: videoInfo.video_quality, uploader_whitelist: uploaderAllowlist, state: newState, + thumbnail_mode: thumbnailMode, + thumbnail_template: thumbnailTemplate, + thumbnail_time: thumbnailTime, + thumbnail_image: thumbnailImage, // We also provide some sheet column values to verify data hasn't changed. sheet_name: videoInfo.sheet_name,