AO3 Re-read Savior: Bookmark tracker, Rekudos converter & Mark for Later+Subscribe buttons at BOP

Userscripts for an optimized and efficient AO3 experience, particularly rereading. This includes automatically populating bookmark notes with fic title, author, workID and summary alongside whatever existing bookmark notes. Converts re-clicks of the Kudos button into a "rekudos" comment. Adds the "subscribe" and "mark for later/mark as read" buttons to the end of the fic.

目前为 2023-07-09 提交的版本。查看 最新版本

// ==UserScript==
// @name         AO3 Re-read Savior: Bookmark tracker, Rekudos converter & Mark for Later+Subscribe buttons at BOP
// @namespace    Ellililunch AO3 USERSCIPTS
// @description  Userscripts for an optimized and efficient AO3 experience, particularly rereading. This includes automatically populating bookmark notes with fic title, author, workID and summary alongside whatever existing bookmark notes. Converts re-clicks of the Kudos button into a "rekudos" comment. Adds the "subscribe" and "mark for later/mark as read" buttons to the end of the fic.
// @version      0.9
// @history      0.0 replicated Ellililunch Bookmark maker script modified from Bairdel's AO3 Bookmarking Records to automatically add title, author, and summary to the bookmark description for ease of recordkeeping
// @history      0.1 added in Rekudos Converter modified from Van Irie (automatically comment on a fic when you've already left kudos)
// @history      0.2 added in Ellililunch's AO3 clone "mark for later" button at bottom (recreates marked for later button at end of works to easily mark something as read at the bottom of the page) based on script by scriptfairy
// @history      0.3 added code that puts the "Marked for Later" button in a fic blurb when browsing AO3 from "JaneBuzJane but indebted to Bat, always"
// @history      0.4 added code to recreate subscribe button at end of works by scriptfairy + cleaned up redundant code
// @history      0.5 added my code to clone fic title, author, and summary at bottom of the page (based off work from scriptfairy), tried to add the bookmark back button script from sunkitten_shash but it didn't work :(
// @history      0.6 added functionality for bookmark notes where if currently no bookmark notes, populates fic info. if there are bookmark notes that already has the fic info, keep the existing info + adds the current date as the reread date. if there are already bookmark notes, but no fic info, adds the fic info in front of the bookmark notes
// @history      0.7 added autopopulation of workID to bookmark notes on the suggestion of oliver t
// @history      0.8 fixed nested if-else statement to add just workID if already has the summary (for those who already have bookmarks with just title/author/summary)
// @history      0.9 modified bookmark maker to be based off the title and author variables instead of "Summary:" // reformatted it all to lose the heading formatting + make it easier to read.
// @author       Ellililunch
// @match        http://archiveofourown.org/tags*
// @match        https://archiveofourown.org/tags*
// @match        http://archiveofourown.org/works*
// @match        https://archiveofourown.org/works*
// @include      /https?://archiveofourown\.org/.*works/\d+/
// @require      http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js
// @require      https://code.jquery.com/jquery-2.2.4.js
// @run-at       document-idle
// @match        *archiveofourown.org/works/*
// @match        *archiveofourown.org/series/*
// @license      GNU GPLv3
// @license      MIT
// @grant        none
// ==/UserScript==


/////////////////TABLE OF CONTENTS////////////////
// BUTTON CLONING
////// Add subscribe button to bottom of work (end of fic)
////// Add "mark for later" button at bottom of work (end of fic)
////// Add "mark for later" botton to blurb of fic when scrolling through AO3
////// REKUDOS button functionality
// BOOKMARK NOTES MAKER (adds fic title, author, workID, and summary to bookmark notes depending on the existing notes (new bookmark, summary but no workID, summary with workID, no info but existing bookmark notes)
////// duplicates fic info at the bottom of the website as a backup to populate bookmark with fic info




////////////////////////////////////////////////////////////
//////////////// ALL BUTTON CLONING HERE ///////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////


//////////// recreate subscribe button at end of works by scriptfairy
(function($) {
    $(document).ready(function() {
        var sub = $('li.subscribe').clone();
        $('#new_kudo').parent().after(sub);
    });
})(window.jQuery);



//////////////////////////AO3 clone "mark for later" button at bottom//////////////////////
///// this is useful for indicating you've read the fic once you get to the bottom! (ie/ if you "Marked for later" at the top of the fic and read to the bottom, at the bottom this would be a "Mark as read" button :)
(function($) {
    $(document).ready(function() {
        var mfl = $('li.mark').clone();
        $('#new_kudo').parent().after(mfl);
    });
})(window.jQuery);


