Grundo's Cafe Book Helper

Show unread books on your pet's book page

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Grundo's Cafe Book Helper
// @namespace    github.com/windupbird144/
// @version      0.9
// @description  Show unread books on your pet's book page
// @author       You
// @match        https://www.grundos.cafe/books_read/?pet_name=*
// @match        https://grundos.cafe/books_read/?pet_name=*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=grundos.cafe
// @grant        none
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js
// ==/UserScript==
/* globals $ */

// Add on-click toggle for booklist
function toggleBooks() {
    $("#books-to-read").toggle();
}

const booksUrl = `https://raw.githubusercontent.com/rowanberryyyy/gc-book-helper/main/books.json`;

/**
 * Analyse the document to find out which books your pet has read
 *
 * @returns string[] title of book your pets has read
 */
const getReadBooks = () =>
    Array.from(document.querySelectorAll(".center > table > tbody > tr:nth-of-type(n+1)")).map(e => e.childNodes[3].childNodes[0].textContent.trim().replace(" (","").toUpperCase())

/**
 * Return a list of books your pet has not read
 * TODO: Use a more efficient algorithm
 *
 * @param {[string, number][]} listOfBooks
 * @param {string[]} booksRead
 *
 * @returns {[string, number][]} the books your pet has not read
 */
const filterReadBooks = (listOfBooks, booksRead) => {
    return listOfBooks.filter(([name,_]) => !booksRead.includes(name.toUpperCase()));
}

// callback to sort books by rarity
const byRarity = ([_, rarity1], [__, rarity2]) => rarity1 - rarity2;

const html = (books) => `
<div class="bookbutton"><p><button id='viewbooks'>Your pet has ${books.length} books left to read!</button></p></div>
<div id="books-to-read" style="display:none">
    <div class="booklist">
    <ul>
            ${books.sort(byRarity).map(([name, rarity]) => `
                <li>
                    <span style="user-select:all">${name}</span> (<b>r${rarity})</b><br>
                    <a href="/market/wizard/?query=${name}" target="_bookSearch"><img width="15px" src="https://s3.us-west-2.amazonaws.com/cdn.grundos.cafe/misc/wiz.png"></a>
                    <a href="/island/tradingpost/browse/?query=${name}" target="_bookSearch"><img width="15px" src="https://s3.us-west-2.amazonaws.com/cdn.grundos.cafe/misc/tp.png"></a>
                    <a href="/safetydeposit/?page=1&category=&type=&query=${name}" target="_bookSearch"><img width="15px" src="https://s3.us-west-2.amazonaws.com/cdn.grundos.cafe/misc/sdb.gif"></a>
                </li>
            `).join("")}
        </ul>
    </div>
</div>`;

// Append CSS to the page
let customCSS = `
.bookbutton {
    margin: auto;
}
.booklist {
    height: 800px;
    overflow: auto;
    line-height: 20px;
}
.booklist ul {
    column-count: 2;
}
.booklist li {
    width: 95%;
}
.booklist li:nth-of-type(2n) {
    background: var(--grid_select);
}
`;

$("<style>").prop("type", "text/css").html(customCSS).appendTo("head");

// Ty Riz for the SW/TP add-on!

async function main() {
    const listOfBooks = await fetch(booksUrl).then(res => res.json());
    const toRead = filterReadBooks(listOfBooks, getReadBooks());
    $(".center > table").before(html(toRead));

    // Attach the toggleBooks function to the button click event
    $("#viewbooks").on("click", toggleBooks);
}

main().then();