GitHub Notifier

Notifies the user whenever they have new unread notifications on GitHub.

À data de 25/06/2020. Ver a versão mais recente.

Terá de instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Terá de instalar uma extensão como Tampermonkey para instalar este script.

Terá de instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Terá de instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Terá de instalar uma extensão como Tampermonkey para instalar este script.

Terá de instalar uma extensão de gestão de scripts de utilizador para instalar este script.

(Já tenho um gestor de scripts de utilizador, deixe-me instalá-lo!)

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

(Já tenho um gestor de estilos de utilizador, deixe-me instalá-lo!)

// ==UserScript==
// @name GitHub Notifier
// @namespace https://rafaelgssa.gitlab.io/monkey-scripts
// @version 4.1.3
// @author rafaelgssa
// @description Notifies the user whenever they have new unread notifications on GitHub.
// @match https://github.com/*
// @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @require https://greasyfork.org/scripts/405802-monkey-dom/code/Monkey%20DOM.js?version=820314
// @require https://greasyfork.org/scripts/405813-monkey-utils/code/Monkey%20Utils.js?version=820304
// @require https://greasyfork.org/scripts/405935-iwc/code/IWC.js?version=819599
// @run-at document-end
// @grant GM.info
// @grant GM_info
// @noframes
// ==/UserScript==

/* global DOM, SJ */

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

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

	let doShowBrowserNotifications = false;
	let hasChecked = false;
	let hasUnread = false;

	/**
	 * Loads the script.
	 */
	const load = () => {
		const indicator = document.querySelector('.mail-status');
		if (!indicator) {
			// User is not logged in.
			return;
		}
		lockBrowserNotifications();
		check(indicator);
		DOM.observeNode(indicator, { attributes: true }, /** @type {NodeCallback} */ (check));
	};

	/**
	 * Locks browser notifications so that only one tab shows them.
	 */
	const lockBrowserNotifications = () => {
		SJ.lock(`${scriptId}_lock_browserNotifications`, () => {
			console.log(`[${scriptName}] Locked browser notifications!`);
			doShowBrowserNotifications = true;
		});
	};

	/**
	 * Checks for unread notifications and notifies the user.
	 * @param {Element} indicator The element that indicates the notification status.
	 */
	const check = (indicator) => {
		const newValue = indicator.classList.contains('unread');
		if (hasUnread !== newValue) {
			hasUnread = newValue;
			notifyUser();
		}
		hasChecked = true;
	};

	/**
	 * Notifies the user.
	 */
	const notifyUser = () => {
		if (hasUnread) {
			if (!document.title.startsWith('(New) ')) {
				document.title = `(New) ${document.title}`;
			}
		} else if (document.title.startsWith('(New) ')) {
			document.title = document.title.slice(6);
		}
		if (doShowBrowserNotifications && hasChecked && hasUnread && document.hidden) {
			// Only show a browser notification for subsequent unread notifications if the user is away from the tab.
			showBrowserNotification('You have new unread notifications.');
		}
	};

	/**
	 * 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 {
		load();
	} catch (err) {
		console.log(`Failed to load ${scriptName}: `, err);
	}
})();