Skip to content

Instantly share code, notes, and snippets.

@IA21
Last active December 16, 2025 11:20
Show Gist options
  • Select an option

  • Save IA21/ae266dddddf96ab5d5b58604f1fa45a7 to your computer and use it in GitHub Desktop.

Select an option

Save IA21/ae266dddddf96ab5d5b58604f1fa45a7 to your computer and use it in GitHub Desktop.
Userscript for displaying (archived) fansub info on MAL anime pages
// ==UserScript==
// @name MAL Fansubs Archive
// @version 3
// @description Displays archived fansub info on MAL anime pages
// @author /u/iBzOtaku
// @match https://myanimelist.net/anime/*
// @connect gist.githubusercontent.com
// @connect ia21.github.io
// @grant GM.xmlHttpRequest
// ==/UserScript==
(function () {
'use strict';
const configUrlBase = 'https://gist.githubusercontent.com/IA21/b6b55e9eac61c7016d6f027b79ab419c/raw/';
const hideNonEnglishSubsByDefault = true;
const animeId = document.getElementById("myinfo_anime_id")?.value;
const injectionPoint = document.querySelector('#content > table > tbody > tr > td:nth-of-type(2)');
if (!animeId || !injectionPoint) {
return; // Silently exit if this isn't a valid anime page
}
// Create and inject the initial loader section
const fansubSection = document.createElement('div');
fansubSection.innerHTML = `<br><h2>Fansubs</h2><div class="fansub-loader" style="color: #888;">loading...</div><br>`;
injectionPoint.appendChild(fansubSection);
const loader = fansubSection.querySelector('.fansub-loader');
// Append the current timestamp as a query parameter to bypass gist cache
const dynamicConfigUrl = `${configUrlBase}?v=${Date.now()}`;
// Use GM.xmlHttpRequest to fetch the config
GM.xmlHttpRequest({
method: 'GET',
url: dynamicConfigUrl,
onload: function (response) {
try {
const config = JSON.parse(response.responseText);
// Construct the path to the data file using the user's specified logic
const id_str = animeId.toString().padStart(2, '0');
const second_last_digit = id_str.slice(-2, -1);
const last_digit = id_str.slice(-1);
const dataUrl = `${config.apiBaseUrl}/${second_last_digit}/${last_digit}/${animeId}.html`;
fetchData(dataUrl);
} catch (e) {
loader.textContent = 'Error: Could not parse fansub config.';
console.error("MAL Fansubs Error:", e);
}
},
onerror: function () {
loader.textContent = 'Error: Could not load fansub config.';
}
});
function fetchData(url) {
GM.xmlHttpRequest({
method: 'GET',
url: url,
onload: function (response) {
if (response.status === 404) {
loader.textContent = 'No subs available for this show.';
return;
}
renderHTML(response.responseText);
},
onerror: function () {
loader.textContent = 'Error: Could not load fansub data.';
}
});
}
function renderHTML(html) {
loader.innerHTML = `<label style="font-weight: normal;"><input type="checkbox" id="hidelang"> Hide non-English subs</label>`;
const htmlResponseDiv = document.createElement('div');
htmlResponseDiv.innerHTML = html.trim();
fansubSection.appendChild(htmlResponseDiv);
const checkbox = loader.querySelector('#hidelang');
checkbox.addEventListener('change', () => {
const nonEnglishElements = htmlResponseDiv.getElementsByClassName("nonenglish");
for (let el of nonEnglishElements) {
el.style.display = checkbox.checked ? 'none' : 'block';
}
});
htmlResponseDiv.addEventListener('click', (event) => {
if (event.target.classList.contains('commentToggle')) {
const commentsBox = document.getElementById(`comments${event.target.id}`);
if (commentsBox) {
commentsBox.style.display = commentsBox.style.display === 'none' ? 'block' : 'none';
}
}
});
if (hideNonEnglishSubsByDefault) checkbox.click();
}
})();
@Alex-mainGit
Copy link
Copy Markdown

Hey, just to let you know the line const injectionPoint = document.querySelector('#content > table > tbody > tr > td:nth-of-type(2)'); results in it being at the very bottom of the page.

grafik

Changing that to const injectionPoint = document.querySelector('.related-entries'); puts it right under the related entries section where it was before.

grafik

@IA21
Copy link
Copy Markdown
Author

IA21 commented Aug 5, 2025

@Alex-mainGit Hi. Originally MAL had the fansubs section at the bottom of the page and so, the original version of the userscript also placed it at the bottom. At some point MAL changed their page layout and the userscript created fansubs section started being displayed under related entries section. So when I pushed an update to the userscript, I fixed the layout issue as well so that it would go back to being displayed in its original position, at the bottom of the page.

Thank you for posting a solution tho, there must be people who are used to having it displayed under related entries by now and I'm sure it will be helpful for them :)

@Alex-mainGit
Copy link
Copy Markdown

@IA21 Oh I didn't know that. I always had the script version where it was after related entries and yeah I've gotten used to that now :D Thanks for the clarification!

@IA21
Copy link
Copy Markdown
Author

IA21 commented Aug 5, 2025

@Alex-mainGit no worries. btw, was the migration process easy for you to follow? I have been wondering if users on previous userscript version are properly seeing the depreciation notice and upgrading to this latest version of userscript.

@Alex-mainGit
Copy link
Copy Markdown

@IA21 Yeah it was easy. I saw the deprecation warning, went to this site and just replaced the old code in tampermonkey with the new one

@ssjbrap
Copy link
Copy Markdown

ssjbrap commented Dec 16, 2025

This hasn't been working for me. I just keep getting the error "Error: Could not load fansub data.".

@IA21
Copy link
Copy Markdown
Author

IA21 commented Dec 16, 2025

@ssjbrap ok I see the issue, looking into it

@IA21
Copy link
Copy Markdown
Author

IA21 commented Dec 16, 2025

@ssjbrap fixed, thanks for bringing this to my attention ๐Ÿ™

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment