您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Script to help solve Jigidi puzzles, by rendering columns in a colourful grid gradient, and marking each piece with numbers.
// ==UserScript== // @name Jigidi Bingo Solver // @namespace to.soon.userjs.jigidi // @match https://www.jigidi.com/solve* // @match https://www.jigidi.com/s/* // @grant GM_getValue // @grant GM_setValue // @version 1.4 // @author Fox <https://github.com/f-o> // @description Script to help solve Jigidi puzzles, by rendering columns in a colourful grid gradient, and marking each piece with numbers. // @license MIT // ==/UserScript== (function () { 'use strict'; // Custom Gradients array: var gradientsArray = { "Rainbow": ['#FF0000', '#FFFF00', '#00FF00', '#0000FF'], "Distinct": ['#191970', '#006400', '#ff0000', '#00ff00', '#00ffff', '#ff00ff', '#ffb6c1'], "Rastafari": ['#1E9600', "#FFF200", "#FF0000"], "Sublime Vivid": ['#FC466B', "#3F5EFB"], "DanQ": ['#FF0000', '#EE82EE'], "Instagram": ['#833ab4', "#fd1d1d", "#fcb045"], "Hacker": ['#ff0000', "#000000", "#00ff11", "#000000", "#0077ff"] } const $verbose = false; function generateSpectrum(rows, colors) { if (!Array.isArray(colors) || colors.length < 2) { throw new Error('Colors array must have at least two colors.'); } const spectrum = []; const numColors = colors.length - 1; // Number of gradients between colors const increment = numColors / (rows - 1); // Increment between adjacent rows for (let i = 0; i < rows; i++) { const colorIndex = Math.floor(i * increment); // Index of the color gradient const startColor = colors[colorIndex]; // Start color of the gradient const endColor = colors[Math.min(colorIndex + 1, colors.length - 1)]; // End color of the gradient const t = (i * increment) % 1; // Interpolation parameter spectrum.push(interpolateColors(startColor, endColor, t)); // Interpolate color } return spectrum; } function interpolateColors(color1, color2, t) { // Extract RGB components of the colors const [r1, g1, b1] = color1.match(/\w\w/g).map(hex => parseInt(hex, 16)); const [r2, g2, b2] = color2.match(/\w\w/g).map(hex => parseInt(hex, 16)); // Interpolate RGB components const r = Math.round(r1 + (r2 - r1) * t); const g = Math.round(g1 + (g2 - g1) * t); const b = Math.round(b1 + (b2 - b1) * t); // Convert interpolated RGB components to hex format return '#' + [r, g, b].map(component => component.toString(16).padStart(2, '0')).join(''); } // Wait for page to load window.addEventListener('load', function () { // If URL ends with "solve.php", get the puzzle ID from a tag under h1.puzzle-title and redirect if (window.location.href.endsWith('solve.php')) { const puzzleId = document.querySelector('h1.puzzle-title').querySelector('a').href; window.location.href = puzzleId.replace('https://www.jigidi.com/jigsaw-puzzle/', 'https://www.jigidi.com/solve/'); } // If URL contains "/s/", get the puzzle ID from share-url and redirect else if (window.location.href.includes('/s/')) { // Loop through all script tags and find the one containing "ShareEmbed.url" for (const script of document.querySelectorAll('script')) { if (script.innerText.includes('ShareEmbed.url')) { const puzzleId = script.innerText.match(/ShareEmbed.url = "(.+)";/)[1]; window.location.href = puzzleId; break; } } } // Prepare Bingo Solver UI const JigidiBingoSolver = document.createElement('div'); JigidiBingoSolver.id = 'jigidi-bingo-solver'; // Inject Bingo Solver UI after the tool info panel const creatorElem = document.getElementById('tool-info-panel'); creatorElem.after(JigidiBingoSolver); // Cleanup the page const elementWithAds = document.querySelector('.show-ad'); if (elementWithAds) { elementWithAds.classList.remove('show-ad'); if ($verbose) { console.log('Removed element with class "show-ad".'); } } // Get the canvas element const canvas = document.querySelector('canvas'); if (!canvas) { if ($verbose) { console.log('Canvas not found.'); } // Sleep for 2 seconds and try again setTimeout(() => { window.location.reload(); }, 2000); return; } // Global settings const bingoSolverSettingsGlobal = GM_getValue('bingoSolverSettingsGlobal', { showNumbers: true, showColours: true, showColoursBy: 'length', gradient: 'Rainbow', fontSize: 26 }); // Unique jigsaw ID settings const jigsawId = window.location.href.match(/solve\/(\w+)\//)[1]; const bingoSolverSettings = GM_getValue(`bingoSolverSettings_${jigsawId}`, { col: 1 }); // Log settings if ($verbose) { console.log(`Bingo Solver: jigsawId=${jigsawId}`); console.log(`Bingo Solver: bingoSolverSettingsGlobal=${JSON.stringify(bingoSolverSettingsGlobal)}`); console.log(`Bingo Solver: bingoSolverSettings=${JSON.stringify(bingoSolverSettings)}`); } const jDimensions = creatorElem.innerText.match(/(\d+)×(\d+)/); const jCols = parseInt(jDimensions[1]); const jRows = parseInt(jDimensions[2]); if ($verbose) { console.log(`Bingo Solver: jCols=${jCols} jRows=${jRows}`); } // Initialize an empty string to store the HTML options let optionsHTML = ''; // Iterate over the keys of the gradientsArray object for (const gradientName in gradientsArray) { // Check if the current property is a direct property of the object and not inherited if (gradientsArray.hasOwnProperty(gradientName)) { // Create an option element with the gradient name as the value and label optionsHTML += `<option value="${gradientName}" ${bingoSolverSettingsGlobal.gradient === gradientName ? 'selected' : ''}>${gradientName}</option>`; } } JigidiBingoSolver.innerHTML = ` <hr> <div class="hide-complete" style="margin-bottom:2rem;"> <strong>Bingo Solver</strong><br> <p>Help with column? (0 to disable)</p> <div class="panel-tool " style="display: flex; justify-content: space-between; gap: 1rem;" id="animated-border"> <input type="number" id="magicStripesCol" value="${bingoSolverSettings.col}" min="0" max="${jCols}" style="width: 25%; \ text-align: center !important; \ padding: 0.5rem; \ font-size: 2rem; \ font-weight: bold; \ border-radius: 0.5rem; \ background: white; \ color: black; \ border: none;"> <button title="Go!" class="btn em" id="magicStripesGo" style="width: 25%;"><span style="font-size: 2rem; font-weight: bold; cursor: pointer;">Go!</span></button> <div title="Go +1!" class="btn em" id="magicStripesPlusOne" style="width: 50%;"><span style="font-size: 2rem; font-weight: bold; cursor: pointer;">Go +1!</span></div> </div> <div id="tool-settings-panel" class="panel-tool"> <label class="checkbox icon-plus">Show numbers on pieces <input type="checkbox" id="show-numbers" ${bingoSolverSettingsGlobal.showNumbers ? 'checked' : ''}><i style="${bingoSolverSettingsGlobal.showNumbers ? 'background: green;' : 'background: firebrick;'}"></i></label> <label for="font-size" class="checkbox icon-plus">Font size: <select name="font-size" id="font-size" style="padding: 0.5rem; font-weight: bold; border-radius: 0.5rem; background: white; color: black; border: none; float: right;"> <option value="12" ${bingoSolverSettingsGlobal.fontSize === 12 ? 'selected' : ''}>12</option> <option value="16" ${bingoSolverSettingsGlobal.fontSize === 16 ? 'selected' : ''}>16</option> <option value="22" ${bingoSolverSettingsGlobal.fontSize === 22 ? 'selected' : ''}>22</option> <option value="26" ${bingoSolverSettingsGlobal.fontSize === 26 ? 'selected' : ''}>26</option> <option value="30" ${bingoSolverSettingsGlobal.fontSize === 30 ? 'selected' : ''}>30</option> <option value="36" ${bingoSolverSettingsGlobal.fontSize === 36 ? 'selected' : ''}>36</option> <option value="40" ${bingoSolverSettingsGlobal.fontSize === 40 ? 'selected' : ''}>40</option> </select> </label> <label for="gradients" class="checkbox icon-plus">Gradient: <select name="gradients" id="gradients" style="padding: 0.5rem; font-weight: bold; border-radius: 0.5rem; background: white; color: black; border: none; float: right;"> ${optionsHTML} </select> </label> </div> </div> <hr> `; const magicStripesCol = document.getElementById('magicStripesCol'); const magicStripesGo = document.getElementById('magicStripesGo'); magicStripesGo.addEventListener('click', () => { bingoSolverSettings.col = parseInt(magicStripesCol.value); GM_setValue(`bingoSolverSettings_${jigsawId}`, bingoSolverSettings); window.location.reload(); }); document.getElementById('magicStripesPlusOne').addEventListener('click', () => { magicStripesCol.value = (parseInt(magicStripesCol.value) + 1) % (jCols + 1); magicStripesGo.dispatchEvent(new Event('click')); }); var fontSize = GM_getValue('bingoSolverSettingsGlobal', bingoSolverSettingsGlobal).fontSize; // Check whether to show numbers const showNumbers = document.getElementById('show-numbers'); showNumbers.addEventListener('change', () => { if ($verbose) { console.log(`Bingo Solver: showNumbers=${showNumbers.checked}`); } showNumbers.parentElement.querySelector('i').style.background = showNumbers.checked ? 'green' : 'firebrick'; // Store the new value bingoSolverSettingsGlobal.showNumbers = showNumbers.checked; GM_setValue('bingoSolverSettingsGlobal', bingoSolverSettingsGlobal); window.location.reload(); }) // Check which gradient to use const gradient = document.getElementById('gradients'); gradient.addEventListener('change', () => { if ($verbose) { console.log(`Bingo Solver: gradient=${gradient.value}`); } // Store the new value bingoSolverSettingsGlobal.gradient = gradient.value; GM_setValue('bingoSolverSettingsGlobal', bingoSolverSettingsGlobal); window.location.reload(); }) // Check which font size to use const fontSizeSelect = document.getElementById('font-size'); fontSizeSelect.addEventListener('change', () => { if ($verbose) { console.log(`Bingo Solver: fontSize=${fontSizeSelect.value}`); } // Store the new value bingoSolverSettingsGlobal.fontSize = parseInt(fontSizeSelect.value); bingoSolverSettingsGlobal.showNumbers = true; GM_setValue('bingoSolverSettingsGlobal', bingoSolverSettingsGlobal); window.location.reload(); }) // Check whether to show numbers if (!bingoSolverSettingsGlobal.showNumbers) { fontSize = 0; } // Generate spectrum to use if ($verbose) { console.log(`Bingo Solver: colors=${JSON.stringify(gradientsArray[bingoSolverSettingsGlobal.gradient])}`); } const spectrum = generateSpectrum(jRows, gradientsArray[bingoSolverSettingsGlobal.gradient]); if ($verbose) { console.log(spectrum); } const jColors = spectrum.map(color => `${color}`); let jC = 0; const targetCol = parseInt(bingoSolverSettings.col); if (targetCol > 0) { // Override putImageData with a manipulated version for THIS page load CanvasRenderingContext2D.prototype.putImageData = function (imageData, dx, dy) { const targetCol = parseInt(bingoSolverSettings.col); const col = jC % jCols; const row = Math.floor(jC / jCols); if ((col + 1) === targetCol) { // Target column: color and number multiple times this.fillStyle = jColors[row]; if ($verbose) { console.log("Column", col, "Row", row + 1, "Color", "https://www.color-hex.com/color/" + jColors[row % jColors.length].replace('#', '')); } this.fillRect(-1000, -1000, 2000, 2000); // Font size and text this.font = `bold ${fontSize}px sans-serif`; const text = `${row + 1} `.repeat(100); const x = -100; this.fillStyle = 'black'; // Outline color // Linewidth based on font size this.lineWidth = fontSize / 4; //this.lineWidth = 7; // Adjust the thickness of the outline // Draw the outline text with a thicker stroke this.strokeStyle = 'black'; // Set the stroke color this.strokeText(text, x, 0); // Draw the outline text at the top // Draw the inner text in white this.fillStyle = 'white'; // Inner color this.fillText(text, x, 0); // Draw the text in white at the top // Draw the text in multiple rows for (let i = -100; i <= 100; i++) { const y = i * (fontSize * 1.2); // Adjust the spacing between rows this.strokeText(text, x, y); // Outline this.fillText(text, x, y); // Fill } } else if ((col + 2) === targetCol) { // Previous column: lightly color and number once this.fillStyle = jColors[row % jColors.length]; this.fillRect(-1000, -1000, 2000, 2000); // Fill with semi-transparent white this.fillStyle = '#ffffffbb'; this.fillRect(-1000, -1000, 2000, 2000); this.font = `bold ${fontSize}px sans-serif`; this.fillStyle = 'black'; // Write in center, taking into account the size of the number if (row < 10) { this.fillText(`${row + 1}`, 0, 0); } else { var textWidth = this.measureText(`${row}`).width; this.fillText(`${row + 1}`, -textWidth / 2, 0); } } else { // Other columns: white-out this.fillStyle = '#ffffff'; this.fillRect(-1000, -1000, 2000, 2000); } jC++; } } }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址