Run Prettier on other Thrimbletrimmer files

It had not been run in previous PRs
pull/449/head
ElementalAlchemist 3 weeks ago committed by Christopher Usher
parent c8899f5133
commit fc82b2b17f

@ -5,7 +5,7 @@
<title>VST Video Editor</title> <title>VST Video Editor</title>
<link rel="stylesheet" href="styles/thrimbletrimmer.css" /> <link rel="stylesheet" href="styles/thrimbletrimmer.css" />
<link rel="stylesheet" href="styles/jcrop.css"> <link rel="stylesheet" href="styles/jcrop.css" />
<script src="scripts/hls.min.js"></script> <script src="scripts/hls.min.js"></script>
<script src="scripts/luxon.min.js"></script> <script src="scripts/luxon.min.js"></script>
@ -258,15 +258,17 @@
<div class="video-info-thumbnail-mode-options" id="video-info-thumbnail-position-options"> <div class="video-info-thumbnail-mode-options" id="video-info-thumbnail-position-options">
<details> <details>
<summary>Advanced Templating Options</summary> <summary>Advanced Templating Options</summary>
Crop specifies the region of the video frame to capture. <br/> Crop specifies the region of the video frame to capture. <br />
Location specifies the region within the template image where the cropped image will be placed. <br/> Location specifies the region within the template image where the cropped image will
Regions are given as pixel coordinates of the top-left and bottom-right corners. <br/> be placed. <br />
Note that if the regions are different sizes, the image will be stretched. <br/> Regions are given as pixel coordinates of the top-left and bottom-right corners.
<br />
Note that if the regions are different sizes, the image will be stretched. <br />
<button id="video-info-thumbnail-template-source-image-update"> <button id="video-info-thumbnail-template-source-image-update">
Update Source Images Update Source Images
</button> </button>
<br/> <br />
<div class="video-info-thumbnail-advanced-crop-flex-wrapper"> <div class="video-info-thumbnail-advanced-crop-flex-wrapper">
<div class="video-info-thumbnail-advanced-crop-flex-item"> <div class="video-info-thumbnail-advanced-crop-flex-item">
@ -274,23 +276,41 @@
id="video-info-thumbnail-template-video-source-image" id="video-info-thumbnail-template-video-source-image"
class="hidden" class="hidden"
alt="Thumbnail preview image" alt="Thumbnail preview image"
height="360" width="640" height="360"
width="640"
/> />
<br/> <br />
Crop: Crop:
<input type="text" class="video-info-thumbnail-position" id="video-info-thumbnail-crop-0" /> <input
<input type="text" class="video-info-thumbnail-position" id="video-info-thumbnail-crop-1" /> type="text"
class="video-info-thumbnail-position"
id="video-info-thumbnail-crop-0"
/>
<input
type="text"
class="video-info-thumbnail-position"
id="video-info-thumbnail-crop-1"
/>
to to
<input type="text" class="video-info-thumbnail-position" id="video-info-thumbnail-crop-2" /> <input
<input type="text" class="video-info-thumbnail-position" id="video-info-thumbnail-crop-3" /> type="text"
<br/> class="video-info-thumbnail-position"
id="video-info-thumbnail-crop-2"
/>
<input
type="text"
class="video-info-thumbnail-position"
id="video-info-thumbnail-crop-3"
/>
<br />
</div> </div>
<div class="video-info-thumbnail-advanced-crop-flex-item hidden" id="video-info-thumbnail-aspect-ratio-controls"> <div
class="video-info-thumbnail-advanced-crop-flex-item hidden"
id="video-info-thumbnail-aspect-ratio-controls"
>
<div class="video-info-thumbnail-advanced-crop-flex-column"> <div class="video-info-thumbnail-advanced-crop-flex-column">
<div> <div>Aspect Ratio</div>
Aspect Ratio
</div>
<div> <div>
<button id="video-info-thumbnail-aspect-ratio-match-right"> <button id="video-info-thumbnail-aspect-ratio-match-right">
--Match-&gt; --Match-&gt;
@ -303,7 +323,7 @@
</div> </div>
<div> <div>
<label> <label>
<input type="checkbox" id="video-info-thumbnail-lock-aspect-ratio"> <input type="checkbox" id="video-info-thumbnail-lock-aspect-ratio" />
Lock Lock
</label> </label>
</div> </div>
@ -315,19 +335,35 @@
id="video-info-thumbnail-template-overlay-image" id="video-info-thumbnail-template-overlay-image"
class="hidden" class="hidden"
alt="Thumbnail preview image" alt="Thumbnail preview image"
height="360" width="640" height="360"
width="640"
/> />
<br/> <br />
Location: Location:
<input type="text" class="video-info-thumbnail-position" id="video-info-thumbnail-location-0" /> <input
<input type="text" class="video-info-thumbnail-position" id="video-info-thumbnail-location-1" /> type="text"
class="video-info-thumbnail-position"
id="video-info-thumbnail-location-0"
/>
<input
type="text"
class="video-info-thumbnail-position"
id="video-info-thumbnail-location-1"
/>
to to
<input type="text" class="video-info-thumbnail-position" id="video-info-thumbnail-location-2" /> <input
<input type="text" class="video-info-thumbnail-position" id="video-info-thumbnail-location-3" /> type="text"
<br/> class="video-info-thumbnail-position"
id="video-info-thumbnail-location-2"
/>
<input
type="text"
class="video-info-thumbnail-position"
id="video-info-thumbnail-location-3"
/>
<br />
</div> </div>
</div> </div>
</details> </details>
</div> </div>
<div <div

@ -222,7 +222,9 @@ window.addEventListener("DOMContentLoaded", async (event) => {
} }
} }
document.getElementById("range-definition-chapter-marker-first-description").addEventListener("input", (event) => { document
.getElementById("range-definition-chapter-marker-first-description")
.addEventListener("input", (event) => {
validateChapterDescription(event.target); validateChapterDescription(event.target);
}); });
document.getElementById("video-info-title").addEventListener("input", (event) => { document.getElementById("video-info-title").addEventListener("input", (event) => {
@ -269,7 +271,9 @@ window.addEventListener("DOMContentLoaded", async (event) => {
document document
.getElementById("video-info-thumbnail-template-source-image-update") .getElementById("video-info-thumbnail-template-source-image-update")
.addEventListener("click", async (_event) => { .addEventListener("click", async (_event) => {
const videoFrameImageElement = document.getElementById("video-info-thumbnail-template-video-source-image"); const videoFrameImageElement = document.getElementById(
"video-info-thumbnail-template-video-source-image",
);
const timeEntryElement = document.getElementById("video-info-thumbnail-time"); const timeEntryElement = document.getElementById("video-info-thumbnail-time");
const imageTime = wubloaderTimeFromVideoHumanTime(timeEntryElement.value); const imageTime = wubloaderTimeFromVideoHumanTime(timeEntryElement.value);
@ -285,51 +289,80 @@ window.addEventListener("DOMContentLoaded", async (event) => {
videoFrameImageElement.src = `/frame/${globalStreamName}/source.png?${videoFrameQuery}`; videoFrameImageElement.src = `/frame/${globalStreamName}/source.png?${videoFrameQuery}`;
videoFrameImageElement.classList.remove("hidden"); videoFrameImageElement.classList.remove("hidden");
const templateImageElement = document.getElementById("video-info-thumbnail-template-overlay-image"); const templateImageElement = document.getElementById(
"video-info-thumbnail-template-overlay-image",
);
templateImageElement.src = `/thrimshim/template/${imageTemplate}.png`; templateImageElement.src = `/thrimshim/template/${imageTemplate}.png`;
templateImageElement.classList.remove("hidden"); templateImageElement.classList.remove("hidden");
const aspectRatioControls = document.getElementById("video-info-thumbnail-aspect-ratio-controls"); const aspectRatioControls = document.getElementById(
"video-info-thumbnail-aspect-ratio-controls",
);
aspectRatioControls.classList.remove("hidden"); aspectRatioControls.classList.remove("hidden");
createTemplateCropWidgets(); createTemplateCropWidgets();
}); });
document.getElementById("video-info-thumbnail-crop-0").addEventListener("input", updateTemplateCropWidgets); document
document.getElementById("video-info-thumbnail-crop-1").addEventListener("input", updateTemplateCropWidgets); .getElementById("video-info-thumbnail-crop-0")
document.getElementById("video-info-thumbnail-crop-2").addEventListener("input", updateTemplateCropWidgets); .addEventListener("input", updateTemplateCropWidgets);
document.getElementById("video-info-thumbnail-crop-3").addEventListener("input", updateTemplateCropWidgets); document
document.getElementById("video-info-thumbnail-location-0").addEventListener("input", updateTemplateCropWidgets); .getElementById("video-info-thumbnail-crop-1")
document.getElementById("video-info-thumbnail-location-1").addEventListener("input", updateTemplateCropWidgets); .addEventListener("input", updateTemplateCropWidgets);
document.getElementById("video-info-thumbnail-location-2").addEventListener("input", updateTemplateCropWidgets); document
document.getElementById("video-info-thumbnail-location-3").addEventListener("input", updateTemplateCropWidgets); .getElementById("video-info-thumbnail-crop-2")
.addEventListener("input", updateTemplateCropWidgets);
document
.getElementById("video-info-thumbnail-crop-3")
.addEventListener("input", updateTemplateCropWidgets);
document
.getElementById("video-info-thumbnail-location-0")
.addEventListener("input", updateTemplateCropWidgets);
document
.getElementById("video-info-thumbnail-location-1")
.addEventListener("input", updateTemplateCropWidgets);
document
.getElementById("video-info-thumbnail-location-2")
.addEventListener("input", updateTemplateCropWidgets);
document
.getElementById("video-info-thumbnail-location-3")
.addEventListener("input", updateTemplateCropWidgets);
document.getElementById("video-info-thumbnail-lock-aspect-ratio").addEventListener("change", updateTemplateCropAspectRatio); document
.getElementById("video-info-thumbnail-lock-aspect-ratio")
.addEventListener("change", updateTemplateCropAspectRatio);
document.getElementById("video-info-thumbnail-aspect-ratio-match-right").addEventListener("click", function(){ document
.getElementById("video-info-thumbnail-aspect-ratio-match-right")
.addEventListener("click", function () {
// Calculate and copy the aspect ratio from the video field to the template // Calculate and copy the aspect ratio from the video field to the template
const videoFieldX1 = document.getElementById("video-info-thumbnail-crop-0"); const videoFieldX1 = document.getElementById("video-info-thumbnail-crop-0");
const videoFieldY1 = document.getElementById("video-info-thumbnail-crop-1"); const videoFieldY1 = document.getElementById("video-info-thumbnail-crop-1");
const videoFieldX2 = document.getElementById("video-info-thumbnail-crop-2"); const videoFieldX2 = document.getElementById("video-info-thumbnail-crop-2");
const videoFieldY2 = document.getElementById("video-info-thumbnail-crop-3"); const videoFieldY2 = document.getElementById("video-info-thumbnail-crop-3");
const videoFieldAspectRatio = (videoFieldX2.value-videoFieldX1.value)/(videoFieldY2.value-videoFieldY1.value); const videoFieldAspectRatio =
(videoFieldX2.value - videoFieldX1.value) / (videoFieldY2.value - videoFieldY1.value);
templateStage.setOptions({aspectRatio: videoFieldAspectRatio}); templateStage.setOptions({ aspectRatio: videoFieldAspectRatio });
// Re-apply the locked/unlocked status // Re-apply the locked/unlocked status
updateTemplateCropAspectRatio(); updateTemplateCropAspectRatio();
}); });
document.getElementById("video-info-thumbnail-aspect-ratio-match-left").addEventListener("click", function(){ document
.getElementById("video-info-thumbnail-aspect-ratio-match-left")
.addEventListener("click", function () {
// Calculate and copy the aspect ratio from the template to the video field // Calculate and copy the aspect ratio from the template to the video field
const templateFieldX1 = document.getElementById("video-info-thumbnail-location-0"); const templateFieldX1 = document.getElementById("video-info-thumbnail-location-0");
const templateFieldY1 = document.getElementById("video-info-thumbnail-location-1"); const templateFieldY1 = document.getElementById("video-info-thumbnail-location-1");
const templateFieldX2 = document.getElementById("video-info-thumbnail-location-2"); const templateFieldX2 = document.getElementById("video-info-thumbnail-location-2");
const templateFieldY2 = document.getElementById("video-info-thumbnail-location-3"); const templateFieldY2 = document.getElementById("video-info-thumbnail-location-3");
const templateFieldAspectRatio = (templateFieldX2.value-templateFieldX1.value)/(templateFieldY2.value-templateFieldY1.value); const templateFieldAspectRatio =
(templateFieldX2.value - templateFieldX1.value) /
(templateFieldY2.value - templateFieldY1.value);
videoFrameStage.setOptions({aspectRatio: templateFieldAspectRatio}); videoFrameStage.setOptions({ aspectRatio: templateFieldAspectRatio });
// Re-apply the locked/unlocked status // Re-apply the locked/unlocked status
updateTemplateCropAspectRatio(); updateTemplateCropAspectRatio();
@ -375,7 +408,7 @@ window.addEventListener("DOMContentLoaded", async (event) => {
const thumbnailTemplatesListResponse = await fetch("/thrimshim/templates"); const thumbnailTemplatesListResponse = await fetch("/thrimshim/templates");
if (thumbnailTemplatesListResponse.ok) { if (thumbnailTemplatesListResponse.ok) {
const thumbnailTemplatesList = await thumbnailTemplatesListResponse.json(); const thumbnailTemplatesList = await thumbnailTemplatesListResponse.json();
const templateNames = thumbnailTemplatesList.map(t => t.name); const templateNames = thumbnailTemplatesList.map((t) => t.name);
templateNames.sort(); templateNames.sort();
for (const template of thumbnailTemplatesList) { for (const template of thumbnailTemplatesList) {
thumbnailTemplates[template.name] = template; thumbnailTemplates[template.name] = template;
@ -401,7 +434,8 @@ window.addEventListener("DOMContentLoaded", async (event) => {
} }
if (videoInfo.thumbnail_location !== null) { if (videoInfo.thumbnail_location !== null) {
for (let i = 0; i < 4; i++) { for (let i = 0; i < 4; i++) {
document.getElementById(`video-info-thumbnail-location-${i}`).value = videoInfo.thumbnail_location[i]; document.getElementById(`video-info-thumbnail-location-${i}`).value =
videoInfo.thumbnail_location[i];
} }
} }
document.getElementById("video-info-thumbnail-mode").value = videoInfo.thumbnail_mode; document.getElementById("video-info-thumbnail-mode").value = videoInfo.thumbnail_mode;
@ -479,11 +513,12 @@ window.addEventListener("DOMContentLoaded", async (event) => {
}); });
}); });
async function loadTransitions() { async function loadTransitions() {
const response = await fetch("/thrimshim/transitions"); const response = await fetch("/thrimshim/transitions");
if (!response.ok) { if (!response.ok) {
addError("Failed to fetch possible transition types. This probably means the wubloader host is down."); addError(
"Failed to fetch possible transition types. This probably means the wubloader host is down.",
);
return; return;
} }
knownTransitions = await response.json(); knownTransitions = await response.json();
@ -776,8 +811,12 @@ async function initializeVideoInfo() {
if (rangeIndex > 0) { if (rangeIndex > 0) {
const transition = videoInfo.video_transitions[rangeIndex - 1]; const transition = videoInfo.video_transitions[rangeIndex - 1];
const transitionType = rangeContainer.getElementsByClassName("range-transition-type")[0]; const transitionType = rangeContainer.getElementsByClassName("range-transition-type")[0];
const transitionDuration = rangeContainer.getElementsByClassName("range-transition-duration")[0]; const transitionDuration = rangeContainer.getElementsByClassName(
const transitionDurationSection = rangeContainer.getElementsByClassName("range-transition-duration-section")[0]; "range-transition-duration",
)[0];
const transitionDurationSection = rangeContainer.getElementsByClassName(
"range-transition-duration-section",
)[0];
if (transition === null) { if (transition === null) {
transitionType.value = ""; transitionType.value = "";
transitionDuration.value = ""; transitionDuration.value = "";
@ -796,7 +835,7 @@ async function initializeVideoInfo() {
const option = document.createElement("option"); const option = document.createElement("option");
option.value = type; option.value = type;
option.textContent = type; option.textContent = type;
transitionType.append(option) transitionType.append(option);
} }
// Set type and duration. // Set type and duration.
transitionType.value = type; transitionType.value = type;
@ -1062,11 +1101,13 @@ function validateChapterDescription(chapterDescField) {
if (chapterDesc.indexOf("<") !== -1 || chapterDesc.indexOf(">") !== -1) { if (chapterDesc.indexOf("<") !== -1 || chapterDesc.indexOf(">") !== -1) {
chapterDescField.classList.add("input-error"); chapterDescField.classList.add("input-error");
chapterDescField.title = "Chapter description may not contain angle brackets (< or >)"; chapterDescField.title = "Chapter description may not contain angle brackets (< or >)";
} else if (Array.from(chapterDesc).some(c => c.charCodeAt(0) > 127)) { // any char is non-ascii } else if (Array.from(chapterDesc).some((c) => c.charCodeAt(0) > 127)) {
// any char is non-ascii
// We don't know what chars are safe outside the ascii range, so we just warn on any of them. // We don't know what chars are safe outside the ascii range, so we just warn on any of them.
// We know emoji are not safe. // We know emoji are not safe.
chapterDescField.classList.add("input-error"); chapterDescField.classList.add("input-error");
chapterDescField.title = "Chapter descriptions with non-ascii characters may cause issues; proceed with caution"; chapterDescField.title =
"Chapter descriptions with non-ascii characters may cause issues; proceed with caution";
} else { } else {
chapterDescField.classList.remove("input-error"); chapterDescField.classList.remove("input-error");
chapterDescField.title = ""; chapterDescField.title = "";
@ -1115,7 +1156,9 @@ async function sendVideoData(newState, overrideChanges) {
const transitionTypeElements = rangeContainer.getElementsByClassName("range-transition-type"); const transitionTypeElements = rangeContainer.getElementsByClassName("range-transition-type");
if (transitionTypeElements.length > 0) { if (transitionTypeElements.length > 0) {
const transitionType = transitionTypeElements[0].value; const transitionType = transitionTypeElements[0].value;
const transitionDurationStr = rangeContainer.getElementsByClassName("range-transition-duration")[0].value; const transitionDurationStr = rangeContainer.getElementsByClassName(
"range-transition-duration",
)[0].value;
if (transitionType === "") { if (transitionType === "") {
transitions.push(null); transitions.push(null);
} else { } else {
@ -1123,11 +1166,13 @@ async function sendVideoData(newState, overrideChanges) {
// but 0 is an error here anyway. // but 0 is an error here anyway.
// Note that !(x > 0) is not equivalent to (x <= 0) due to NaN. // Note that !(x > 0) is not equivalent to (x <= 0) due to NaN.
const transitionDuration = Number(transitionDurationStr); const transitionDuration = Number(transitionDurationStr);
if ( !(transitionDuration > 0) ) { if (!(transitionDuration > 0)) {
submissionError(`Couldn't submit edits: Invalid transition duration: "${transitionDurationStr}"`); submissionError(
`Couldn't submit edits: Invalid transition duration: "${transitionDurationStr}"`,
);
return; return;
} }
transitions.push([transitionType, transitionDuration]) transitions.push([transitionType, transitionDuration]);
// Since we're overlapping with the previous range, this range's start time is // Since we're overlapping with the previous range, this range's start time is
// actually earlier. This matters for chapter markers. // actually earlier. This matters for chapter markers.
rangeStartInFinalVideo -= transitionDuration; rangeStartInFinalVideo -= transitionDuration;
@ -1186,7 +1231,9 @@ async function sendVideoData(newState, overrideChanges) {
continue; continue;
} }
if (startFieldTime < rangeStartPlayer || startFieldTime > rangeEndPlayer) { if (startFieldTime < rangeStartPlayer || startFieldTime > rangeEndPlayer) {
submissionError(`The chapter at "${startField.value}" is outside its containing time range.`); submissionError(
`The chapter at "${startField.value}" is outside its containing time range.`,
);
return; return;
} }
const chapterStartTime = rangeStartInFinalVideo + startFieldTime - rangeStartPlayer; const chapterStartTime = rangeStartInFinalVideo + startFieldTime - rangeStartPlayer;
@ -1494,7 +1541,7 @@ async function uploadedImageToBase64() {
const fileLoadData = fileReader.result; const fileLoadData = fileReader.result;
if (fileLoadData.error) { if (fileLoadData.error) {
throw new Error( throw new Error(
`An error (${fileLoadData.error.name}) occurred loading the thumbnail: ${fileLoadData.error.message}` `An error (${fileLoadData.error.name}) occurred loading the thumbnail: ${fileLoadData.error.message}`,
); );
} }
if (fileLoadData.substring(0, 22) !== "data:image/png;base64,") { if (fileLoadData.substring(0, 22) !== "data:image/png;base64,") {
@ -1536,7 +1583,7 @@ async function renderThumbnail() {
} }
// Converting the result into base64 is similarly painful. // Converting the result into base64 is similarly painful.
const blob = await res.blob(); const blob = await res.blob();
const data = await new Promise(resolve => { const data = await new Promise((resolve) => {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = () => resolve(reader.result); reader.onload = () => resolve(reader.result);
reader.readAsDataURL(blob); reader.readAsDataURL(blob);
@ -1558,13 +1605,15 @@ function updateDownloadLink() {
const transitionTypeElements = rangeContainer.getElementsByClassName("range-transition-type"); const transitionTypeElements = rangeContainer.getElementsByClassName("range-transition-type");
if (transitionTypeElements.length > 0) { if (transitionTypeElements.length > 0) {
const transitionType = transitionTypeElements[0].value; const transitionType = transitionTypeElements[0].value;
const transitionDurationStr = rangeContainer.getElementsByClassName("range-transition-duration")[0].value; const transitionDurationStr = rangeContainer.getElementsByClassName(
"range-transition-duration",
)[0].value;
if (transitionType === "") { if (transitionType === "") {
transitions.push(""); transitions.push("");
} else { } else {
let transitionDuration = Number(transitionDurationStr); let transitionDuration = Number(transitionDurationStr);
// We don't have a sensible way to error out here, so default invalid durations to 1s // We don't have a sensible way to error out here, so default invalid durations to 1s
if ( !(transitionDuration > 0) ) { if (!(transitionDuration > 0)) {
transitionDuration = 1; transitionDuration = 1;
} }
transitions.push(`${transitionType},${transitionDuration}`); transitions.push(`${transitionType},${transitionDuration}`);
@ -1711,8 +1760,11 @@ function makeElement(tag, classes = [], values = {}) {
function rangeDefinitionDOM() { function rangeDefinitionDOM() {
// Shortcut builder for image-based buttons // Shortcut builder for image-based buttons
const button = (cls, src, alt) => makeElement("img", [cls, "click"], { const button = (cls, src, alt) =>
src, alt, title: alt, makeElement("img", [cls, "click"], {
src,
alt,
title: alt,
}); });
const rangeContainer = makeElement("div", ["range-definition-removable"]); const rangeContainer = makeElement("div", ["range-definition-removable"]);
@ -1731,7 +1783,10 @@ function rangeDefinitionDOM() {
updateTransitionTypes([transitionType]); updateTransitionTypes([transitionType]);
// Duration always starts hidden because type always starts as cut. // Duration always starts hidden because type always starts as cut.
const transitionDurationSection = makeElement("div", ["range-transition-duration-section", "hidden"]); const transitionDurationSection = makeElement("div", [
"range-transition-duration-section",
"hidden",
]);
// Add/remove hidden when type changes // Add/remove hidden when type changes
transitionType.addEventListener("change", (event) => { transitionType.addEventListener("change", (event) => {
if (transitionType.value === "") { if (transitionType.value === "") {
@ -1754,7 +1809,7 @@ function rangeDefinitionDOM() {
transitionContainer.append("Transition: ", transitionType, transitionDurationSection); transitionContainer.append("Transition: ", transitionType, transitionDurationSection);
const rangeTimesContainer = makeElement("div", ["range-definition-times"]); const rangeTimesContainer = makeElement("div", ["range-definition-times"]);
const rangeStart = makeElement("input", ["range-definition-start"], {type: "text"}); const rangeStart = makeElement("input", ["range-definition-start"], { type: "text" });
const rangeStartSet = button( const rangeStartSet = button(
"range-definition-set-start", "range-definition-set-start",
"images/pencil.png", "images/pencil.png",
@ -1766,7 +1821,7 @@ function rangeDefinitionDOM() {
"Play from start point", "Play from start point",
); );
const rangeTimeGap = makeElement("div", ["range-definition-between-time-gap"]); const rangeTimeGap = makeElement("div", ["range-definition-between-time-gap"]);
const rangeEnd = makeElement("input", ["range-definition-end"], {type: "text"}); const rangeEnd = makeElement("input", ["range-definition-end"], { type: "text" });
const rangeEndSet = button( const rangeEndSet = button(
"range-definition-set-end", "range-definition-set-end",
"images/pencil.png", "images/pencil.png",
@ -1777,11 +1832,7 @@ function rangeDefinitionDOM() {
"images/play_to.png", "images/play_to.png",
"Play from end point", "Play from end point",
); );
const removeRange = button( const removeRange = button("range-definition-remove", "images/minus.png", "Remove range");
"range-definition-remove",
"images/minus.png",
"Remove range",
);
if (canEditVideo()) { if (canEditVideo()) {
rangeStartSet.addEventListener("click", getRangeSetClickHandler("start")); rangeStartSet.addEventListener("click", getRangeSetClickHandler("start"));
@ -2239,20 +2290,20 @@ function isNonVideoInput(element) {
*/ */
function createTemplateCropWidgets() { function createTemplateCropWidgets() {
if (videoFrameStage == null) { if (videoFrameStage == null) {
videoFrameStage = Jcrop.attach('video-info-thumbnail-template-video-source-image'); videoFrameStage = Jcrop.attach("video-info-thumbnail-template-video-source-image");
videoFrameStage.listen('crop.update',function(widget,e){ videoFrameStage.listen("crop.update", function (widget, e) {
const pos = widget.pos; const pos = widget.pos;
const fieldX1 = document.getElementById("video-info-thumbnail-crop-0"); const fieldX1 = document.getElementById("video-info-thumbnail-crop-0");
const fieldY1 = document.getElementById("video-info-thumbnail-crop-1"); const fieldY1 = document.getElementById("video-info-thumbnail-crop-1");
const fieldX2 = document.getElementById("video-info-thumbnail-crop-2"); const fieldX2 = document.getElementById("video-info-thumbnail-crop-2");
const fieldY2 = document.getElementById("video-info-thumbnail-crop-3"); const fieldY2 = document.getElementById("video-info-thumbnail-crop-3");
// 640x320 -> 1920x1080 // 640x320 -> 1920x1080
fieldX1.value = Math.round(pos.x*3); fieldX1.value = Math.round(pos.x * 3);
fieldY1.value = Math.round(pos.y*3); fieldY1.value = Math.round(pos.y * 3);
fieldX2.value = Math.round((pos.x+pos.w)*3); fieldX2.value = Math.round((pos.x + pos.w) * 3);
fieldY2.value = Math.round((pos.y+pos.h)*3); fieldY2.value = Math.round((pos.y + pos.h) * 3);
}); });
videoFrameStage.listen('crop.change',function(widget,e){ videoFrameStage.listen("crop.change", function (widget, e) {
// This only fires when the user is finished dragging, not every time the size // This only fires when the user is finished dragging, not every time the size
// of the cropped area updates. This avoids the template area updating every // of the cropped area updates. This avoids the template area updating every
// instant due to minute changes in the aspect ratio, which causes it to shrink // instant due to minute changes in the aspect ratio, which causes it to shrink
@ -2261,18 +2312,18 @@ function createTemplateCropWidgets() {
}); });
} }
if (templateStage == null) { if (templateStage == null) {
templateStage = Jcrop.attach('video-info-thumbnail-template-overlay-image'); templateStage = Jcrop.attach("video-info-thumbnail-template-overlay-image");
templateStage.listen('crop.update',function(widget,e){ templateStage.listen("crop.update", function (widget, e) {
const pos = widget.pos; const pos = widget.pos;
const fieldX1 = document.getElementById("video-info-thumbnail-location-0"); const fieldX1 = document.getElementById("video-info-thumbnail-location-0");
const fieldY1 = document.getElementById("video-info-thumbnail-location-1"); const fieldY1 = document.getElementById("video-info-thumbnail-location-1");
const fieldX2 = document.getElementById("video-info-thumbnail-location-2"); const fieldX2 = document.getElementById("video-info-thumbnail-location-2");
const fieldY2 = document.getElementById("video-info-thumbnail-location-3"); const fieldY2 = document.getElementById("video-info-thumbnail-location-3");
// 640x320 -> 1280x720 // 640x320 -> 1280x720
fieldX1.value = Math.round(pos.x*2); fieldX1.value = Math.round(pos.x * 2);
fieldY1.value = Math.round(pos.y*2); fieldY1.value = Math.round(pos.y * 2);
fieldX2.value = Math.round((pos.x+pos.w)*2); fieldX2.value = Math.round((pos.x + pos.w) * 2);
fieldY2.value = Math.round((pos.y+pos.h)*2); fieldY2.value = Math.round((pos.y + pos.h) * 2);
}); });
} }
@ -2290,7 +2341,12 @@ function updateTemplateCropWidgets() {
const videoFieldX2 = document.getElementById("video-info-thumbnail-crop-2"); const videoFieldX2 = document.getElementById("video-info-thumbnail-crop-2");
const videoFieldY2 = document.getElementById("video-info-thumbnail-crop-3"); const videoFieldY2 = document.getElementById("video-info-thumbnail-crop-3");
// Video frame: 640x360 -> 1920x1080 // Video frame: 640x360 -> 1920x1080
const videoFrameRect = Jcrop.Rect.create(videoFieldX1.value/3, videoFieldY1.value/3, (videoFieldX2.value-videoFieldX1.value)/3, (videoFieldY2.value-videoFieldY1.value)/3); const videoFrameRect = Jcrop.Rect.create(
videoFieldX1.value / 3,
videoFieldY1.value / 3,
(videoFieldX2.value - videoFieldX1.value) / 3,
(videoFieldY2.value - videoFieldY1.value) / 3,
);
if (videoFrameStage.active == null) { if (videoFrameStage.active == null) {
videoFrameStage.newWidget(videoFrameRect); videoFrameStage.newWidget(videoFrameRect);
} else { } else {
@ -2303,7 +2359,12 @@ function updateTemplateCropWidgets() {
const templateFieldX2 = document.getElementById("video-info-thumbnail-location-2"); const templateFieldX2 = document.getElementById("video-info-thumbnail-location-2");
const templateFieldY2 = document.getElementById("video-info-thumbnail-location-3"); const templateFieldY2 = document.getElementById("video-info-thumbnail-location-3");
// Template: 640x360 -> 1280x720 // Template: 640x360 -> 1280x720
const templateRect = Jcrop.Rect.create(templateFieldX1.value/2, templateFieldY1.value/2, (templateFieldX2.value-templateFieldX1.value)/2, (templateFieldY2.value-templateFieldY1.value)/2); const templateRect = Jcrop.Rect.create(
templateFieldX1.value / 2,
templateFieldY1.value / 2,
(templateFieldX2.value - templateFieldX1.value) / 2,
(templateFieldY2.value - templateFieldY1.value) / 2,
);
if (templateStage.active == null) { if (templateStage.active == null) {
templateStage.newWidget(templateRect); templateStage.newWidget(templateRect);
} else { } else {
@ -2321,11 +2382,12 @@ function updateTemplateCropAspectRatio() {
const videoFieldY1 = document.getElementById("video-info-thumbnail-crop-1"); const videoFieldY1 = document.getElementById("video-info-thumbnail-crop-1");
const videoFieldX2 = document.getElementById("video-info-thumbnail-crop-2"); const videoFieldX2 = document.getElementById("video-info-thumbnail-crop-2");
const videoFieldY2 = document.getElementById("video-info-thumbnail-crop-3"); const videoFieldY2 = document.getElementById("video-info-thumbnail-crop-3");
const videoFieldAspectRatio = (videoFieldX2.value-videoFieldX1.value)/(videoFieldY2.value-videoFieldY1.value); const videoFieldAspectRatio =
videoFrameStage.setOptions({aspectRatio: videoFieldAspectRatio}); (videoFieldX2.value - videoFieldX1.value) / (videoFieldY2.value - videoFieldY1.value);
templateStage.setOptions({aspectRatio: videoFieldAspectRatio}); videoFrameStage.setOptions({ aspectRatio: videoFieldAspectRatio });
templateStage.setOptions({ aspectRatio: videoFieldAspectRatio });
} else { } else {
videoFrameStage.setOptions({aspectRatio: null}); videoFrameStage.setOptions({ aspectRatio: null });
templateStage.setOptions({aspectRatio: null}); templateStage.setOptions({ aspectRatio: null });
} }
} }

@ -137,7 +137,7 @@ function generateDownloadURL(startTime, endTime, downloadType, allowHoles, quali
const query = new URLSearchParams({ const query = new URLSearchParams({
type: downloadType, type: downloadType,
allow_holes: allowHoles allow_holes: allowHoles,
}); });
if (startURLTime) { if (startURLTime) {
query.append("start", startURLTime); query.append("start", startURLTime);

Loading…
Cancel
Save