您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Script that loops the process of importing cards in order to allow multiple imports at once
// ==UserScript== // @name Import multiple decks to Duelingbook // @namespace http://tampermonkey.net/ // @version 1.9 // @description Script that loops the process of importing cards in order to allow multiple imports at once // @author Andrino Cauduro - https://github.com/AndrinoC // @match https://www.duelingbook.com/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // Define the inputOK function function inputOK() { hideDisplayBoxes(); input_callback && input_callback(); } // Create control panel const controlPanel = document.createElement('div'); controlPanel.style.position = 'fixed'; controlPanel.style.top = '10px'; controlPanel.style.right = '10px'; controlPanel.style.zIndex = '10000'; controlPanel.style.backgroundColor = 'white'; controlPanel.style.border = '1px solid black'; controlPanel.style.padding = '15px'; controlPanel.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.5)'; controlPanel.style.width = '150px'; controlPanel.style.textAlign = 'center'; controlPanel.style.transition = 'width 0.3s'; document.body.appendChild(controlPanel); // Create close button const closeButton = document.createElement('button'); closeButton.textContent = '×'; closeButton.style.position = 'absolute'; closeButton.style.top = '5px'; closeButton.style.left = '-5px'; closeButton.style.fontSize = '14px'; closeButton.style.border = 'none'; closeButton.style.backgroundColor = 'transparent'; closeButton.style.cursor = 'pointer'; closeButton.style.zIndex = '10001'; controlPanel.appendChild(closeButton); // Create File Input button (hidden) const fileInputButton = document.createElement('input'); fileInputButton.type = 'file'; fileInputButton.style.fontSize = '20px'; fileInputButton.style.width = '100%'; fileInputButton.style.display = 'none'; fileInputButton.multiple = true; fileInputButton.accept = '.ydk'; fileInputButton.id = 'file-input'; controlPanel.appendChild(fileInputButton); // Create Label to act as button const fileInputLabel = document.createElement('label'); fileInputLabel.textContent = 'Choose .ydk files'; fileInputLabel.htmlFor = 'file-input'; fileInputLabel.style.fontSize = '20px'; fileInputLabel.style.width = '100%'; fileInputLabel.style.display = 'inline-block'; fileInputLabel.style.backgroundColor = '#007bff'; fileInputLabel.style.cursor = 'pointer'; controlPanel.appendChild(fileInputLabel); // Create Status label const statusLabel = document.createElement('div'); statusLabel.style.position = 'relative'; statusLabel.textContent = 'Status: Waiting for file'; statusLabel.style.fontSize = '10px'; statusLabel.style.marginTop = '10px'; controlPanel.appendChild(statusLabel); // Function to transform YDK content to JSON function ydkToJson(ydkContent) { const main = []; const extra = []; const side = []; let section = 'main'; ydkContent.split('\n').forEach(line => { line = line.trim(); if (line === '#main') section = 'main'; else if (line === '#extra') section = 'extra'; else if (line === '!side') section = 'side'; else if (line && !line.startsWith('#')) { const cardId = parseInt(line, 10); if (!isNaN(cardId)) { if (section === 'main') main.push(cardId); else if (section === 'extra') extra.push(cardId); else if (section === 'side') side.push(cardId); } } }); return { main, extra, side }; } // Function to import YDK content function importYDK(ydkContent, deckName) { const { main, extra, side } = ydkToJson(ydkContent); window.importYDK = function(content) { const cardIds = { main: [], extra: [], side: [] }; const sections = { '#main': 'main', '#extra': 'extra', '!side': 'side' }; let section = 'main'; Object.entries(sections).forEach(([marker, type]) => { const start = content.indexOf(marker); const end = content.indexOf(Object.keys(sections).find(k => k !== marker), start + marker.length) || content.length; const sectionContent = content.slice(start + marker.length, end).trim(); sectionContent.split('\n').forEach(line => { const cardId = parseInt(line.trim(), 10); if (!isNaN(cardId)) cardIds[type].push(cardId); }); }); ['main', 'extra', 'side'].forEach(type => { cardIds[type] = cardIds[type].map(cardId => { const card = getCardByPasscode(cardId); return card ? card.id : null; }).filter(id => id !== null); }); importedCards = cardIds; importedDeckName = deckName; importDeckE(); inputOK(); }; window.importYDK(ydkContent); // Reset the file input button and update status fileInputButton.value = ''; statusLabel.textContent = 'Status: Ready for new file'; } // Function to process files (single .ydk or array of promises for .ydk files) function processFiles(files) { if (!Array.isArray(files)) files = [files]; let fileIndex = 0; const delay = 500; // Delay before processing the next file function importNextFile() { if (fileIndex < files.length) { files[fileIndex].then(({ content, name }) => { importYDK(content, name); fileIndex++; setTimeout(importNextFile, delay); }); } else { statusLabel.textContent = 'Status: All files processed'; } } importNextFile(); } // Function to extract deck name from file name function getDeckName(fileName) { return fileName.replace('.ydk', ''); } // Function to read file content and name function readFile(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => resolve({ content: e.target.result, name: getDeckName(file.name) }); reader.onerror = reject; reader.readAsText(file); }); } // Event listener for file input fileInputButton.addEventListener('change', (event) => { const files = Array.from(event.target.files); if (files.length > 0) { statusLabel.textContent = 'Status: Processing files...'; const ydkFiles = files.filter(file => file.name.endsWith('.ydk')); if (ydkFiles.length > 0) { processFiles(ydkFiles.map(readFile)); } else { statusLabel.textContent = 'Status: No .ydk files found'; } } }); // Minimize/Maximize functionality let isMinimized = false; closeButton.addEventListener('click', () => { if (isMinimized) { controlPanel.style.width = '150px'; statusLabel.style.display = 'block'; fileInputLabel.style.display = 'inline-block'; fileInputButton.style.display = 'none'; // Ensure file input button stays hidden } else { controlPanel.style.width = '30px'; statusLabel.style.display = 'none'; fileInputLabel.style.display = 'none'; fileInputButton.style.display = 'none'; } isMinimized = !isMinimized; }); })();