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;
});
})();