// ==UserScript==
// @name AO3: Badge for Unread Inbox Messages
// @namespace https://greasyfork.org/en/users/906106-escctrl
// @version 1.0
// @description puts a little notification badge in the menu for unread messages in your AO3 inbox
// @author escctrl
// @match https://*.archiveofourown.org/*
// @license MIT
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js
// @grant none
// @downloadURL none
// ==/UserScript==
/****************** CONFIGURATION ******************/
// how often the script will check for unread messages (in hours)
const REFRESH_INTERVAL = 12;
// if the badge should show as an icon (true), or as text (false)
const BADGE_ICON = true;
// pick a background color for the badge to stand out more, or leave empty quotes ""
const HIGHLIGHT_COLOR = "gold";
// if the inbox link in the sidebar should automatically filter to unread messages only
const FILTER_INBOX = false;
// ****************** NOTE ON LOCAL STORAGE ******************
// For compatibility between userscript managers, this script uses local storage, which is visible from the Developer console.
// If you ever uninstall the script, unfortunately its data can't be automatically deleted.
// If you want to remove the data it sets, (1) visit archiveofourown.org, (2) go into the Developer console,
// (3) look for the Local Storage (4) and delete the entries for "unread_inbox_count" and "unread_inbox_date".
// The script also removes its data if you ever visit AO3 while logged out.
(function($) {
'use strict';
// first question: is the user logged in? if not, don't bother with any of this
const linkDash = $("#greeting p.icon a").attr('href') || "";
if (linkDash === "") {
localStorage.removeItem('unread_inbox_count');
localStorage.removeItem('unread_inbox_date');
return;
}
var highlight_css = (HIGHLIGHT_COLOR !== "") ? `#greeting #inboxbadge { background-color: ${HIGHLIGHT_COLOR}; border-radius: .25em; }` : "";
$("head").append(``)
.prepend(``);
// build a new inbox link (filtered to unread)
const linkInbox = linkDash + "/inbox?filters[read]=false&filters[replied_to]=all&filters[date]=desc&commit=Filter";
// the fun begins: on a page where we're seeing the unread msgs, we simply set the value
var page_url = window.location.pathname;
if (page_url.includes(linkDash)) {
// grab unread msgs # from the sidebar
var badge = (page_url.includes("/inbox")) ? $("div#dashboard li span.current").html() : $("div#dashboard a[href$='inbox']").html();
badge = badge.match(/\d+/);
// store the currently seen value with the current date, on every page visit, no questions asked
localStorage.setItem('unread_inbox_count', badge);
localStorage.setItem('unread_inbox_date', new Date());
// change sidebar inbox link as well to filtered
if (FILTER_INBOX) $("div#dashboard a[href$='inbox']").attr('href', linkInbox);
printBadge();
}
// on other pages, we check if the stored value is recent enough, otherwise we load it again
else {
var timeStored = new Date(localStorage.getItem("unread_inbox_date") || '1970'); // the date when the storage was last refreshed
var timeNow = createDate(0, 0, REFRESH_INTERVAL*-1, 0, 0, 0); // hours before that's max allowed
// if recent enough, simply create the badge
if (timeStored > timeNow) printBadge();
// if not, we have to start a background load
else {
$.get(linkDash, function(response) {
}).done(function(response) {
// grab the number from within the response
if ($(response).find("div#dashboard a[href$='inbox']").length > 0) {
var badge = $(response).find("div#dashboard a[href$='inbox']").html();
badge = badge.match(/\d+/);
// update the stored data with what we just received
localStorage.setItem('unread_inbox_count', badge);
localStorage.setItem('unread_inbox_date', new Date());
printBadge();
}
// the response has hit a different page e.g. a CF prompt
else
console.log("[script] Badge for Unread Inbox Messages: ajax error", response);
}).fail(function(data, textStatus, xhr) {
//This shows status code eg. 429
console.log("[script] Badge for Unread Inbox Messages: ajax error", data.status);
});
}
}
// add a little round badge to the user icon in the menu (if there are unread emails)
// this is called as a function as it needs to run only when the async ajax page load has completed
function printBadge() {
const badge = localStorage.getItem('unread_inbox_count');
const displaytext = (BADGE_ICON) ? ` ${badge}` : `Inbox (${badge})`;
if (count != "0") $("div#greeting p.icon").prepend(`${displaytext}`);
}
})(jQuery);
// convenience function to be able to pass minus values into a Date, so JS will automatically shift correctly over month/year boundaries
// thanks to Phil on Stackoverflow for the code snippet https://stackoverflow.com/a/37003268
function createDate(secs, mins, hours, days, months, years) {
var date = new Date();
date.setFullYear(date.getFullYear() + years);
date.setMonth(date.getMonth() + months);
date.setDate(date.getDate() + days);
date.setHours(date.getHours() + hours);
date.setMinutes(date.getMinutes() + mins);
date.setSeconds(date.getSeconds() + secs);
return date;
}