SGTools Notifier

Notifies the user when a SGTools rules check is complete and optionally redirects to the giveaway.

当前为 2020-06-23 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name SGTools Notifier
// @namespace https://rafaelgssa.gitlab.io/monkey-scripts
// @version 4.1.1
// @author rafaelgssa
// @description Notifies the user when a SGTools rules check is complete and optionally redirects to the giveaway.
// @match https://www.sgtools.info/*
// @match https://www.steamgifts.com/giveaway/*
// @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @require https://greasyfork.org/scripts/405802-monkey-dom/code/Monkey%20DOM.js?version=819513
// @require https://greasyfork.org/scripts/405831-monkey-storage/code/Monkey%20Storage.js?version=819508
// @require https://greasyfork.org/scripts/405813-monkey-utils/code/Monkey%20Utils.js?version=819175
// @require https://greasyfork.org/scripts/405840-monkey-wizard/code/Monkey%20Wizard.js?version=819509
// @run-at document-idle
// @grant GM.info
// @grant GM.setValue
// @grant GM.getValue
// @grant GM.deleteValue
// @grant GM_info
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @noframes
// ==/UserScript==

/* global MonkeyDom, MonkeyStorage, MonkeyWizard */

(async () => {
	'use strict';

	const scriptId = 'sgtn';
	const scriptName = GM.info.script.name;

	/** @type {WizardSchema[]} */
	const schemas = [
		{
			type: 'multi',
			id: 'doRedirect',
			message: 'Do you want to be redirected to the giveaway when the check is complete?',
			defaultValue: false,
			choices: [
				{
					id: 'y',
					template: '"%" for yes',
					value: true,
				},
				{
					id: 'n',
					template: '"%" for no',
					value: false,
				},
			],
		},
	];

	let doRedirect = false;

	/** @type {HTMLElement | null} */
	let checkButton;

	/**
	 * Loads the script.
	 * @returns {Promise<void>}
	 */
	const load = async () => {
		if (window.location.hostname === 'www.steamgifts.com') {
			return _removePageUrlFragment();
		}
		doRedirect = /** @type {boolean} */ (await MonkeyStorage.getSetting('doRedirect'));
		checkButton = document.querySelector('#check');
		if (checkButton) {
			checkButton.addEventListener('click', _waitForRulesCheck);
		}
	};

	/**
	 * Removes the fragment from the page URL and notifies the user if exists.
	 * @returns {Promise<void>}
	 */
	const _removePageUrlFragment = async () => {
		if (window.location.hash === `#${scriptId}`) {
			window.history.replaceState(
				'',
				document.title,
				`${window.location.origin}${window.location.pathname}${window.location.search}`
			);
			_notifyUser(true);
		}
	};

	/**
	 * Waits until the check is complete and notifies the user.
	 * @returns {Promise<void>}
	 */
	const _waitForRulesCheck = async () => {
		if (!checkButton) {
			return;
		}
		const result = await MonkeyDom.dynamicQuerySelector(
			'#getlink, #error_alert:not(.hidden)',
			1800
		);
		if (!result) {
			// Rules have not been checked after 30 minutes.
			return;
		}
		if (result.matches('#getlink')) {
			// User passed the rules.
			if (doRedirect) {
				checkButton.removeEventListener('click', _waitForRulesCheck);
				checkButton.dispatchEvent(new MouseEvent('click', { bubbles: true }));
				await _waitForGiveawayLink();
			} else {
				_notifyUser(true);
			}
		} else {
			// User failed to pass the rules.
			_notifyUser(false);
		}
	};

	/**
	 * Waits for the giveaway link, redirects to the giveaway and notifies the user.
	 * @returns {Promise<void>}
	 */
	const _waitForGiveawayLink = async () => {
		const link = /** @type {HTMLAnchorElement} */ (await MonkeyDom.dynamicQuerySelector(
			'#gaurl a'
		));
		if (link) {
			window.location.href = `${link.href}#${scriptId}`;
		} else {
			_notifyUser(true);
		}
	};

	/**
	 * Notifies the user.
	 * @param {boolean} isSuccess Whether the user passed the rules or not.
	 */
	const _notifyUser = (isSuccess) => {
		const [emoji, message] = isSuccess
			? ['✔️', 'You passed the rules!']
			: ['❌', 'You failed to pass the rules.'];
		if (window.location.hostname === 'www.sgtools.info') {
			document.title = `${emoji} ${document.title}`;
		}
		if (document.hidden) {
			// Only show a browser notification if the user is away from the tab.
			_showBrowserNotification(`${emoji} ${message}`);
		}
	};

	/**
	 * Shows a browser notification.
	 * @param {string} body The message to show.
	 * @return {Promise<void>}
	 */
	const _showBrowserNotification = async (body) => {
		if (Notification.permission !== 'granted') {
			await Notification.requestPermission();
		}
		if (Notification.permission === 'granted') {
			new Notification(scriptName, { body });
		}
	};

	try {
		await MonkeyStorage.init(scriptId, {
			settings: {
				doRedirect: false,
			},
		});
		await MonkeyWizard.init(scriptId, scriptName, schemas);
		await load();
	} catch (err) {
		console.log(`Failed to load ${scriptName}: `, err);
	}
})();