Ssieth / Storium Notification

// ==UserScript==
// @name        Storium Notification
// @namespace   storiumnotification.ssieth.co.uk
// @description Desktop notifications for storium
// @include     https://storium.com/notifications*
// @include		https://storium.com/#
// @include		https://storium.com/
// @include		https://storium.com
// @version     1.0.8
// @require     https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
// @grant       none
// ==/UserScript==


// ---------------------------------------------------------------------------
// You can readily alter variables in this section to customize the script for you
// ---------------------------------------------------------------------------
var intSecs = 300;  // Main timer interval - change this if you want more 
                    // or less frequent checks.
					
var logThese = {};  // Things to log.  Set to false to make the console logs less spammy
logThese.init 			= true;
logThese.timerFire 		= true;
logThese.scriptStart 	= true;
logThese.functionEntry  = false;
logThese.newNotes 		= true;
// ---------------------------------------------------------------------------
			
					
// ---------------------------------------------------------------------------
// Don't change anything below this line.....
// ---------------------------------------------------------------------------
var permResult;			// Permissions we have been allocated to desktop notifications
var aryNotes = [];		// Most recently loaded set of notifications (strings)
var aryNotesLast = [];	// Copy of the last loaded set of notifications
var aryNotesNew = [];	// Notifications that are new
var intMinSecs = 120;   // An idiot check to make sure that noone sets the refresh 
						// interval too low
var intRefDelay = 30	// Number of seconds to wait before refreshing notifications page.  
						// When this happens, the update is cleared.						
// Version info						
var scriptVerShort = GM_info.script.version;
var scriptVer = "script-name=ssi-sn&script-ver=" + scriptVerShort;						
// ---------------------------------------------------------------------------

log('Script start : ' + scriptVerShort,'scriptStart');
init();


// Iniialization routine
function init() {
	logFunctionEntry();
	// Idiot check
	log("Performing idiot check","init");
	if (intSecs < intMinSecs) {
		log("Idiot check failed: " + intSecs,"init");
		intSecs = intMinSecs;
	}

	// Ask for permission to do desktop notifications
	log("Getting permission for desktop notifications","init");
	askPermission();

	// Work out our starting position regarding what the notifications are
	log("Initialising notifications","init");
	getNotifications();

	// Set the check timer going
	log("Starting timer @ " + intSecs + "s","init");
	setInterval(function(){ checkUpdate(); }, 1000 * intSecs);
}

// Let's extend array prototype for ready comparison of array contents
Array.prototype.compare = function(testArr) {
    if (this.length != testArr.length) return false;
    for (var i = 0; i < testArr.length; i++) {
        if (this[i].compare) { 
            if (!this[i].compare(testArr[i])) return false;
        }
        if (this[i] !== testArr[i]) return false;
    }
    return true;
}

// Logging
function log(strMessage,strCategory) {
	if (logThese[strCategory]) {
		var now = new Date();
		if (log.caller) {
			console.log(now.toLocaleString() + ": " + log.caller.name + ": " + JSON.stringify(strMessage));
		} else {
			console.log(now.toLocaleString() + ": -none-: " + JSON.stringify(strMessage));
		}
	}
}

function logFunctionEntry() {
	if (logFunctionEntry.caller) {
		log(logFunctionEntry.caller.name, "functionEntry");
	}
}

// Send a desktop notification
function sendNotification(strTitle, strBody) {
	logFunctionEntry();
	var options = {
		body: strBody,
		requireInteraction: true,
		icon: "https://storium.com/favicon.ico?v=2"
	}		
	var notification = new Notification(strTitle, options);
}

// Refresh the page after a notification is detected
function refreshPage() {
	window.location.reload();
}

// Get new storium notifications and trigger a desktop notification if required
function getNotifications() {
	logFunctionEntry();
	// Add script version info to request so that we can signal to the storium techies that it's this script running.
	var url = "/notifications?" + scriptVer;
	
	$.get(url,function(data){
		var $notePage = $(data);
		var $tbody = $notePage.find("tbody");
		
		aryNotes = [];
		aryNotesNew = [];
		$tbody.find("td:not(.ago)").each(function() {
			var strEntry = $(this).text().trim();
			aryNotes.push(strEntry);
		});
		
		if (aryNotesLast.length > 0) {
			// We can do a comparison
			if (!aryNotes.compare(aryNotesLast)) {
				var intMarker = -1;
				// The notifications have changed so work out which are new
				for (var i = 1;i < aryNotes.length; i++) {
					if (aryNotes[i] == aryNotesLast[0]) {
						intMarker = i;
						break;
					}
				}
				for (var i = 0;i < intMarker; i++) {
					aryNotesNew.push(aryNotes[i]);					
				}
				log(aryNotes,"newNotes");
				log(aryNotesLast,"newNotes");
				log(aryNotesNew,"newNotes");
				sendNotification("New Storium Activitity", aryNotesNew.join("\n"));
				setTimeout(function() {	refreshPage(); }, 1000 * intRefDelay);
					
			}
		}
		// Clone the array of notes
		aryNotesLast = aryNotes.slice(0);
	});
}

// Ask permission if we don't have it and then 
function checkUpdate() {
	logFunctionEntry();
	log("Fired","timerFire");
	askPermission();
	
	if (permResult === "granted") {
		getNotifications();
	}
}

// Request user permission for desktop notifications
function askPermission() {
	logFunctionEntry();
	if (permResult !== "granted" && permResult !== "denied") {
		Notification.requestPermission(function (permission) {
			permResult = permission;
		})
	}
}