i made a user script that removes results from advanced search and recently added pages. you can set tags to be removed and also filter out reading list entries.
Setup: open the website THEN click on library, this will retrieve your reading list. don't visit the library page directly, just navigate to it from anywhere and you're set
the script will automatically add and remove titles when you add to reading list or set reading status to none.
tags are case insensitive. the script will run every 2 seconds or whenever you change pages, you can edit that at the bottom
i can add filtering by description if someone wants it
Setup: open the website THEN click on library, this will retrieve your reading list. don't visit the library page directly, just navigate to it from anywhere and you're set
the script will automatically add and remove titles when you add to reading list or set reading status to none.
tags are case insensitive. the script will run every 2 seconds or whenever you change pages, you can edit that at the bottom
i can add filtering by description if someone wants it
JavaScript:
// ==UserScript==
// @name MangaDex Reading List and Tag Filter
// @namespace http://tampermonkey.net/
// @version 1.7
// @match https://mangadex.org/title/*
// @match https://mangadex.org/titles/recent
// @match https://mangadex.org/titles?*
// @match https://mangadex.org/titles/follows
// @grant none
// ==/UserScript==
(function() {
'use strict';
const excludedTags = ["horror", "Tragedy"]; // case insensitive, use " if tag contains '
let currentUrl = window.location.href;
// Placeholder for initial JSON data, optional, you can add your own ids that aren't in your list
const newJsonData = {
"result": "ok",
"statuses": {}
};
function loadJsonData() {
const storedData = localStorage.getItem('mangaData');
return storedData ? JSON.parse(storedData) : { statuses: {}, library: {} };
}
function mergeJsonData(newData) {
let jsonData = loadJsonData();
const existingStatuses = jsonData.statuses || {};
Object.keys(newData.statuses || {}).forEach(key => {
existingStatuses[key] = newData.statuses[key];
});
jsonData.statuses = existingStatuses;
return jsonData;
}
function saveJsonData(jsonData) {
localStorage.setItem('mangaData', JSON.stringify(jsonData));
}
// Initialize data storage on script load
const jsonData = mergeJsonData(newJsonData);
saveJsonData(jsonData);
let idsToRemove = Object.keys(jsonData.statuses);
let totalRemoved = 0;
let cards;
function updateCards() {
cards = document.querySelectorAll('.manga-card, .col-md-6');
}
function handleAddButtonClick() {
const readingStatusElement = document.querySelector('.md-select-inner-wrap .placeholder-text');
const mangaTitle = document.querySelector('.font-bold.text-xl.self-start.mb-2').textContent.trim();
const mangaId = window.location.pathname.split('/title/')[1].split('/')[0];
const readingStatus = readingStatusElement ? readingStatusElement.textContent.trim() : "None";
if (readingStatus !== "None") {
jsonData.statuses[mangaId] = readingStatus;
console.log(`Added "${mangaTitle}" to the library with status: ${readingStatus}`);
} else {
delete jsonData.statuses[mangaId];
console.log(`Removed "${mangaTitle}" from the library.`);
}
saveJsonData(jsonData);
}
function isFollowsPage() {
return window.location.href.includes('https://mangadex.org/titles/follows');
}
function removeMangaCards() {
if (isFollowsPage()) return;
totalRemoved = 0;
cards.forEach(card => {
const cardLinkElement = card.querySelector('a[href*="/title/"]');
const href = cardLinkElement ? cardLinkElement.getAttribute('href') : '';
const mangaId = href.split('/title/')[1]?.split('/')[0];
if (mangaId && idsToRemove.includes(mangaId)) {
card.remove();
totalRemoved++;
}
});
if (totalRemoved > 0) {
console.log("Removed " + totalRemoved + " manga card(s) by ID.");
}
}
function removeMangaCardsByExcludedTags() {
if (isFollowsPage()) return;
totalRemoved = 0;
cards.forEach(card => {
const tags = card.querySelectorAll('.tags-row .tag');
const hasExcludedTag = Array.from(tags).some(tag => {
const tagText = tag.textContent.trim().toLowerCase();
return excludedTags.some(excludedTag => excludedTag.toLowerCase() === tagText);
});
if (hasExcludedTag) {
card.remove();
totalRemoved++;
}
});
if (totalRemoved > 0) {
console.log("Removed " + totalRemoved + " manga card(s) due to excluded tags.");
}
}
function addButtonListeners() {
const buttons = document.querySelectorAll('button');
buttons.forEach(button => {
const buttonText = button.textContent.trim();
if (buttonText === "Update" || buttonText === "Add") {
button.addEventListener('click', function() {
console.log(`${buttonText} button clicked`);
handleAddButtonClick();
});
}
});
}
function periodicCheck() {
updateCards();
removeMangaCards();
removeMangaCardsByExcludedTags();
}
function initializeScript() {
// Reset states on new page load
idsToRemove = Object.keys(jsonData.statuses);
totalRemoved = 0;
updateCards();
removeMangaCards();
removeMangaCardsByExcludedTags();
addButtonListeners();
handlePage();
console.log('Script re-initialized for the new URL.');
}
setInterval(periodicCheck, 2000);
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.addedNodes.length) {
addButtonListeners();
}
});
});
observer.observe(document.body, { childList: true, subtree: true });
// Detect URL changes
const observerurl = new MutationObserver(() => {
if (currentUrl !== window.location.href) {
console.log('URL changed from:', currentUrl, 'to:', window.location.href);
currentUrl = window.location.href;
initializeScript(); // Re-initialize the script when the URL changes
}
});
observerurl.observe(document.body, { childList: true, subtree: true });
function handlePage() {
const isLibraryPage = window.location.href.includes('https://mangadex.org/titles/follows');
if (isLibraryPage) {
// Retrieve the Bearer token from localStorage
const tokenData = JSON.parse(localStorage.getItem('oidc.user:https://auth.mangadex.org/realms/mangadex:mangadex-frontend-stable'));
if (tokenData && tokenData.access_token) {
const bearerToken = tokenData.access_token;
const headers = {
'Authorization': `Bearer ${bearerToken}`,
'Content-Type': 'application/json'
};
fetch('https://api.mangadex.org/manga/status', {
method: 'GET',
headers: headers
})
.then(response => response.json())
.then(data => {
console.log('Manga status response:', data);
localStorage.setItem('mangaData', JSON.stringify(data));
console.log('Manga status saved to localStorage');
})
.catch(error => {
console.error('Error fetching manga status:', error);
});
} else {
console.error('Bearer token not found in localStorage');
}
}
}
})();
Last edited: