您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Take a nice shot of your deck!
// ==UserScript== // @name Master Duel Meta - Screenshot for Deck Builder // @namespace https://github.com/DonkeyBear // @version 0.2.6 // @description Take a nice shot of your deck! // @author DonkeyBear // @match http://www.masterduelmeta.com/deck-tester* // @match https://www.masterduelmeta.com/deck-tester* // @icon https://s3.duellinksmeta.com/img/icons/favicon-32x32.png // @require https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js // @grant none // ==/UserScript== const stylesheet = /* css */` .deck-container.taking-shot .new-card, .deck-container.taking-shot .adjust-buttons-container, .search-container.taking-shot { display: none !important; } .screenshot { object-fit: contain; max-width: 100vw; max-height: 100vh; } .overlay { position: fixed; top: 0; bottom: 0; left: 0; right: 0; background-color: rgba(0, 0, 0, .5); backdrop-filter: blur(3px); z-index: 999; display: flex; align-items: center; justify-content: center; } .info-container { font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: .75em; font-weight: 500; } .info-container .slot-info { color: white; } .slot-info, .card-count { flex-basis: auto !important; } .tag { color: white; padding: .1rem .4rem; border-radius: .25rem; margin-right: .25rem; } .tag.rarity-ur { background: linear-gradient(90deg, #c92ae7 0%, #7844fd 49%, #43bcd5 100%); } .tag.rarity-sr { background: linear-gradient(90deg, #e85504 0%, #f19d00 100%); } .tag.rarity-r { background: linear-gradient(90deg, #1831cc 0%, #017cfb 100%); } .tag.rarity-n { background: linear-gradient(90deg, #4f494b 0%, #969696 100%); } `; const style = document.createElement('style'); style.textContent = stylesheet; document.head.appendChild(style); // Append screenshot button const tabButtonContainer = document.querySelector('ul.svelte-umfxo'); const newTabButton = document.createElement('li'); newTabButton.classList.add('svelte-umfxo', 'screenshot-button'); newTabButton.textContent = 'Screenshot'; newTabButton.onclick = () => { takeshot() }; tabButtonContainer.appendChild(newTabButton); countCards(); const observer = {}; // Append screenshot button again if it's removed observer.tabButtonContainer = new MutationObserver(() => { if (!tabButtonContainer.querySelector('.screenshot-button')) { tabButtonContainer.appendChild(newTabButton); } }); observer.tabButtonContainer.observe(tabButtonContainer, { childList: true }); // Count cards and print observer.mainDeck = new MutationObserver(() => { countCards() }); observer.extraDeck = new MutationObserver(() => { countCards() }); observer.deckContainer = new MutationObserver(() => { // Append count-info again if it's removed if (document.querySelector('.deck-container > .info-container').textContent.includes('cards')) { countCards() } const mainDeck = document.querySelector('.deck-container > .box-container'); const extraDeck = document.querySelector('.extra-side-deck'); if (mainDeck) { observer.mainDeck.observe(mainDeck, { childList: true, subtree: true, attributes: true }) } if (extraDeck) { observer.extraDeck.observe(extraDeck, { childList: true, subtree: true, attributes: true }) } if (mainDeck && mainDeck) { observer.deckContainer.disconnect() } }); observer.deckContainer.observe(document.querySelector('.deck-container'), { childList: true }); function takeshot () { const deckContainer = document.querySelector('.deck-container'); const searchContainer = document.querySelector('.search-container'); deckContainer.classList.add('taking-shot'); searchContainer.classList.add('taking-shot'); const overlay = document.createElement('div'); overlay.classList.add('overlay'); overlay.onclick = () => { overlay.remove() }; document.body.appendChild(overlay); const options = { allowTaint: false, useCORS: true, backgroundColor: '#001b35', // Background color of <body> logging: false }; html2canvas(deckContainer.parentElement, options).then(canvas => { // eslint-disable-line no-undef canvas.classList.add('screenshot'); overlay.appendChild(canvas); }); deckContainer.classList.remove('taking-shot'); searchContainer.classList.remove('taking-shot'); } function countCards () { const counter = { main: 0, extra: 0, ur: 0, sr: 0, r: 0, n: 0 }; const mainDeckCards = document.querySelectorAll('.deck-container > .box-container > .card-container > .card'); const extraDeckCards = document.querySelectorAll('.extra-side-deck .card-container > .card'); for (const cards of [mainDeckCards, extraDeckCards]) { for (const card of cards) { if (!card.querySelector('img')) { break } let copies; const cardAmount = card.querySelector('img.card-amount'); if (!cardAmount) { copies = 1; } else if (cardAmount.alt.includes('2')) { copies = 2; } else if (cardAmount.alt.includes('3')) { copies = 3; } cards === mainDeckCards ? counter.main += copies : counter.extra += copies; const rarityImage = card.querySelector('.rarity-image > img'); if (!rarityImage) { break } switch (rarityImage.alt) { case 'UR Rarity': counter.ur += copies; break; case 'SR Rarity': counter.sr += copies; break; case 'R Rarity': counter.r += copies; break; case 'N Rarity': counter.n += copies; } } } const infoLeft = document.querySelector('.info-container .slot-info'); const infoRight = document.querySelector('.info-container .card-count'); infoLeft.innerHTML = /* html */` <span class="tag rarity-ur">${counter.ur} UR</span> <span class="tag rarity-sr">${counter.sr} SR</span> <span class="tag rarity-r">${counter.r} R</span> <span class="tag rarity-n">${counter.n} N</span> `; infoRight.textContent = `Main: ${counter.main} Extra: ${counter.extra}`; }