Greasy Fork 还支持 简体中文。

Mamreader Plus

Adds buttons on Goodreads pages to search authors/books/series on MAM

目前為 2025-09-30 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Mamreader Plus
// @namespace    https://github.com/prateek-who/Mamreader-plus
// @version      0.9.0
// @description  Adds buttons on Goodreads pages to search authors/books/series on MAM
// @author       prateek-who
// @match        *://www.goodreads.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  function addMamButtonToBookPage() {
    if (document.getElementById("mam-search-button-single")) {
      console.log("[G+] Button already exists. Halting.");
      return;
    }
    console.log("[G+] Book page detected! Running script...");
    let bookTitle = "", authorName = "";
    try {
      bookTitle = document.querySelector('[data-testid="bookTitle"]')?.innerText ?? "";
      authorName = document.querySelector('[data-testid="name"]')?.innerText ?? "";
      console.log(`[G+] Book title: ${bookTitle}
Author name: ${authorName}`);
    } catch (e) {
      console.error("[G+] Could not find title or author.", e);
      return;
    }
    const encodedQuery = encodeURIComponent(`${bookTitle} ${authorName}`);
    const mamSearchUrl = `https://www.myanonamouse.net/tor/browse.php?tor[text]=${encodedQuery}`;
    const buttonContainer = document.querySelector(".BookActions");
    if (!buttonContainer) {
      console.error("[G+] Could not find a container to add the button to.");
      return;
    }
    const buttonToClone = buttonContainer.querySelector("button");
    if (!buttonToClone) {
      console.error("[G+] Could not find a button to clone for styling.");
      return;
    }
    const mamButton = buttonToClone.cloneNode(true);
    mamButton.id = "mam-search-button-single";
    mamButton.innerText = "Search MAM";
    mamButton.onclick = () => window.open(mamSearchUrl, "_blank");
    Object.assign(mamButton.style, {
      marginTop: "8px",
      marginBottom: "8px",
      backgroundColor: "#ebc210",
      color: "black",
      borderColor: "#ebc210"
    });
    const icon = document.createElement("img");
    icon.src = "https://i.postimg.cc/nzMcQpSF/my-Anona-Mouse-logo.png";
    icon.alt = "icon";
    icon.style.width = "22px";
    icon.style.height = "22px";
    icon.style.marginRight = "12px";
    icon.style.verticalAlign = "middle";
    mamButton.prepend(icon);
    const originalColor = "#ebc210";
    const hoverColor = "#fbd011";
    icon.style.transition = "all 0.2s ease-in-out";
    mamButton.addEventListener("mouseenter", () => {
      mamButton.style.backgroundColor = hoverColor;
      icon.style.filter = "brightness(1.1)";
    });
    mamButton.addEventListener("mouseleave", () => {
      mamButton.style.backgroundColor = originalColor;
      icon.style.filter = "brightness(1)";
    });
    const wantToReadButtonContainer = buttonContainer.querySelector(
      ".BookActions__button"
    );
    if (wantToReadButtonContainer) {
      wantToReadButtonContainer.insertAdjacentElement("afterend", mamButton);
    } else {
      buttonContainer.appendChild(mamButton);
    }
    console.log("[G+] 'Search MAM' button added!");
  }

  function addMamButtonsToSeriesPage() {
    if (document.querySelector(".mam-search-button-series")) {
      console.log("[G+] Series buttons already added. Halting.");
      return;
    }
    console.log("[G+] Series page detected! Running script...");
    const allBooks = document.querySelectorAll(".responsiveBook");
    console.log(`[G+] Found ${allBooks.length} books on the page.`);
    for (const bookElement of allBooks) {
      try {
        const title = bookElement.querySelector('[itemprop="name"]')?.innerText ?? "";
        const author = bookElement.querySelector('[itemprop="author"] [itemprop="name"]')?.innerText ?? "";
        const actionsContainer = bookElement.querySelector(".objectLockupContent__actions");
        const buttonToClone = actionsContainer?.querySelector(".wantToReadButton button");
        if (title && author && actionsContainer && buttonToClone) {
          const encodedQuery = encodeURIComponent(`${title} ${author}`);
          const mamSearchUrl = `https://www.myanonamouse.net/tor/browse.php?tor[text]=${encodedQuery}`;
          const mamButton = buttonToClone.cloneNode(false);
          mamButton.innerText = "Search MAM";
          mamButton.className = " mam-search-button-series";
          Object.assign(mamButton.style, {
            marginTop: "4px",
            marginLeft: "8px",
            paddingTop: "2px",
            paddingLeft: "8px",
            paddingRight: "8px",
            backgroundColor: "#ebc210",
            color: "black",
            borderRadius: "0.25rem",
            border: "none",
            fontFamily: '"Lato", "Helvetica Neue", "Helvetica", sans-serif',
            fontSize: "14px",
            lineHeight: "1",
            height: "31px",
            width: "150px",
            cursor: "pointer"
          });
          const icon = document.createElement("img");
          icon.src = "https://i.postimg.cc/nzMcQpSF/my-Anona-Mouse-logo.png";
          icon.alt = "icon";
          icon.style.width = "16px";
          icon.style.height = "16px";
          icon.style.marginRight = "8px";
          icon.style.verticalAlign = "middle";
          mamButton.prepend(icon);
          const originalColor = "#ebc210";
          const hoverColor = "#d1a80e";
          mamButton.addEventListener("mouseenter", () => {
            mamButton.style.backgroundColor = hoverColor;
            icon.style.filter = "brightness(0.87)";
          });
          mamButton.addEventListener("mouseleave", () => {
            mamButton.style.backgroundColor = originalColor;
            icon.style.filter = "brightness(1)";
          });
          mamButton.onclick = (e) => {
            e.preventDefault();
            e.stopPropagation();
            window.open(mamSearchUrl, "_blank");
          };
          actionsContainer.appendChild(mamButton);
        }
      } catch (e) {
        console.error("Could not process a book entry, skipping.", bookElement);
      }
    }
    console.log("[G+] Finished adding series buttons!");
  }

  function addMamButtonToAuthorPage() {
    if (document.querySelector(".mam-search-button-author")) {
      console.log("[G+] Author button already added. Halting.");
      return;
    }
    const followButton = document.querySelector(
      ".authorFollowButtonContainer"
    );
    if (!followButton) return;
    const authorNameElem = document.querySelector(
      ".authorName span[itemprop='name']"
    );
    if (!authorNameElem) return;
    const authorName = authorNameElem.innerText.trim();
    const mamSearchUrl = `https://www.myanonamouse.net/tor/browse.php?tor[text]=${encodeURIComponent(
    authorName
  )}`;
    const mamButton = followButton.cloneNode(true);
    mamButton.innerText = "Search Author";
    mamButton.className = "mam-search-button";
    Object.assign(mamButton.style, {
      padding: "8px 12px",
      backgroundColor: "#ebc210",
      color: "black",
      borderColor: "black",
      marginTop: "8px",
      borderRadius: "3px",
      border: "1px solid #969696ff",
      boxSizing: "border-box",
      display: "inline-block",
      fontFamily: '"Lato", "Helvetica Neue", "Helvetica", sans-serif',
      fontSize: "14px",
      height: "32px",
      width: "140px",
      lineHeight: "1",
      cursor: "pointer"
    });
    const icon = document.createElement("img");
    icon.src = "https://i.postimg.cc/nzMcQpSF/my-Anona-Mouse-logo.png";
    icon.alt = "icon";
    icon.style.width = "16px";
    icon.style.height = "16px";
    icon.style.marginRight = "8px";
    icon.style.verticalAlign = "middle";
    mamButton.prepend(icon);
    const hoverColor = "#d1a80e";
    mamButton.addEventListener("mouseenter", () => {
      mamButton.style.backgroundColor = hoverColor;
      icon.style.filter = "brightness(0.87)";
    });
    mamButton.addEventListener("mouseleave", () => {
      mamButton.style.backgroundColor = "#ebc210";
      icon.style.filter = "brightness(1)";
    });
    mamButton.onclick = (e) => {
      e.preventDefault();
      e.stopPropagation();
      window.open(mamSearchUrl, "_blank");
    };
    followButton.appendChild(mamButton);
    console.log("[G+] 'Search Author' button added!");
    const allBooks = document.querySelectorAll(
      'tr[itemscope][itemtype="http://schema.org/Book"]'
    );
    const styles = `
        html.desktop .wtrButtonContainer {
            height: 80px !important;
            width: 140px !important;
        }

        .wtrButtonContainer .wtrUp {
            margin-top: 0px !important;
            padding: 0 !important;
            height: 20px !important;
            text-align: center; !important
        }

        .wtrToRead, .wtrExclusiveShelf, .wtrShelfButton {
            display: flex !important;
            justify-content: center !important;
            align-items: center !important;

            margin-top: 0px !important;
            height: 18px !important;
            line-height: 18px !important; 
            padding: 0 !important;
            padding-bottom: 0 !important;
            font-size: 11px !important;
            text-align: center;
        }

        .wtrButtonContainer .ratingStars {
            margin-top: 0px !important;
        }

        .mam-search-button {
            background-color: #ebc210;
            border: 1px solid #969696ff;
            border-radius: 3px;
            box-sizing: border-box;
            color: black;
            cursor: pointer;
            display: block;
            font-family: "Lato", "Helvetica Neue", "Helvetica", sans-serif;
            font-size: 11px;
            font-weight: bold;
            height: 20px;
            line-height: 18px;
            margin-top: 0px;
            padding: 0 12px;
            text-align: center;
            width: 100%;
            text-decoration: none;
        }

        .mam-search-button:hover {
            background-color: #d1a80e;
        }
    `;
    const styleSheet = document.createElement("style");
    styleSheet.innerText = styles;
    document.head.appendChild(styleSheet);
    for (const bookRow of allBooks) {
      try {
        const mainButtonContainer = bookRow.querySelector(
          ".wtrButtonContainer"
        );
        if (!mainButtonContainer) continue;
        if (mainButtonContainer.querySelector(".mam-search-button")) continue;
        const title = bookRow.querySelector('a.bookTitle span[itemprop="name"]')?.innerText.trim();
        const author = bookRow.querySelector('a.authorName span[itemprop="name"]')?.innerText.trim();
        if (!title || !author) continue;
        const encodedQuery = encodeURIComponent(`${title} ${author}`);
        const mamSearchUrl2 = `https://www.myanonamouse.net/tor/browse.php?tor[text]=${encodedQuery}`;
        const mamButton2 = document.createElement("button");
        mamButton2.className = "mam-search-button";
        mamButton2.innerText = "Search MAM";
        const icon2 = document.createElement("img");
        icon2.src = "https://i.postimg.cc/nzMcQpSF/my-Anona-Mouse-logo.png";
        icon2.alt = "icon";
        icon2.style.width = "10px";
        icon2.style.height = "10px";
        icon2.style.lineHeight = "10px";
        icon2.style.marginRight = "8px";
        icon2.style.verticalAlign = "middle";
        mamButton2.prepend(icon2);
        mamButton2.addEventListener("mouseenter", () => {
          icon2.style.filter = "brightness(0.87)";
        });
        mamButton2.addEventListener("mouseleave", () => {
          icon2.style.filter = "brightness(1)";
        });
        mamButton2.onclick = (e) => {
          e.preventDefault();
          e.stopPropagation();
          window.open(mamSearchUrl2, "_blank");
        };
        const ratingDiv = mainButtonContainer.querySelector(".ratingStars");
        if (ratingDiv) {
          ratingDiv.insertAdjacentElement("afterend", mamButton2);
        } else {
          mainButtonContainer.appendChild(mamButton2);
        }
      } catch (e) {
        console.error("Could not process a book row, skipping.", { bookRow, e });
      }
    }
    console.log("[G+] Finished adding author page buttons!");
  }

  let currentPage = "";
  function runCheck() {
    const path = window.location.pathname;
    if (currentPage === path) return;
    if (path.includes("/book/show/") && document.querySelector('[data-testid="bookTitle"]')) {
      currentPage = path;
      addMamButtonToBookPage();
    } else if (path.includes("/series/") && document.querySelector(".responsiveSeriesHeader__title")) {
      currentPage = path;
      addMamButtonsToSeriesPage();
    } else if (path.includes("/author/show/") && document.querySelector("h1.authorName")) {
      currentPage = path;
      addMamButtonToAuthorPage();
    } else {
      currentPage = "";
    }
  }
  const observer = new MutationObserver(runCheck);
  observer.observe(document.body, { childList: true, subtree: true });
  runCheck();

})();