Skip to content

Instantly share code, notes, and snippets.

@sellithy
Last active June 11, 2025 08:17
Show Gist options
  • Save sellithy/0faff5c8bb5789e00a1e9134c2daced4 to your computer and use it in GitHub Desktop.
Save sellithy/0faff5c8bb5789e00a1e9134c2daced4 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @author sellithy
// @name Chess.com → WintrChess
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Insert a WintrChess favicon button on Chess.com; auto-paste PGN on WintrChess, and starts an analysis
// @match https://www.chess.com/game/*
// @match https://www.chess.com/game/live/*
// @match https://www.chess.com/game/daily/*
// @match https://www.chess.com/analysis/game/live/*
// @match https://wintrchess.com/analysis*
// @require https://cdn.jsdelivr.net/npm/wait-for-the-element@4
// @downloadURL https://gist.github.com/sellithy/0faff5c8bb5789e00a1e9134c2daced4/raw/108d3d804be20871e437c55ec79df5110e00bef6/analyzeOnWintrChess.user.js
// @grant GM_openInTab
// @run-at document-idle
// ==/UserScript==
const {waitForTheElement} = this["wait-for-the-element"];
(function() {
'use strict';
const WINTR_CHESS_BUTTON_ID = 'tm-wintrchess-btn';
async function insertWintrChessButton() {
const shareBtn = await waitForTheElement('button[aria-label^="Share"]', {timeout: 1000});
if (!shareBtn) {
console.error('Timeout waiting for Share button');
return;
}
if (document.getElementById(WINTR_CHESS_BUTTON_ID)) return;
const wintrBtnImage = document.createElement('img');
wintrBtnImage.src = 'https://www.google.com/s2/favicons?domain=wintrchess.com&sz=256';
wintrBtnImage.style.height = shareBtn.clientHeight + 'px';
wintrBtnImage.style.width = 'auto';
wintrBtnImage.style.border = 'none'
const wintrBtn = document.createElement('button');
wintrBtn.id = WINTR_CHESS_BUTTON_ID;
wintrBtn.classList.add('live-game-buttons-button');
wintrBtn.style.height = wintrBtnImage.style.height;
wintrBtn.style.padding = '0';
wintrBtn.style['background-color'] = 'transparent';
wintrBtn.style.border = 'none';
wintrBtn.appendChild(wintrBtnImage);
wintrBtn.onclick = async () => {
shareBtn.click();
const dialog = await waitForTheElement('div[role="dialog"]');
if (!dialog) {
console.error('Share modal did not appear.');
return;
}
const pgnTab = Array.from(dialog.querySelectorAll('button'))
.find(b => b.textContent.trim() === 'PGN');
if (!pgnTab) {
console.error('PGN tab not found.');
return;
}
pgnTab.click();
const textarea = await waitForTheElement('textarea');
if (!textarea) {
console.error('PGN textarea did not load.');
return;
}
const pgn = textarea.value.trim();
if (!pgn) {
console.error('Failed to retrieve PGN.');
return;
}
const closeBtn = dialog.querySelector('button[aria-label="Close"]');
if (closeBtn) closeBtn.click();
const url = 'https://wintrchess.com/analysis?pgn=' + encodeURIComponent(pgn);
GM_openInTab(url, false);
};
shareBtn.parentNode.insertBefore(wintrBtn, shareBtn.nextSibling);
}
async function clickAnalyze() {
const pgnParam = new URLSearchParams(location.search).get('pgn');
if (!pgnParam) return;
const decodedPgn = decodeURIComponent(pgnParam);
const textarea = await waitForTheElement('textarea', {timeout: 1000});
if (!textarea) {
console.error('Failed to find PGN textarea on WintrChess.');
return;
}
const select = await waitForTheElement('select:has(option[value="PGN"])', {timeout: 1000})
if (!select) {
console.error('Failed to find select on WintrChess.');
return;
}
if (select.value != "PGN") {
select.value = "PGN";
select.dispatchEvent(new Event("change", { bubbles: true }));
await new Promise(resolve => setTimeout(resolve, 1000));
}
Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value")
.set.call(textarea, decodedPgn);
textarea.dispatchEvent(new Event("input", { bubbles: true }));
const btn = Array.from(document.querySelectorAll('button'))
.find(b => b.textContent.trim().toLowerCase() === 'analyse');
if (!btn) {
console.error('Analyse button not found.');
return;
}
await new Promise(resolve => setTimeout(resolve, 1000));
btn.click();
}
(function main() {
if (location.hostname === 'wintrchess.com') {
clickAnalyze();
} else {
insertWintrChessButton();
}
})();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment