Skip to content

Instantly share code, notes, and snippets.

@BrutuZ
Last active March 3, 2025 00:45
Show Gist options
  • Save BrutuZ/29952c436d5abde675f798788e237432 to your computer and use it in GitHub Desktop.
Save BrutuZ/29952c436d5abde675f798788e237432 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name MU Toggle Backlog
// @version 0.13.3
// @description Adds link to only show items in your list with unread chapters
// @author BrutuZ
// @match https://www.mangaupdates.com/lists/*
// @icon64 https://www.mangaupdates.com/images/mascot.png
// @homepage https://gist.github.com/BrutuZ/29952c436d5abde675f798788e237432
// @downloadURL https://gist.github.com/BrutuZ/29952c436d5abde675f798788e237432/raw/mu-backlog-toggle.user.js
// @updateURL https://gist.github.com/BrutuZ/29952c436d5abde675f798788e237432/raw/mu-backlog-toggle.user.js
// @connect mangaupdates.com
// @grant GM.xmlHttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @noframes
// ==/UserScript==
const APIURL = 'https://api.mangaupdates.com/v1/series/';
const CDNURL = 'https://cdn.mangaupdates.com/image/thumb/';
let DRAWING = 0;
function backlog() {
document.getElementById('my_toggle')?.remove();
const entries = document.querySelectorAll('div[class^=series-list] > div.row');
const unread = document.querySelectorAll('span[class*=newlist]');
const rem = document.createElement('a');
rem.id = 'my_toggle';
rem.innerText = `👁️‍🗨️ Toggle ${entries.length - unread.length}/${
entries.length
} entries without unread chapters`;
rem.className = 'text';
rem.href = 'javascript:;';
rem.addEventListener('click', () => {
entries.forEach(item => {
if (item.querySelector('span[class*=newlist]')) return;
item.hidden = !item.hidden;
if (item.hidden) item.style = 'display:none';
else item.removeAttribute('style');
});
if (DRAWING != rem.innerText) {
DRAWING = rem.innerText;
drawCovers();
} else console.log('Abstaining');
});
document.querySelector('main .d-flex').insertAdjacentElement('afterend', rem);
const footer = document.querySelector('div:has(> a[title^=Export])');
if (footer.textContent.search('unread') === -1) {
footer.insertBefore(
document.createTextNode(`${unread.length} unread] [`),
document.querySelector('a[title^=Export]')
);
}
if (unread.length > 0) document.getElementById('my_toggle').click();
createObserver();
}
function fixStyleSheet() {
for (var i = 0; i < document.styleSheets.length; i++) {
const sheet = document.styleSheets[i];
if (!sheet.href?.startsWith('http')) return false;
var match = false;
for (var j = 0; j < sheet.cssRules.length; j++) {
const rule = sheet.cssRules[j];
match = rule?.selectorText?.match(/.*list_table.* > :nth-child\(2n\)/);
if (match) {
rule.selectorText = match[0].replace('2n', '2n of :not([hidden])');
break;
}
}
if (match) break;
}
}
function drawCovers() {
const newChaps = Array.from(document.querySelectorAll('[class^=series-list-item_newlist] > a'));
console.log(newChaps.length, 'entries');
newChaps.forEach(el => {
const th = el.closest('div').closest('.row').querySelector('.col-auto');
if (th.querySelector('img')) return;
const id = el.href.replace(/\D/g, '');
const savedThumb = GM_getValue(id);
if (savedThumb) draw(savedThumb, th, id);
else
GM.xmlHttpRequest({
url: APIURL + id,
responseType: 'json',
fetch: true,
onloadstart: console.log('Requesting API'),
})
.then(req => {
console.log('Requested:', req.response.title);
const thumb = req.response.image.url.thumb.replace(CDNURL, '');
GM_setValue(id, thumb);
draw(thumb, th, id);
})
.catch(e => {
console.error(e.error);
return;
});
});
}
function draw(thumb, th, id) {
console.log({ ID: id, Thumb: thumb });
const img = document.createElement('img');
img.loading = 'lazy';
img.src = CDNURL + thumb;
img.addEventListener('error', () => {
GM_deleteValue(id);
img.remove();
drawCovers();
});
th.insertAdjacentElement('beforeend', img);
}
function createObserver() {
new MutationObserver(check).observe(document.body, {
childList: true,
subtree: true,
});
}
function check(_, observer) {
if (document.querySelector('div[class^=series-list]')) {
observer.disconnect();
backlog();
}
}
fixStyleSheet();
createObserver();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment