Inbox counter in favicon

I use Inbox as my primary way to see whats new in Fibery.

The idea here is to put the counter of messages in the inbox to be able to see the inbox count when the tab isn’t in focus.
Similar to how Gmail can do it for unread message count.

I was able to create this as a userscript (Greasemonkey/Tampermonkey) so I was able to have this working for myself. I’m sharing it here in case anyone else is intereseted.

// ==UserScript==
// @name     Fibery Favicon
// @version  1
// @grant    none
// @match    https://*.fibery.io/*
// ==/UserScript==

let saved_number_of_unread = 0;

function str2int(str) {
	if (!str) {
		return 0;
	}
	return parseInt(str.replace(/\D/g, ''), 10) || 0;
}

function faviconNbUnread() {
  const t = document.querySelector('.menu_header .count_badge');
  if (! t) {
    return;
  }
  const number_of_unread = str2int(t.innerHTML);
  if (saved_number_of_unread === number_of_unread) {
    return;
  }
  saved_number_of_unread = number_of_unread;
	// http://remysharp.com/2010/08/24/dynamic-favicons/
	// https://github.com/FreshRSS/FreshRSS/blob/4568111c00813756a3a34a381d684b8354fc4438/p/scripts/main.js#L2012C1-L2052C1
	const canvas = document.createElement('canvas');
	const link = document.getElementById('favicon').cloneNode(true);
	let ratio = window.devicePixelRatio;
	if (canvas.getContext && link) {
		canvas.height = canvas.width = 16 * ratio;
		const img = document.createElement('img');
		img.onload = function () {
			const ctx = canvas.getContext('2d');
			ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
			if (number_of_unread > 0) {
				let text = '';
				if (number_of_unread < 10) {
					text = number_of_unread;
          ratio = ratio * 1.5;
				} else if (number_of_unread < 1000) {
					text = number_of_unread;
				} else if (n < 100000) {
					text = Math.floor(number_of_unread / 1000) + 'k';
				} else {
					text = 'E' + Math.floor(Math.log10(number_of_unread));
				}
				ctx.font = 'bold ' + 9 * ratio + 'px "Arial", sans-serif';
				ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
				ctx.fillRect(0, 7 * ratio, ctx.measureText(text).width, 9 * ratio);
				ctx.fillStyle = '#000';
				ctx.fillText(text, 0, canvas.height - 1);
			}
			link.href = canvas.toDataURL('image/png');
			// Check if data URI has generated a real favicon and if not, fallback to standard icon
			if (link.href.length > 180) {
				document.querySelector('link[rel~=icon]').remove();
        link.type="image/x-icon";
				document.head.appendChild(link);
			}
		};
		img.src = '/favicon.ico';
	}
}

window.setInterval(faviconNbUnread, 60000);

// Initial load.
window.setTimeout(faviconNbUnread, 5000);