////////////////////  Add AO3 Mark for Later Button to works list ///////////////////
// description  Puts the "Marked for Later" button in a fic blurb when browsing AO3 from "JaneBuzJane but indebted to Bat, always"
// This script adds a button to each work on archiveofourown.org (AO3) when browsing tags that allows a user to add a work to their "Marked for Later" list without having to open the fic in a separate tab.
var $j = jQuery.noConflict();

$j(document).ready(function() {

    for (var i = 0, link, links = $("li[role=article] > .header > .heading:first-child > a[href*='/works']"); i < links.length; i++) {

    (link = $(links[i])).closest(".header")
        .nextAll(".stats")
        .before("<span class=\"actions\" style=\"float: left; clear: right;\"><a href=\"" + link.attr("href") + "/mark_for_later\">Mark For Later</a></span>");
}

});



/////////FOR REKUDOS//////////////////

//ACNOWLEDGEMENT: most of the method is cribbed from "ao3 no rekudos" by scriptfairy
//Rest is cribbed from "Change Ao3 Kudos button text to Glory" by AlectoPerdita
//I do not know enough JS to do shit like this on my own
//https://gf.qytechs.cn/en/scripts/406616-ao3-no-rekudos
//https://gf.qytechs.cn/en/scripts/390197-change-ao3-kudos-button-text-to-glory/code

//SETUP//

var auto = false;
    //Set to "true" if you want to skip the confirmation automatically.

var comments = Array(
    "Extra Kudos <3 ",
    "This is an extra kudos, since I've already left one. :) ",
    "I just wanted to leave another kudos <3 ",
    "Kudos! ♥ ",
    "I loved this! ",
    "This was great ♥ ",
    "♥ ♥ ♥ ",
    "LOVE LOVE LOVE! ",
    "<3 <3 <3 ",
    "This is great ♥ ",
    "Loved this <3 ",
    "Thank you for sharing this ♥ ",
    "Kudos ♥ ",
    "I loved this so much I reread it and now im leaving an extra kudos! ",
    "Kissing you on your forehead kudos ",
    "Kissing you on your forehead, MWAH ",
    "Reread kudos :) "
         //ellililunch added some more array options for more random rekudos messages
);
    //Remember to keep your message between the quotation marks.
    //Remember to separate comments with a comma!
    //Message max length: 10000 characters

var lat = 500;
    //Delay in milliseconds, waiting for reply from OTW servers. (Check with CTRL+SHIFT+K)

var verify = true;
    //Set to "false" to turn off anti-spam verification. (Not recommended.)

//Definitions
var work_id, kudos, banner, kudo_btn, cmnt_btn, cmnt_field, id;

work_id = window.location.pathname;
work_id = work_id.substring(work_id.lastIndexOf('/')+1);

banner = document.getElementById('kudos_message');

kudo_btn = document.getElementById('new_kudo');

cmnt_btn = document.getElementById('comment_submit_for_'+work_id);
cmnt_field = document.getElementById('comment_content_for_'+work_id);

//Message randomiser
var random = Math.floor(Math.random() * comments.length);
var message = comments[random];

// ID
if (verify == true) {
var d = new Date();
id = d.toISOString();
id = id.substring(0,10);
message = message+'</br><sub>Sent '+id+' using an Ao3 Rekudos Converter</sub>'
}

//Comment-sending with button press rather than form submit
function send() {
    cmnt_field.value = message;
    cmnt_btn.click();
}

//Change kudos button behaviour
function change() {
    kudo_btn.addEventListener("click", send);
}

//Extra click for confirmation
var active = 'Rekudos?';
function rename() {
    'use strict';
    var kudo_text = document.querySelector('#kudo_submit');
    kudo_text.value = active;
    change();
}

//New method
function isAuto(){
if (auto == false || window.AssistMode == true) {
    rename();}
    else {
    send();}
}

function makeitwork() {
console.log('Rekudo latency check');
if (banner.classList.contains("kudos_error") == true) {
    isAuto();}
}

function delay(){
    setTimeout(makeitwork,lat);
}

kudo_btn.addEventListener("click", delay);



