AO3: Badge for Unread Inbox Messages

puts a little notification badge in the menu for unread messages in your AO3 inbox

当前为 2024-04-02 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         AO3: Badge for Unread Inbox Messages
// @namespace    https://greasyfork.org/en/users/906106-escctrl
// @version      1.1
// @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
// ==/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(`<style type="text/css"> #inboxbadge .iconify { font-family: FontAwesome, sans-serif; }
        a#inboxbadge { display: block; padding: .25em .75em !important; text-align: center; float: left; margin: 0 1em; line-height: 1.286; height: 1.286em; }
        p.icon a { float: right; } ${highlight_css}</style>`)
        .prepend(`<script src="https://use.fontawesome.com/ed555db3cc.js" />`);

    // 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) ? `<span class="iconify">&#xf0e0;</span>&nbsp;&nbsp;${badge}` : `Inbox (${badge})`;
        if (badge != "0") $("#greeting p.icon").prepend(`<a id="inboxbadge" href="${linkInbox}" title="You have unread messages in you inbox">${displaytext}</a>`);
    }

})(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;
}