// ==UserScript== // @name AO3: Badge for Unread Inbox Messages // @namespace https://greasyfork.org/en/users/906106-escctrl // @version 2.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(``); // 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 (badge != "0") $("#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; }