Mamreader Plus

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

// ==UserScript==
// @name         Mamreader Plus
// @namespace    https://github.com/prateek-who/Mamreader-plus
// @version      0.9.1
// @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.querySelector(".mam-book-page-button")) {
      console.log("[G+] Book page button already exists. Halting.");
      return;
    }
    console.log("[G+] Book page detected! Running script...");
    const bookTitle = document.querySelector('[data-testid="bookTitle"]')?.innerText;
    const authorNameElement = document.querySelector('[data-testid="name"]');
    const authorName = authorNameElement?.innerText;
    if (!bookTitle || !authorName) {
      console.error("[G+] Could not find title or author elements.");
      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!");
    console.log("we are getting to adding the author follo button part..");
    const encodedAuthorQuery = encodeURIComponent(authorName);
    const mamAuthorSearchUrl = `https://www.myanonamouse.net/tor/browse.php?tor[text]=${encodedAuthorQuery}`;
    const followButtonContainer = document.querySelector(".AuthorFollowButton");
    if (!followButtonContainer) {
      console.log("[G+] Could not find follow button container for author search.");
      return;
    }
    const parentContainer = followButtonContainer.parentElement;
    if (!parentContainer) {
      console.log("[G+] Could not find parent container.");
      return;
    }
    parentContainer.style.display = "flex";
    parentContainer.style.alignItems = "center";
    parentContainer.style.gap = "8px";
    const authorButton = buttonToClone.cloneNode(true);
    authorButton.classList.add("mam-author-search-button");
    authorButton.innerText = "Search Author";
    authorButton.onclick = () => window.open(mamAuthorSearchUrl, "_blank");
    Object.assign(authorButton.style, {
      backgroundColor: "#ebc210",
      color: "black",
      borderColor: "#ebc210",
      whiteSpace: "normal",
      lineHeight: "1.1"
    });
    const authorIcon = document.createElement("img");
    authorIcon.src = "https://i.postimg.cc/nzMcQpSF/my-Anona-Mouse-logo.png";
    authorIcon.alt = "icon";
    authorIcon.style.width = "22px";
    authorIcon.style.height = "22px";
    authorIcon.style.marginRight = "12px";
    authorIcon.style.verticalAlign = "middle";
    authorButton.prepend(authorIcon);
    authorIcon.style.transition = "all 0.2s ease-in-out";
    authorButton.addEventListener("mouseenter", () => {
      authorButton.style.backgroundColor = hoverColor;
      authorIcon.style.filter = "brightness(1.1)";
    });
    authorButton.addEventListener("mouseleave", () => {
      authorButton.style.backgroundColor = originalColor;
      authorIcon.style.filter = "brightness(1)";
    });
    parentContainer.insertBefore(authorButton, followButtonContainer);
    console.log("[G+] 'Search Author' 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() {
    const addMainAuthorButton = () => {
      if (document.querySelector(".mam-search-button-author")) {
        console.log("[G+] Author button already added. Halting.");
        return;
      }
      const authorNameElem = document.querySelector("h1.authorName");
      if (!authorNameElem) return;
      const authorName = authorNameElem.innerText.trim();
      const mamSearchUrl = `https://www.myanonamouse.net/tor/browse.php?tor[text]=${encodeURIComponent(authorName)}`;
      const mamButton = document.createElement("button");
      mamButton.innerText = "Search Author";
      mamButton.className = "mam-search-button-author";
      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.className = "mam-icon";
      Object.assign(icon.style, {
        width: "16px",
        height: "16px",
        marginRight: "8px",
        verticalAlign: "middle"
      });
      mamButton.prepend(icon);
      mamButton.addEventListener("mouseenter", () => {
        mamButton.style.backgroundColor = "#d1a80e";
        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");
      };
      const followButtonContainer = document.querySelector(".authorFollowButtonContainer");
      if (followButtonContainer) {
        followButtonContainer.appendChild(mamButton);
      } else {
        authorNameElem.insertAdjacentElement("afterend", mamButton);
      }
      console.log("[G+] 'Search Author' button added!");
    };
    const addBookButtons = () => {
      if (!document.getElementById("mam-styles")) {
        const styles = `
        html.desktop .wtrButtonContainer {
          height: 80px !important;
          width: 140px !important;
        }

        .wtrButtonContainer .wtrUp {
          text-align: center;
          margin-top: 0px !important;
          padding: 0 !important;
          height: 20px !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.id = "mam-styles";
        styleSheet.innerText = styles;
        document.head.appendChild(styleSheet);
      }
      const allBooks = document.querySelectorAll(
        'tr[itemscope][itemtype="http://schema.org/Book"]'
      );
      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 mamSearchUrl = `https://www.myanonamouse.net/tor/browse.php?tor[text]=${encodedQuery}`;
          const mamButton = document.createElement("button");
          mamButton.className = "mam-search-button";
          mamButton.innerText = "Search MAM";
          const icon = document.createElement("img");
          icon.src = "https://i.postimg.cc/nzMcQpSF/my-Anona-Mouse-logo.png";
          icon.alt = "icon";
          icon.style.width = "10px";
          icon.style.height = "10px";
          icon.style.lineHeight = "10px";
          icon.style.marginRight = "8px";
          icon.style.verticalAlign = "middle";
          mamButton.prepend(icon);
          mamButton.addEventListener("mouseenter", () => {
            icon.style.filter = "brightness(0.87)";
          });
          mamButton.addEventListener("mouseleave", () => {
            icon.style.filter = "brightness(1)";
          });
          mamButton.onclick = (e) => {
            e.preventDefault();
            e.stopPropagation();
            window.open(mamSearchUrl, "_blank");
          };
          const ratingDiv = mainButtonContainer.querySelector(".ratingStars");
          if (ratingDiv) {
            ratingDiv.insertAdjacentElement("afterend", mamButton);
          } else {
            mainButtonContainer.appendChild(mamButton);
          }
        } catch (e) {
          console.error("Could not process a book row, skipping.", { bookRow, e });
        }
      }
    };
    addMainAuthorButton();
    addBookButtons();
    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();

})();