Here's the code I have. Can you make it so it can also copy the frame of a paused video, if the video has played at least a little. Also can you conjoin the node to the menu. So that when the button is pressed in the node, the menu div appears relative and above the node div. With style attributes like it's a speech div. With a little upside down triangle at the bottom of the menu div pointing towards the node div. Can you also make it so that when the save or copy button is pressed, if successful. The save and copy buttons to disappear and be replaced with a green tick and then for the menu to disappear. Inversely if every save or copy method fails for there to be a red tick. "// ==UserScript==
// @name My Stash Video JS CopySave
// @namespace https://github.com/7dJx1qP/stash-userscripts
// @version 0.3
// @description Adds performer suggestions based on similar tags.
// @author QxxxGit
// @match http://localhost:9999/\*
// @include \*
// @require https://raw.githubusercontent.com/7dJx1qP/stash-userscripts/master/src\StashUserscriptLibrary.js
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js
// @grant unsafeWindow
// @grant GM\_getResourceText
// @grant GM\_addStyle
// @grant GM\_setClipboard
// @grant GM\_download
// @run-at document-idle
// ==/UserScript==
(function() {
 'use strict';
 const {
 stash,
 Stash,
 waitForElementId,
 waitForElementClass,
 waitForElementByXpath,
 getElementByXpath,
 getClosestAncestor,
 updateTextInput,
 } = unsafeWindow.stash;

 stash.addEventListener("page:scene", async function() {
 if (!document.getElementById('video-js-copySave')) {

 await waitForElementClass("vjs-control-bar", async function(className, el) {
 const node = document.createElement("div");
 node.innerHTML = "Hellp

"
 const control = document.querySelector('.vjs-control-bar');
 node.setAttribute('id', 'video-js-copySave');
 control.appendChild(node);
 control.insertBefore(node, control.childNodes[9]);

 await waitForElementByXpath("//div[contains(@class, 'VideoPlayer')]", function(xpath, el) {

 // Create the button to capture the video frame
 const button = document.createElement("button");
 button.innerHTML = "Capture Frame";
 button.style.position = "relative";
 button.style.bottom = "20px";
 button.style.right = "20px";
 button.style.zIndex = "9999";
 button.style.backgroundColor = "#333";
 button.style.color = "#fff";
 button.style.padding = "10px 20px";
 button.style.border = "none";
 button.style.borderRadius = "5px";
 button.style.cursor = "pointer";

 // Append the button to the body
 node.appendChild(button);

 // Listen for clicks on the button
 button.addEventListener("click", function() {
 console.log("Click")
 // Get all video elements on the page
 const videos = document.getElementsByTagName("video");
 console.log("videos: " + videos)

 // Check if there are any videos playing
 for (let i = 0; i < videos.length; i++) {
 if (!videos[i].paused) {
 console.log("videos playing: ")

 // Get the canvas element to draw the current video frame
 const canvas = document.createElement("canvas");
 canvas.width = videos[i].videoWidth;
 canvas.height = videos[i].videoHeight;
 const ctx = canvas.getContext("2d");
 ctx.drawImage(videos[i], 0, 0, canvas.width, canvas.height);

 // Create the options menu to save or copy the image
 const menu = document.createElement("div");
 menu.style.position = "fixed";
 menu.style.top = "50%";
 menu.style.left = "50%";
 menu.style.transform = "translate(-50%, -50%)";
 menu.style.backgroundColor = "#333";
 menu.style.color = "#fff";
 menu.style.padding = "20px";
 menu.style.borderRadius = "5px";
 menu.style.zIndex = "9999";

 // Create the save button
 const saveButton = document.createElement("button");
 saveButton.innerHTML = "Save";
 saveButton.style.marginRight = "10px";
 saveButton.style.backgroundColor = "#fff";
 saveButton.style.color = "#333";
 saveButton.style.padding = "10px 20px";
 saveButton.style.border = "none";
 saveButton.style.borderRadius = "5px";
 saveButton.style.cursor = "pointer";
 saveButton.addEventListener("click", function() {
 GM\_download({
 url: canvas.toDataURL(),
 name: "video\_frame.png",
 saveAs: true
 });
 menu.remove();
 });
 menu.appendChild(saveButton);

 // Create the copy button
 const copyButton = document.createElement("button");
 copyButton.innerHTML = "Copy";
 copyButton.style.backgroundColor = "#fff";
 copyButton.style.color = "#333";
 copyButton.style.padding = "10px 20px";
 copyButton.style.border = "none";
 copyButton.style.borderRadius = "5px";
 copyButton.style.cursor = "pointer";
copyButton.addEventListener("click", function() {
 setTimeout(function() {
 var canvas = document.createElement("canvas");
 var video = document.querySelector("video");
 canvas.width = video.videoWidth;
 canvas.height = video.videoHeight;
 canvas.getContext("2d").drawImage(video, 0, 0, canvas.width, canvas.height);

 if (navigator.clipboard) {
 navigator.clipboard.writeText(canvas.toDataURL("image/jpeg")).then(function() {
 console.log("Image copied to clipboard successfully");
 // Display success toast notification
 }, function(error) {
 console.error("Failed to copy image to clipboard: " + error);
 // Display error toast notification
 });
 } else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
 var imageData = canvas.toDataURL("image/jpeg");
 var tempInput = document.createElement("input");
 tempInput.style = "position: absolute; left: -1000px; top: -1000px";
 tempInput.value = imageData;
 document.body.appendChild(tempInput);
 tempInput.select();
 document.execCommand("copy");
 document.body.removeChild(tempInput);
 console.log("Image copied to clipboard successfully");
 // Display success toast notification
 } else {
 console.error("Clipboard API not supported");
 // Use GM\_setClipboard as a last resort
 }
 }, 50);
menu.remove();
});
 menu.appendChild(copyButton);

 // Append the options menu to the body
 document.body.appendChild(menu);
 break;
 }
 }
 });
})
 })
 }
 })
})
 ();
