Save Player Drawings

Click on a user and then click Track to automatically download their drawings after their turn.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

You will need to install an extension such as Tampermonkey to install this script.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name        Save Player Drawings
// @namespace   https://greasyfork.org/users/281093
// @match       https://sketchful.io/
// @grant       none
// @version     1.0
// @author      Bell
// @license     MIT
// @copyright   2020, Bell
// @description Click on a user and then click Track to automatically download their drawings after their turn.
// ==/UserScript==
/* jshint esversion: 6 */

const trackedPlayers = JSON.parse(localStorage.getItem('trackedPlayers')) || [];
const userModalHeader = document.querySelector('#userModal div.modal-header');
const chat = document.querySelector('#gameChatList');
const buttonTextOff = 'Track';
const buttonTextOn = 'Untrack';
const buttonStyle = `width: 100px; top: 70px; margin-right:
					 16px; position: absolute; right: 0px`;

(function addButton() {
	const modalBody = document.querySelector('#userModal div.modal-body');
	const button = document.createElement('button');
	button.setAttribute('class', 'btn btn-primary');
	button.setAttribute('style', buttonStyle);
	button.textContent = buttonTextOff;
	button.id = 'trackButton';
	button.onclick = toggleTrackedPlayer;
	modalBody.appendChild(button);
})();

function toggleTrackedPlayer() {
	const player = document.querySelector('#userModal h3').textContent;
	const button = document.querySelector('#trackButton');
	const tracked = trackedPlayers.includes(player);

	if (tracked) {
		trackedPlayers.splice(trackedPlayers.indexOf(player), 1);
		button.textContent = buttonTextOff;
	}
	else {
		trackedPlayers.push(player);
		button.textContent = buttonTextOn;
	}

	localStorage.setItem('trackedPlayers', JSON.stringify(trackedPlayers));
}

const updateHeader = (mutations) => {
	mutations.forEach(mutation => {
		const newNodes = mutation.addedNodes;
		if (!newNodes.length) return;
		updateButtonState(newNodes[0]);
	});
};

new MutationObserver(updateHeader)
	.observe(userModalHeader, { childList: true, subtree: true });

function updateButtonState(nameNode) {
	const player = nameNode.textContent;
	const button = document.querySelector('#trackButton');
	const tracked = trackedPlayers.includes(player);
	button.textContent = tracked ? buttonTextOn : buttonTextOff;
}

const checkChat = (mutations) => {
	mutations.forEach(mutation => {
		const msgNode = mutation.addedNodes[0];
		if (!msgNode || !msgNode.classList.contains('chatAdmin')) return;
		parseSystemMessage(msgNode.textContent);
	});
};

new MutationObserver(checkChat).observe(chat, { childList: true });

function downloadDrawing(name) {
	const a = document.createElement('a');
	a.download = name + '.png';
	a.href = document.querySelector('#canvas').toDataURL();
	a.click();
}

function parseSystemMessage(message) {
	if (message.startsWith('The word was')) {
		const word = /: ([a-zA-Z0-9 -]+)/.exec(message)[1];
		const drawerNode = document.querySelector('.gameDrawing').parentElement;
		let drawerName = drawerNode.querySelector('.gameAvatarName').textContent;

		if (!trackedPlayers.includes(drawerName)) return;

		drawerName = drawerName.replaceAll(/[\/\\*:>?<|"]/, '');
		if (!drawerName.length) drawerName = 'anon';
		downloadDrawing(`${word} by ${drawerName}`);
	}
}