您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Encode or decode Base64 or Hex strings and copy to clipboard
- // ==UserScript==
- // @name Encode/Decode Base64 or Hex with Copy Option
- // @version 1.8
- // @description Encode or decode Base64 or Hex strings and copy to clipboard
- // @author itisme
- // @include https://*
- // @include http://*
- // @exclude *://youtube.com/*
- // @exclude *://github.com/*
- // @icon https://data.voz.vn/styles/next/xenforo/smilies/popopo/sexy_girl.png?v=01
- // @license GPL-3.0
- // @run_at document_idle
- // @grant GM_addStyle
- // @namespace http://tampermonkey.net/
- // ==/UserScript==
- (function() {
- 'use strict';
- GM_addStyle(`
- :root {
- --overlay-bg: rgba(0, 0, 0, 0.7);
- --overlay-color: #ffffff;
- --font-color: #333333;
- --close-color: #f44336;
- --close-hover-color: #d32f2f;
- --button-bg: #007bff;
- --button-active-bg: #0056b3;
- --copy-bg: #28a745;
- --copy-active-bg: #195427;
- --copy-hover-bg: #218838;
- --clear-bg: #dc3545;
- --clear-active-bg: #c82333;
- --shadow: 0 6px 12px rgba(0, 0, 0, 0.25);
- --transition: 0.3s ease;
- }
- .my-overlay-container {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: var(--overlay-bg);
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 99999;
- max-height: 100vh;
- overflow: auto;
- }
- .my-overlay {
- background: var(--overlay-color);
- padding: 20px;
- border-radius: 10px;
- width: 100%;
- max-width: 600px;
- position: relative;
- box-shadow: var(--shadow);
- transition: var(--transition);
- }
- .my-overlay-title {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 20px;
- position: relative;
- }
- .my-overlay-title-text {
- font-size: 26px;
- font-weight: 600;
- color: var(--font-color);
- }
- .my-overlay-titleCloser {
- font-size: 30px;
- cursor: pointer;
- color: var(--close-color);
- transition: var(--transition);
- }
- .my-overlay-titleCloser:hover {
- color: var(--close-hover-color);
- }
- .my-overlay-content {
- display: flex;
- flex-direction: column;
- }
- .my-overlay-content label {
- margin-bottom: 8px;
- font-weight: 600;
- font-size: 16px;
- }
- .my-overlay-content select,
- .my-overlay-content textarea {
- width: 100%;
- margin-bottom: 20px;
- padding: 12px;
- border: 1px solid #ccc;
- border-radius: 5px;
- box-sizing: border-box;
- }
- .my-overlay-content textarea {
- height: 120px;
- font-size: 16px;
- line-height: 1.5;
- resize: vertical;
- }
- .my-button-container {
- display: flex;
- gap: 20px;
- }
- .my-button-container button {
- padding: 12px 20px;
- font-size: 14px;
- border: none;
- border-radius: 5px;
- cursor: pointer;
- flex: 1;
- transition: background-color var(--transition), box-shadow var(--transition);
- box-shadow: var(--shadow);
- }
- #actionButton {
- background-color: var(--button-bg);
- color: #ffffff;
- }
- #actionButton:hover,
- #actionButton:active {
- background-color: var(--button-active-bg);
- }
- #copyButton {
- background-color: var(--copy-bg);
- color: #ffffff;
- }
- #copyButton:hover {
- background-color: var(--copy-hover-bg);
- }
- #copyButton:active {
- background-color: var(--copy-active-bg);
- }
- #copyButton.flash {
- animation: flash 1s;
- background-color: var(--copy-bg);
- }
- @keyframes flash {
- 0% {
- background-color: var(--copy-bg);
- }
- 100% {
- background-color: var(--copy-active-bg);
- }
- }
- .custom-popup-link {
- position: fixed;
- width: 40px;
- height: 40px;
- background-image: url("https://data.voz.vn/styles/next/xenforo/smilies/popopo/sexy_girl.png?v=01");
- background-size: cover;
- background-position: center;
- border: none;
- cursor: pointer;
- z-index: 2147483647;
- user-select: none;
- background-color: transparent;
- transition: background-color var(--transition);
- }
- `);
- const createToggleButton = () => {
- const toggleButton = document.createElement('button');
- toggleButton.className = 'custom-popup-link';
- document.body.appendChild(toggleButton);
- // Load saved position
- const savedPosition = JSON.parse(localStorage.getItem('toggleButtonPosition')) || {
- top: 673,
- left: 1468
- };
- Object.assign(toggleButton.style, {
- top: `${savedPosition.top}px`,
- left: `${savedPosition.left}px`
- });
- makeDraggable(toggleButton);
- };
- const makeDraggable = (element) => {
- if (!element) return console.error('Phần tử không tồn tại.');
- let offsetX, offsetY, startX, startY, isDragging = false;
- element.style.userSelect = 'none';
- const setPosition = (x, y) => {
- element.style.left = `${x}px`;
- element.style.top = `${y}px`;
- };
- const moveElement = (e) => {
- if (!isDragging) {
- if (Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5) {
- isDragging = true;
- }
- return;
- }
- const rect = element.getBoundingClientRect();
- const windowWidth = window.innerWidth;
- const windowHeight = window.innerHeight;
- let newLeft = e.clientX - offsetX;
- let newTop = e.clientY - offsetY;
- newLeft = Math.max(0, Math.min(newLeft, windowWidth - rect.width));
- newTop = Math.max(0, Math.min(newTop, windowHeight - rect.height));
- setPosition(newLeft, newTop);
- };
- const stopDragging = (e) => {
- if (isDragging) {
- localStorage.setItem('toggleButtonPosition', JSON.stringify({
- top: element.style.top,
- left: element.style.left
- }));
- } else if (e.button === 0 && typeof toggleOverlay === 'function') {
- toggleOverlay();
- }
- document.removeEventListener('mousemove', moveElement);
- document.removeEventListener('mouseup', stopDragging);
- document.removeEventListener('mouseleave', stopDragging);
- isDragging = false;
- };
- const startDragging = (e) => {
- if (e.button !== 0) return;
- const rect = element.getBoundingClientRect();
- offsetX = e.clientX - rect.left;
- offsetY = e.clientY - rect.top;
- startX = e.clientX;
- startY = e.clientY;
- document.addEventListener('mousemove', moveElement);
- document.addEventListener('mouseup', stopDragging);
- document.addEventListener('mouseleave', stopDragging);
- };
- element.addEventListener('mousedown', startDragging);
- const savedPosition = JSON.parse(localStorage.getItem('toggleButtonPosition'));
- if (savedPosition) {
- setPosition(
- parseFloat(savedPosition.left) || 0,
- parseFloat(savedPosition.top) || 0
- );
- }
- };
- window.addEventListener('load', () => {
- const toggleButton = document.querySelector('.toggleButtonClass');
- if (toggleButton) {
- makeDraggable(toggleButton);
- }
- });
- const toggleOverlay = () => {
- const overlayContainer = document.querySelector('.my-overlay-container');
- if (overlayContainer) {
- overlayContainer.style.display = (overlayContainer.style.display === 'none') ? 'flex' : 'none';
- } else if (typeof createOverlay === 'function') {
- createOverlay();
- const newOverlayContainer = document.querySelector('.my-overlay-container');
- if (newOverlayContainer) {
- newOverlayContainer.style.display = 'flex';
- } else {
- console.error('Không thể tìm thấy phần tử .my-overlay-container sau khi tạo.');
- }
- } else {
- console.error('Hàm createOverlay không tồn tại.');
- }
- };
- const createOverlay = () => {
- const overlayContainer = document.createElement('div');
- overlayContainer.className = 'my-overlay-container';
- overlayContainer.innerHTML = `
- <div class="my-overlay">
- <div class="my-overlay-title">
- <span class="my-overlay-title-text">Encode/Decode Input</span>
- <a class="my-overlay-titleCloser" role="button" aria-label="Close">×</a>
- </div>
- <div class="my-overlay-content">
- <label>Select Operation:</label>
- <select id="operationType">
- <option value="decode">Decode</option>
- <option value="encode">Encode</option>
- </select>
- <label>Select Type:</label>
- <select id="decodeType">
- <option value="hex">Hex</option>
- <option value="base64">Base64</option>
- </select>
- <textarea id="inputString" placeholder="Enter text..."></textarea>
- <textarea id="resultOutput" readonly placeholder="Result..."></textarea>
- <div class="my-button-container">
- <button id="actionButton">Decode/Encode</button>
- <button id="copyButton">Copy</button>
- </div>
- </div>
- </div>
- `;
- document.body.appendChild(overlayContainer);
- const closeButton = document.querySelector('.my-overlay-titleCloser');
- closeButton.addEventListener('click', () => {
- overlayContainer.style.display = 'none';
- document.getElementById('inputString').value = '';
- document.getElementById('resultOutput').value = '';
- document.getElementById('operationType').value = "decode";
- document.getElementById('decodeType').value = "hex";
- });
- const encodeHex = s => Array.from(s, c => c.charCodeAt(0).toString(16).padStart(2, '0')).join(' ').toUpperCase();
- const decodeHex = h => {
- try {
- const cleanedHex = h.replace(/\s+/g, '');
- if (!/^[a-fA-F0-9]+$/.test(cleanedHex)) throw new Error('Invalid hex string');
- if (cleanedHex.length % 2 !== 0) throw new Error('Invalid hex string length');
- return cleanedHex.match(/../g).map(b => String.fromCharCode(parseInt(b, 16))).join('');
- } catch (err) {
- throw new Error(err.message);
- }
- };
- const encodeBase64 = b => btoa(b);
- const decodeBase64 = b => {
- try {
- if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/.test(b)) {
- throw new Error('Invalid base64 string');
- }
- return atob(b);
- } catch (err) {
- throw new Error(err.message);
- }
- };
- document.getElementById('actionButton').addEventListener('click', () => {
- const op = document.getElementById('operationType').value;
- const type = document.getElementById('decodeType').value;
- const input = document.getElementById('inputString').value.trim();
- if (!input) return alert('Please enter a string.');
- try {
- let result;
- switch (type) {
- case 'base64':
- result = (op === 'decode') ? decodeBase64(input) : encodeBase64(input);
- break;
- case 'hex':
- result = (op === 'decode') ? decodeHex(input) : encodeHex(input);
- break;
- default:
- result = (op === 'decode') ? decodeURIComponent(input) : encodeURIComponent(input);
- }
- document.getElementById('resultOutput').value = result;
- } catch (err) {
- console.error(`Error [${type}]:`, err, 'Input:', input);
- alert(`Error: ${err.message}`);
- }
- });
- document.getElementById('copyButton').addEventListener('click', async () => {
- const resultOutput = document.getElementById('resultOutput');
- const textToCopy = resultOutput.value.trim();
- if (!textToCopy) {
- alert('Nothing to copy!');
- return;
- }
- try {
- await navigator.clipboard.writeText(textToCopy);
- alert('Copied to clipboard!');
- const copyButton = document.getElementById('copyButton');
- copyButton.classList.add('flash');
- setTimeout(() => copyButton.classList.remove('flash'), 1000);
- } catch (err) {
- console.error('Error copying to clipboard:', err);
- alert('Error copying to clipboard.');
- }
- });
- }
- createToggleButton();
- })();