"
제가 가진 코드는 다음과 같습니다. 동영상이 조금이라도 재생된 경우 일시 정지된 동영상의 프레임도 복사할 수 있도록 만들 수 있나요? 또한 노드를 메뉴에 연결할 수 있습니까? 노드에서 버튼을 누르면 메뉴 div가 노드 div 위에 상대적으로 표시되도록 할 수 있습니다. 음성 div와 같은 스타일 속성을 사용합니다. 메뉴 div 하단에 노드 div를 가리키는 작은 거꾸로 된 삼각형이 있습니다. 저장 또는 복사 버튼을 눌렀을 때 성공하면 사라지도록 만들 수도 있나요? 저장 및 복사 버튼이 사라지고 녹색 체크 표시로 바뀐 다음 메뉴가 사라지도록 할 수 있습니다. 반대로 모든 저장 또는 복사 메서드가 실패하면 빨간색 체크 표시가 나타납니다. "// ==UserScript==
// @name 내 보관함 비디오 JS 복사 저장
// @namespace https://github.com/7dJx1qP/stash-userscripts
// @버전 0.3
// @description 유사한 태그를 기반으로 출연자 제안을 추가합니다.
// @author QxxxGit
// @match http://localhost:9999/\*
// @include \*
// @require https://raw.githubusercontent.com/7dJx1qP/stash-userscripts/master/src\StashUserscriptLibrary.js
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js
// @grant unsafeWindow
// @grant GM\_getResourceText
// @grant GM\_addStyle
// @grant GM\_setClipboard
// @grant GM\_download
// @run-at document-idle
// ==/UserScript==
(function() {
 'use strict';
 const {
 stash,
 Stash,
 waitForElementId,
 waitForElementClass,
 waitForElementByXpath,
 getElementByXpath,
 가장 가까운 조상,
 업데이트 텍스트 입력,
 } = unsafeWindow.stash;

 stash.addEventListener("page:scene", async function() {
 if (!document.getElementById('video-js-copySave')) {

 await waitForElementClass("vjs-control-bar", async function(className, el) {
 const node = document.createElement("div");
 node.innerHTML = "헬프

"
 const control = document.querySelector('.vjs-control-bar');
 node.setAttribute('id', 'video-js-copySave');
 control.appendChild(node);
 control.insertBefore(node, control.childNodes[9]);

 await waitForElementByXpath("//div[contains(@class, 'VideoPlayer')]", function(xpath, el) { // 버튼을 생성합니다.

 // 비디오 프레임을 캡처하는 버튼을 생성합니다.
 const button = document.createElement("button");
 button.innerHTML = "프레임 캡처";
 button.style.position = "상대적";
 button.style.bottom = "20px";
 button.style.right = "20px";
 button.style.zIndex = "9999";
 button.style.backgroundColor = "#333";
 button.style.color = "#fff";
 button.style.padding = "10px 20px";
 button.style.border = "none";
 button.style.borderRadius = "5px";
 button.style.cursor = "포인터";

 // 본문에 버튼 추가
 node.appendChild(button);

 // 버튼 클릭을 수신합니다.
 button.addEventListener("click", function() {
 console.log("클릭")
 // 페이지의 모든 동영상 요소 가져오기
 const videos = document.getElementsByTagName("video");
 console.log("videos: " + videos)

 // 재생 중인 동영상이 있는지 확인
 for (let i = 0; i < videos.length; i++) {
 if (!videos[i].paused) {
 console.log("동영상 재생 중: ")

 // 현재 비디오 프레임을 그릴 캔버스 요소를 가져옵니다.
 const canvas = document.createElement("canvas");
 canvas.width = videos[i].videoWidth;
 canvas.height = videos[i].videoHeight;
 const ctx = canvas.getContext("2d");
 ctx.drawImage(videos[i], 0, 0, canvas.width, canvas.height);

 // 이미지를 저장하거나 복사할 수 있는 옵션 메뉴를 생성합니다.
 const menu = document.createElement("div");
 menu.style.position = "고정";
 menu.style.top = "50%";
 menu.style.left = "50%";
 menu.style.transform = "translate(-50%, -50%)";
 menu.style.backgroundColor = "#333";
 menu.style.color = "#fff";
 menu.style.padding = "20px";
 menu.style.borderRadius = "5px";
 menu.style.zIndex = "9999";

 // 저장 버튼 생성
 const saveButton = document.createElement("button");
 saveButton.innerHTML = "저장";
 saveButton.style.marginRight = "10px";
 saveButton.style.backgroundColor = "#fff";
 saveButton.style.color = "#333";
 saveButton.style.padding = "10px 20px";
 saveButton.style.border = "none";
 saveButton.style.borderRadius = "5px";
 saveButton.style.cursor = "포인터";
 saveButton.addEventListener("click", function() {
 GM\_download({
 url: canvas.toDataURL(),
 name: "video\_frame.png",
 saveAs: true
 });
 menu.remove();
 });
 menu.appendChild(saveButton);

 // 복사 버튼 생성
 const copyButton = document.createElement("button");
 copyButton.innerHTML = "복사";
 copyButton.style.backgroundColor = "#fff";
 copyButton.style.color = "#333";
 copyButton.style.padding = "10px 20px";
 copyButton.style.border = "none";
 copyButton.style.borderRadius = "5px";
 copyButton.style.cursor = "포인터";
copyButton.addEventListener("click", function() {
 setTimeout(function() {
 var canvas = document.createElement("캔버스");
 var video = document.querySelector("video");
 canvas.width = video.videoWidth;
 canvas.height = video.videoHeight;
 canvas.getContext("2d").drawImage(video, 0, 0, canvas.width, canvas.height);

 if (navigator.clipboard) {
 navigator.clipboard.writeText(canvas.toDataURL("image/jpeg")).then(function() 