您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
this script will allow you to copy the content from the room and save notes at the bottom right of the page
// ==UserScript== // @license JazzMedo // @name TryHackMe Copy to Clipboard and add notes // @version 1.0.2 // @description this script will allow you to copy the content from the room and save notes at the bottom right of the page // @author JazzMedo // @match https://tryhackme.com/r/* // @include https://tryhackme.com/r/* // @icon https://www.google.com/s2/favicons?sz=64&domain=tryhackme.com // @grant none // @namespace https://greasyfork.org/users/1420266 // ==/UserScript== (function () { 'use strict'; setTimeout(() => { (function () { // Select all elements with data-sentry-component="AccordionDetails" const accordionDetailsList = document.querySelectorAll('[data-sentry-component="AccordionDetails"]'); // Function to get text excluding images and handling links const getTextExcludingImages = (element) => { let textContent = ''; // Loop through the child nodes of the element Array.from(element.childNodes).forEach((child) => { // Skip if the child or its parent is inside a <pre> tag const isInsidePre = (node) => { while (node && node !== element) { if (node.tagName === 'PRE' || node.tagName === 'pre') { return true; } node = node.parentNode; } return false; }; if (isInsidePre(child.nodeType === Node.TEXT_NODE ? child.parentNode : child)) { return; } // Only consider text nodes or elements that aren't images if (child.nodeType === Node.TEXT_NODE) { let text = child.textContent.trim(); if (text) { // Check if the parent element is a <p> tag const parentElement = child.parentElement; const isParagraph = parentElement && parentElement.tagName === 'P'; // Add newline if the text ends with a period in a <p> tag if ((isParagraph && text.trim(" ").endsWith('.')) || text.endsWith('?') || text.endsWith(':')) { textContent += text + '\n\n'; } else { textContent += text; } } } else if (child.nodeType === Node.ELEMENT_NODE && child.tagName !== 'IMG') { // Skip <pre> tags and their contents if (child.tagName === 'PRE' || child.tagName === 'pre') { return; } // If it's an element and not an image, recurse into it if (child.tagName === 'A' || child.tagName === 'a') { // If it's a link, add the text and a newline after it textContent += ' ' + child.textContent.trim() + ' '; } else if (child.tagName === 'B' || child.tagName === 'b') { // If the element is a <b> tag, add the text and a newline after the paragraph textContent += child.textContent.trim() + '\n\n'; } else if (child.tagName === 'span' || child.tagName === 'SPAN') { // If the element is a <b> tag, add the text and a newline after the paragraph textContent += " " + child.textContent.trim() + ' '; } else if (child.tagName === 'UL' || child.tagName === 'ul') { // Add newline after a <ul> tag textContent += getTextExcludingImages(child) + '\n'; } else if (child.tagName === 'LI' || child.tagName === 'li') { // Add newline after a <li> tag textContent += child.textContent.trim() + '\n'; } else if (child.tagName === 'P' || child.tagName === 'p') { // If <p> contains <b>, add \n\n before <p> if (child.querySelector('b') || child.querySelector('B')) { textContent += '\n\n' + getTextExcludingImages(child); } else { textContent += getTextExcludingImages(child) + '\n\n'; } } else if (child.tagName === 'TABLE' || child.tagName === 'table') { // Format the table content textContent += formatTable(child) + '\n\n'; // Call a new function to format the table } else if (child.tagName === 'DIV' || child.tagName === 'div') { // Add double newlines before and after the <div> content textContent += '\n\n' + getTextExcludingImages(child) + '\n\n'; } else if (child.tagName === 'H2' || child.tagName === 'h2') { // Add newline after <h2> tag textContent += child.textContent.trim() + '\n\n'; } else if (child.tagName === 'code' || child.tagName === 'CODE') { // Add newline after <h2> tag textContent += ' `' + child.textContent.trim() + '` '; } else { // Otherwise, continue recursively textContent += getTextExcludingImages(child); } } }); // Filter excessive newlines (replace \n\n\n with \n\n) textContent = textContent.replace(/\n{3,}/g, '\n\n'); return textContent; }; // New function to format the table function formatTable(table) { let formattedTable = '----------------------------\n'; const rows = table.querySelectorAll('tr'); rows.forEach((row) => { const cells = row.querySelectorAll('th, td'); const rowContent = Array.from(cells).map(cell => cell.textContent.trim()).join(' | '); // Join cell content with a separator formattedTable += '| ' + rowContent + ' |\n'; // Add a newline after each row }); // Add a newline after each row for separation formattedTable += '----------------------------\n'; // Ensure there's a newline after the last row return formattedTable; } // Loop through all the matched elements accordionDetailsList.forEach((accordionDetails) => { // Create a button for each AccordionDetails element const button = document.createElement('button'); // Replace text with SVG icon button.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path> </svg>`; button.title = 'Copy Text Only'; button.style.position = 'absolute'; button.style.bottom = '10px'; button.style.right = '10px'; // Position the button in the top-right corner // button.style.zIndex = '1000'; button.style.padding = '8px 8px 4px 8px'; // Make the button more square-shaped for the icon button.style.borderRadius = '5px'; button.style.backgroundColor = '#47acee'; // Green background button.style.color = 'white'; button.style.border = 'none'; button.style.cursor = 'pointer'; button.style.transition = 'all ease-in-out 0.3s'; // Position the region element relative to show the button correctly accordionDetails.style.position = 'relative'; // Add the button to the accordion details element accordionDetails.appendChild(button); // Flag to track whether the button was already clicked let isClicked = false; // Set up button click event to copy the text button.addEventListener('click', () => { if (isClicked) return; // Prevent further clicks if already clicked isClicked = true; // Mark as clicked let textContent = getTextExcludingImages(accordionDetails); // Use the Clipboard API to copy text if (textContent) { navigator.clipboard.writeText(textContent).then(() => { // Change button icon to checkmark when copied button.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <polyline points="20 6 9 17 4 12"></polyline> </svg>`; button.style.backgroundColor = '#4CAF50'; setTimeout(() => { // Reset to copy icon button.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path> </svg>`; button.style.backgroundColor = '#47acee'; isClicked = false; }, 1000); }).catch((err) => { console.error('Failed to copy text: ', err); isClicked = false; // Reset flag in case of error }); } }); }); // Inject CSS into the document const style = document.createElement('style'); style.innerHTML = ` pre { position: relative; /* Ensure the button is positioned relative to the pre block */ } .copy-button { position: absolute; bottom: 10px; right: 10px; background-color: #47acee; /* Dark yellow background */ color: white; border: none; padding: 8px 8px 4px; cursor: pointer; border-radius: 5px; transition: all ease-in-out 0.2s; /* Animation for button press */ } .copy-button:hover { background-color: #8cd1ff; /* Darker green on hover */ } .copy-button:active { transform: scale(0.95); /* Slightly shrink the button on click */ } `; document.head.appendChild(style); document.querySelectorAll('pre code').forEach(block => { const copyButton = document.createElement('button'); copyButton.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path> </svg>`; copyButton.className = 'copy-button'; // Add class for styling copyButton.title = 'Copy Commands Only'; block.parentElement.style.position = 'relative'; // Ensure the parent is positioned block.parentElement.appendChild(copyButton); copyButton.addEventListener('click', () => { const lines = block.innerText.split('\n'); const commands = lines.map(line => { if (line.includes('$ ')) { const parts = line.split('$ '); return parts.length > 1 ? parts[1] : ''; } else if (line.includes('>')) { const parts = line.split('>'); return parts.length > 1 ? parts[1].trim() : ''; } return ''; }).filter(command => command !== '').join('\n'); navigator.clipboard.writeText(commands).then(() => { const originalText = copyButton.innerHTML; copyButton.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <polyline points="20 6 9 17 4 12"></polyline> </svg>`; copyButton.style.backgroundColor = '#4CAF50'; setTimeout(() => { copyButton.innerHTML = originalText; copyButton.style.backgroundColor = '#47acee'; }, 2000); }); }); }); // تعديل مكان الزر العائم ليكون في الزاوية السفلى اليسرى// تعديل مكان الزر العائم ليكون في الزاوية السفلى اليسرى function createCommandPopupUI() { if (document.querySelector('#command-popup-ui')) return; const floatingButton = document.createElement('button'); floatingButton.id = 'floating-button'; floatingButton.innerHTML = `+`; floatingButton.style.position = 'fixed'; floatingButton.style.fontSize = '2rem'; floatingButton.style.bottom = '20px'; floatingButton.style.left = '20px'; // استخدام left بدلاً من right floatingButton.style.width = '33px'; floatingButton.style.height = '33px'; floatingButton.style.borderRadius = '5px'; floatingButton.style.border = 'none'; floatingButton.style.backgroundColor = '#61dafb'; floatingButton.style.color = 'white'; floatingButton.style.fontSize = '24px'; floatingButton.style.cursor = 'pointer'; floatingButton.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)'; floatingButton.style.zIndex = '9999'; floatingButton.style.transition = 'all ease-in-out 0.3s'; const popup = document.createElement('div'); popup.id = 'command-popup-ui'; popup.style.position = 'fixed'; popup.style.bottom = '80px'; popup.style.left = '20px'; // تغيير الموضع إلى يسار الصفحة popup.style.width = '400px'; popup.style.backgroundColor = '#282c34'; popup.style.color = 'white'; popup.style.padding = '15px'; popup.style.borderRadius = '8px'; popup.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)'; popup.style.display = 'none'; popup.style.zIndex = '9999'; const input = document.createElement('input'); input.type = 'text'; input.placeholder = 'Write you command here ...'; input.style.width = 'calc(100% - 50px)'; input.style.padding = '10px'; input.style.borderRadius = '4px'; input.style.border = 'none'; input.style.marginRight = '10px'; // Add keypress event listener for Enter key input.addEventListener('keypress', (event) => { if (event.key === 'Enter') { const command = input.value.trim(); if (command) { const originalContent = runButton.innerHTML; runButton.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <polyline points="20 6 9 17 4 12"></polyline> </svg>`; runButton.style.transform = 'scale(0.95)'; output.appendChild(createCommandElement(command)); saveCommand(command); input.value = ''; setTimeout(() => { runButton.innerHTML = originalContent; runButton.style.transform = 'scale(1)'; }, 1000); } } }); const inputContainer = document.createElement('div'); inputContainer.style.display = 'flex'; inputContainer.style.alignItems = 'center'; inputContainer.style.marginBottom = '10px'; const runButton = document.createElement('button'); runButton.innerText = "➕"; runButton.style.backgroundColor = '#61dafb'; runButton.style.color = '#282c34'; runButton.style.border = 'none'; runButton.style.padding = '10px'; runButton.style.borderRadius = '4px'; runButton.style.cursor = 'pointer'; runButton.style.width = '40px'; runButton.style.height = '38px'; const output = document.createElement('div'); output.style.marginTop = '10px'; output.style.fontSize = '14px'; output.style.overflowY = 'auto'; output.style.maxHeight = '200px'; output.style.transition = 'all 0.3s ease'; const savedCommands = JSON.parse(localStorage.getItem('commands')) || []; function createCommandElement(command) { const commandContainer = document.createElement('div'); commandContainer.style.display = 'flex'; commandContainer.style.alignItems = 'center'; commandContainer.style.marginBottom = '8px'; commandContainer.style.animation = 'slideIn 0.3s ease'; const commandText = document.createElement('div'); commandText.innerHTML = `$ ${command}`; commandText.style.color = '#61dafb'; commandText.style.flex = '1'; const buttonsContainer = document.createElement('div'); buttonsContainer.style.display = 'flex'; buttonsContainer.style.gap = '5px'; const cmdCopyBtn = document.createElement('button'); cmdCopyBtn.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path> </svg>`; cmdCopyBtn.style.backgroundColor = '#98c379'; cmdCopyBtn.style.color = 'white'; cmdCopyBtn.style.border = 'none'; cmdCopyBtn.style.padding = '8px 8px 4px'; cmdCopyBtn.style.borderRadius = '4px'; cmdCopyBtn.style.cursor = 'pointer'; cmdCopyBtn.style.fontSize = '12px'; cmdCopyBtn.style.marginLeft = '10px'; cmdCopyBtn.style.transition = 'transform 0.2s ease'; const deleteBtn = document.createElement('button'); deleteBtn.innerText = '🗑'; deleteBtn.style.backgroundColor = '#e06c75'; deleteBtn.style.color = 'white'; deleteBtn.style.border = 'none'; deleteBtn.style.padding = '5px 10px'; deleteBtn.style.borderRadius = '4px'; deleteBtn.style.cursor = 'pointer'; deleteBtn.style.fontSize = '12px'; deleteBtn.style.transition = 'transform 0.2s ease'; cmdCopyBtn.addEventListener('click', () => { navigator.clipboard.writeText(command); const originalSvg = cmdCopyBtn.innerHTML; cmdCopyBtn.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <polyline points="20 6 9 17 4 12"></polyline> </svg>`; cmdCopyBtn.style.transform = 'scale(0.95)'; setTimeout(() => { cmdCopyBtn.style.transform = 'scale(1)'; cmdCopyBtn.innerHTML = originalSvg; }, 1000); }); deleteBtn.addEventListener('click', () => { const originalContent = commandContainer.innerHTML; commandContainer.style.backgroundColor = '#ff000015'; commandContainer.innerHTML = ` <div style="display: flex; align-items: center; justify-content: space-between; width: 100%;"> <span style="color: #e06c75;">Are you sure you want to delete this command?</span> <div style="display: flex; gap: 8px;"> <button id="confirm-delete" style="background: #e06c75; border: none; color: white; padding: 5px 10px; border-radius: 4px; cursor: pointer;">Yes</button> <button id="cancel-delete" style="background: #98c379; border: none; color: white; padding: 5px 10px; border-radius: 4px; cursor: pointer;">No</button> </div> </div> `; const confirmBtn = commandContainer.querySelector('#confirm-delete'); const cancelBtn = commandContainer.querySelector('#cancel-delete'); confirmBtn.addEventListener('click', () => { commandContainer.style.animation = 'slideOut 0.3s ease'; setTimeout(() => { commandContainer.remove(); const index = savedCommands.indexOf(command); if (index > -1) { savedCommands.splice(index, 1); localStorage.setItem('commands', JSON.stringify(savedCommands)); } }, 280); }); cancelBtn.addEventListener('click', () => { commandContainer.style.backgroundColor = 'transparent'; commandContainer.innerHTML = originalContent; }); }); buttonsContainer.appendChild(cmdCopyBtn); buttonsContainer.appendChild(deleteBtn); commandContainer.appendChild(commandText); commandContainer.appendChild(buttonsContainer); return commandContainer; } savedCommands.forEach(command => { output.appendChild(createCommandElement(command)); }); function saveCommand(command) { savedCommands.push(command); localStorage.setItem('commands', JSON.stringify(savedCommands)); } runButton.addEventListener('click', () => { const command = input.value.trim(); if (command) { const originalContent = runButton.innerHTML; runButton.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <polyline points="20 6 9 17 4 12"></polyline> </svg>`; runButton.style.transform = 'scale(0.95)'; output.appendChild(createCommandElement(command)); saveCommand(command); input.value = ''; setTimeout(() => { runButton.innerHTML = originalContent; runButton.style.transform = 'scale(1)'; }, 1000); } }); floatingButton.addEventListener('click', () => { if (popup.style.display === 'none') { popup.style.display = 'block'; popup.style.opacity = '0'; popup.style.transform = 'scale(0.95) translateY(20px)'; floatingButton.innerHTML = `-`; floatingButton.style.backgroundColor = '#ffcdd2'; setTimeout(() => { popup.style.opacity = '1'; popup.style.transform = 'scale(1) translateY(0)'; }, 0); } else { popup.style.opacity = '0'; popup.style.transform = 'scale(0.95) translateY(20px)'; floatingButton.innerHTML = `+`; floatingButton.style.backgroundColor = '#61dafb'; setTimeout(() => { popup.style.display = 'none'; }, 300); } }); const style = document.createElement('style'); style.textContent = ` @keyframes slideIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideOut { from { opacity: 1; transform: translateX(0); } to { opacity: 0; transform: translateX(-100%); } } @keyframes popIn { 0% { transform: scale(0) rotate(-180deg); opacity: 0; } 100% { transform: scale(1) rotate(0deg); opacity: 1; } } #floating-button { transition: transform 0.3s ease; animation: popIn 0.5s ease; } #floating-button:hover { transform: scale(1.1); } #command-popup-ui { transition: opacity 0.3s ease, transform 0.3s ease; transform-origin: bottom left; } `; document.head.appendChild(style); inputContainer.appendChild(input); inputContainer.appendChild(runButton); popup.appendChild(inputContainer); popup.appendChild(output); document.body.appendChild(floatingButton); document.body.appendChild(popup); } createCommandPopupUI(); })(); }, 2000); // Delay the execution by 2 seconds // Your code here... })();