//////////////////////////////////////////////
//////////////////////////////////////////////
//////// THIS IS THE BOOKMARK AREA ///////////
//////////////////////////////////////////////
//////////////////////////////////////////////




//////////THE BOOKMARK SAVIOR/////////////
////////////automatically adds title, author and summary above exisiting notes in bookmark////////////
////this is all modified from Bairdel's AO3 Bookmarking Records

(function() {
        // automatically checks the Private Bookmark checkbox. Set to false if you don't want this.
        document.getElementById("bookmark_private").checked = true;
        // keeps any bookmark notes you've made previously. Must be above the "Read: ".
        // this updates the date you last read the fic each time.
        var bookmarkNotes = (document.getElementById("bookmark_notes").innerHTML);

        ////////////////////////// customisations ///////////////////////////////// DO NOT WORRY ABOUT
        // get the current date. should be in local time. you could add HH:MM if you wanted.
        var currdate = new Date();
        var dd = String(currdate.getDate()).padStart(2, '0');
        var mm = String(currdate.getMonth() + 1).padStart(2, '0'); //January is 0
        var yyyy = currdate.getFullYear();
        var hh = String(currdate.getHours()).padStart(2, '0');
        var mins = String(currdate.getMinutes()).padStart(2, '0');
        // change to preferred date format
        var date;
        //date = dd + '/' + mm + '/' + yyyy + " " + hh + ":" + mins;
        date = mm + '/' + dd + '/' + yyyy; //this is the USA standard date format
        console.log(date);

        var author;
        var words;
        var status;
        var title;
        var summary;
        var series_notes;
        var lastChapter;
        var workID;

        workID = window.location.href.split("/")[4]; //the code was suggested by oliver t, and is useful if a work is deleted and you want to recreate the URL for the wayback machine

        /*
        What should it do?
        if story title, author, and info is already there, don't add anything
        if there are bookmark notes but no story info, add story info
        if it's a series, it should get all the titles + summaries?
                     i think the class for the series "summary" is notes
                     so this would be
                     var series_notes;
                     series_notes = = document.getElementsByClassName("notes")[0].innerHTML; // series "summary" attempt
        */

        // checks if series
        var seriesTrue = document.getElementsByClassName("current")[0];
        if (seriesTrue != undefined) {
            // options for series bookmark notes

            title = document.getElementsByTagName("h2")[0].innerHTML.trim();
            words = document.getElementsByClassName("stats")[2].getElementsByTagName("dd")[0].textContent;
            author = document.querySelectorAll('[rel="author"]')[0].innerHTML.trim(); // fic author
            summary = document.getElementsByClassName("series meta group.userstuff")[0].innerHTML; // series notes "summary" attempt //attempted  new way: document.getElementsByClassName("series meta group.userstuff")[0].innerText.substring(10, document.getElementsByClassName("series meta group.userstuff")[0].innerText.length); //old way:

            /*var complete = document.getElementsByClassName("stats")[2].getElementsByTagName("dd")[2].textContent;
            var updated = document.getElementsByClassName("series meta group")[0].getElementsByTagName("dd")[2].textContent
            // var status
            if (complete == "No") {
                status = "Updated: " + updated;
            } else if (complete == "Yes") {
                status = "Completed: " + updated;
            }*/


        } else {
            // options for fics
            lastChapter = "Chapter " + document.getElementsByClassName("chapters")[1].innerHTML.split("/")[0];
            title = document.getElementsByClassName("title heading")[0].innerHTML.trim(); // fic name
            words = document.getElementsByClassName("words")[1].innerHTML; // fic wordcount
            author = document.querySelector("#workskin > .preface .byline").textContent.trim(); // new way of finding fic author regardless of Anonymous suggested by w4tchdog on greasyfork, this was the old way if that breaks it for you: document.querySelectorAll('[rel="author"]')[0].innerHTML.trim(); // old way of finding fic author
            summary = document.getElementsByClassName("summary")[0].innerText.substring(10, document.getElementsByClassName("summary")[0].innerText.length); // old way to get summmary that had all sorts of OG formatting document.getElementsByClassName("summary")[0].innerHTML; // summary attempt

            /*// status i.e. Completed: 2020-08-23, Updated: 2022-05-08, Published: 2015-06-29
            if (document.getElementsByClassName("status").length != 0) {
                // for multichapters
                status = document.getElementsByClassName("status")[0].innerHTML + " " + document.getElementsByClassName("status")[1].innerHTML;
            } else{
                // for single chapter fics
                status = document.getElementsByClassName("published")[0].innerHTML + " " + document.getElementsByClassName("published")[1].innerHTML;
            }
            */
        }




        //////////////////// THIS IS THE BIT FOR YOU TO LOOK AT /////////////////////////////////////////////////////////////////////////////////////

        // puts it all together. feel free to change this format to whatever you like.
        // <br> puts the next text on a new line
        // options for variables are:
    // date = current date
    // current time
    // current chapter count of fic / current number of parts in series
    // title = title of fic
    // author = author of fic (note that author "Anonymous" breaks this, but "orphan_account" doesn't
    // word count of fic
    // summary = fic summary
    // bookmarkNotes = existing bookmark notes
    // newBookmarkNotes = this is the variable for the new bookmark notes
    // status of fic i.e. Completed: 2020-08-23, Updated: 2022-05-08, Published: 2015-06-29


        /////// examples //////////
        //    bookmarkNotes = bookmarkNotes + "<br>Last Read: " + date + "<br>Chapter " + lastChapter;
        //    bookmarkNotes = bookmarkNotes + "<br>Last Read: " + date + "<br>Chapter " + lastChapter + "<br><br>" + title + " by " + author;
        //    bookmarkNotes + "<br>Last Read: " + date + "<br>" + lastChapter + "<br><br>" + title + " by " + author + "<br>" + status;


        /////////////////SELECT YOU OPTIONS//////////////////////////////

        ///// if currently no bookmark notes, populates fic info. if there are bookmark notes that already has the fic info, keep the existing info + adds the current date as the reread date. if there are already bookmark notes, but no fic info, adds the fic info in front of the bookmark notes
        if (bookmarkNotes === "") {  ///learned this from: https://stackoverflow.com/questions/154059/how-do-i-check-for-an-empty-undefined-null-string-in-javascript
        // if no existing bookmarks, then add all info:
            var newBookmarkNotes = "<b>" + title + " by " + author + "</b> (workID: " + workID + ")<blockquote>Summary: <br>" + summary + "</blockquote>Read: " + date;

        } else if (bookmarkNotes.includes(title + " by " + author)) {    ///learned this from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else
            if (bookmarkNotes.includes("orkID:")) {
                var newBookmarkNotes = bookmarkNotes + "<br>" + "Read: " + date; ///trying to see if I can add reread date to existing bookmark notes... we'll see babes
            } else {
                var newBookmarkNotes = "(WorkID: " + workID + ") " +bookmarkNotes + "<br>" + "Read: " + date;
            }

        //OG code that worked for existing info in
        /*} else if (bookmarkNotes.includes("Summary:")) {    ///learned this from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else
            if (bookmarkNotes.includes("orkID:")) {
                var newBookmarkNotes = bookmarkNotes + "<br>" + "Reread: " + date; ///trying to see if I can add reread date to existing bookmark notes... we'll see babes
            } else {
                var newBookmarkNotes = bookmarkNotes + "<br>" + "WorkID: " + workID + "<br>" + "Reread: " + date;
            }*/

        } else {    ///learned this from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else
            var newBookmarkNotes = "<b>" + title + " by " + author + "</b> (workID: " + workID + ")<blockquote>Summary: <br>" + summary + "</blockquote>" + bookmarkNotes;
        }

        // fills in the bookmark notes box.
        document.getElementById("bookmark_notes").innerHTML = newBookmarkNotes;
    })();


//////////////////// backup AO3 clone fic title, author, and summary at bottom of page (helpful when author is anonymous and the modifed Bairdel's Bookmark Maker doesn't help)//////
    (function($) {
        $(document).ready(function() {
        // new attempt
            var summary = $('div.preface .summary').clone();
            $('#feedback').parent().after(summary);
            var author = $('div.preface .byline').clone();
            //$('#feedback').parent().after(author);
            var format = " by "
            //$('#feedback').parent().after(format);
            var title = $('div.preface .title.heading').clone();
            $('#feedback').parent().after(author); + $('#feedback').parent().after(format); + $('#feedback').parent().after(title);
            //document.write("test text") #completely overwrote entire page //more research has been done, looks like this is mostly jquery lol
            var words = $('.meta .stats dl dd.words').clone();
            $('#feedback').parent().after(words);
            //var wordlabel = "Words: "
            $('#feedback').parent().after("Words: ");

        });
    })(window.jQuery);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址