Add "Search MAM" buttons to TheStoryGraph book and series pages (Title/Series and Title/Series + Author)
当前为
// ==UserScript==
// @name StoryGraph Plus: Search MAM Buttons
// @namespace https://greasyfork.org/en/users/1457912
// @version 0.2.1
// @description Add "Search MAM" buttons to TheStoryGraph book and series pages (Title/Series and Title/Series + Author)
// @author WilliestWonka
// @match https://app.thestorygraph.com/books/*
// @match https://app.thestorygraph.com/series/*
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
const maxRetries = 5;
let retryCount = 0;
let retryIntervalId = null;
function createMamButtons(title, author, isSeries = false) {
const container = document.createElement("div");
container.className = "mam-button-container flex mt-2 mb-2 space-x-2 w-full";
const createButton = (text, url) => {
const button = document.createElement("a");
button.href = url;
button.target = "_blank";
button.textContent = text;
button.className =
"py-2 px-2 border-x-2 border-x-darkGrey dark:border-x-darkerGrey " +
"border-y border-y-darkGrey dark:border-y-darkerGrey border-b-2 " +
"bg-grey dark:bg-darkestGrey hover:bg-darkGrey dark:hover:bg-darkerGrey " +
"inline-block w-full text-center text-xs text-darkerGrey dark:text-lightGrey";
return button;
};
const searchUrl = (query) =>
`https://www.myanonamouse.net/tor/browse.php?tor[text]=${encodeURIComponent(query)}`;
if (isSeries) {
container.appendChild(createButton("Search MAM Series", searchUrl(title)));
container.appendChild(createButton("Search MAM Series + Author", searchUrl(`${title} ${author}`)));
} else {
container.appendChild(createButton("Search MAM Title", searchUrl(title)));
container.appendChild(createButton("Search MAM Title + Author", searchUrl(`${title} ${author}`)));
}
return container;
}
function addButtonsIfReady() {
const pathParts = location.pathname.split('/').filter(Boolean);
let titleElement, authorElement, isSeries = false;
if (pathParts[0] === "books") {
titleElement = document.querySelector("h3.font-serif");
authorElement = document.querySelector("a[href^='/authors/']");
} else if (pathParts[0] === "series") {
isSeries = true;
titleElement = document.querySelector("h4.page-heading");
authorElement = document.querySelector("p.font-body a[href^='/authors/']");
} else {
return false;
}
if (!titleElement || !authorElement) {
return false;
}
const rawTitle = titleElement?.childNodes[0]?.textContent?.trim();
const author = authorElement?.textContent?.trim();
if (!rawTitle || !author) return false;
if (document.querySelector(".mam-button-container")) return true;
const buttonContainer = createMamButtons(rawTitle, author, isSeries);
if (isSeries) {
const flexRow = titleElement.closest("div.flex.justify-between.items-center.px-1");
if (flexRow && flexRow.parentElement) {
flexRow.parentElement.insertBefore(buttonContainer, flexRow.nextSibling);
}
} else {
const bookBlock = document.querySelector("div.book-title-author-and-series");
bookBlock?.appendChild(buttonContainer);
}
console.log("[SG+] 'Search MAM' buttons added!");
return true;
}
function startUnifiedRetryLoop() {
clearInterval(retryIntervalId);
retryCount = 0;
retryIntervalId = setInterval(() => {
if (retryCount >= maxRetries) {
clearInterval(retryIntervalId);
console.log("[SG+] Max retries reached, stopping.");
return;
}
if (!document.querySelector(".mam-button-container")) {
console.log(`[SG+] Buttons removed or missing, re-adding... Retry ${retryCount}`);
const success = addButtonsIfReady();
retryCount++;
if (success) {
clearInterval(retryIntervalId);
}
}
}, 1000);
}
function setupNavigationListener() {
const originalPushState = history.pushState;
history.pushState = function (...args) {
originalPushState.apply(this, args);
window.dispatchEvent(new Event("locationchange"));
};
const originalReplaceState = history.replaceState;
history.replaceState = function (...args) {
originalReplaceState.apply(this, args);
window.dispatchEvent(new Event("locationchange"));
};
window.addEventListener("popstate", () => {
window.dispatchEvent(new Event("locationchange"));
});
window.addEventListener("locationchange", () => {
setTimeout(() => {
startUnifiedRetryLoop();
}, 300); // slight delay after navigation
});
}
window.addEventListener("load", () => {
console.log("[SG+] Script loaded.");
startUnifiedRetryLoop();
setupNavigationListener();
});
})();