// ==UserScript==
// @name Find The Correct Watch Order And All Related Entries+Live-Actions+Doramas + Copy Entry Title
// @namespace Search for Live-Actions\Doramas\All Related Entries + Correct Watch Order + Copy Entry Title
// @version 48
// @description Find the Correct Watch Order And All Related Entries. Also, find out if an anime has any Live-Action or Dorama adaptations, and Copy The entry Title.
// @author hacker09
// @include https://myanimelist.net/forum/?topicid=1863965
// @include /^https:\/\/myanimelist\.net\/((anime|manga)(id=)?(\.php\?id=)?)(\/)?([\d]+)/
// @exclude https://myanimelist.net/anime/genre/*
// @exclude https://myanimelist.net/anime/producer/*
// @icon https://t3.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://myanimelist.net&size=64
// @run-at document-end
// @connect chiaki.site
// @connect mydramalist.com
// @grant GM.xmlHttpRequest
// ==/UserScript==
(function() {
'use strict';
var hasRun = true; //Create a new variable
async function Prog() { //Run the program
if (document.hasFocus() && hasRun) //If the tab has focus and it's the first time the script runs
{ //Starts the if condition
hasRun = false; //Change the var condition
if (location.href === 'https://myanimelist.net/forum/?topicid=1863965') { //If the user is on the Official Guidex Index
$("b:contains('Guides available:')")[0].innerHTML = '<b style="font-weight: normal;">(Click on the letter you want to jump to.)</b><br><div style="cursor: pointer;"><b id="GoToA">Guides available: A</b> | <b id="GoToB">B</b> | <b id="GoToC">C</b> | <b id="GoToD">D</b> | <b id="GoToE">E</b> | <b id="GoToF">F</b> | <b id="GoToG">G</b> | <b id="GoToH">H</b> | <b id="GoToI">I</b> | <b id="GoToJ">J</b> | <b id="GoToK">K</b> | <b id="GoToL">L</b> | <b id="GoToM">M</b> | <b id="GoToN">N</b> | <b id="GoToO">O</b> | <b id="GoToP">P</b> | <b id="GoToQ">Q</b> | <b id="GoToR">R</b> | <b id="GoToS">S</b> | <b id="GoToT">T</b> | <b id="GoToU">U</b> | <b id="GoToV">V</b> | <b id="GoToW">W</b> | <b id="GoToX">X</b> | <b id="GoToY">Y</b> | <b id="GoToZ">Z</b><div> <style>#topBtn {display: block;position: fixed;bottom: 20px;right: 30px;z-index: 99;font-size: 18px;border: none;outline: none;background-color: #2e51a2;color: white;cursor: pointer;padding: 15px;border-radius: 4px;}</style><button onclick="document.documentElement.scrollTop = 0;" id="topBtn" title="Go to top" style="transform: rotate(90deg); display: block;"><</button>'; //Adds a text and makes the letters clickable. Also adds a scroll to top button on the page
for (let i = 'A'.charCodeAt(0); i <= 'Z'.charCodeAt(0); ++i) { //For every charCode
document.querySelector(`b#GoTo${String.fromCharCode(i)}`).onclick = () => document.querySelectorAll('b')[i - 36].scrollIntoView(); //Scroll the page until the letter can be seen
} //Finishes the for condition
} //Finishes the if condition
else //If the user isn't on any Guide Index
{ //Starts the else condition
const findButton = document.createElement("a"), copyButton = document.createElement("a"), chiakiButton = document.createElement("a"); //Creates an "a" element so the button will appear
var ChiakiFranchiseTitle, ChiakiFranchiseTitleWithSymbols, MalClubText, ChiakiDocument, IMDBAsianWiki, hasAnime = '', ChiakiTextData = [], ChiakientryidSArray = [], MyDramaListText = ' and MyDramaList', MyDramaListCheck = '👍 Found on MyDramaList.'; //Create new global variables
if (location.pathname.split('/')[1] === 'manga') { //If the user is in an manga entry
const Relations = await (await fetch('https://api.jikan.moe/v4/' + location.href.split('/')[3] + '/' + location.pathname.match(/\d+/)[0] + '/relations')).json(); //Fetch
hasAnime = Relations.data.flatMap(relation => relation.entry).find(entry => entry.type === "anime"); //Try getting 1 entry that is an anime
} //Finishes the if condition
var entryid = hasAnime !== undefined && hasAnime !== '' ? hasAnime.mal_id : location.pathname.match(/\d+/)[0]; //Get the anime id
GM.xmlHttpRequest({ //Starts the xmlHttpRequest
method: "GET",
url: 'https://chiaki.site/?/tools/watch_order/id/' + entryid,
onload: (response) => { //Starts the onload event listener
ChiakiDocument = new DOMParser().parseFromString(response.responseText, 'text/html'); //Parses the fetch response
if (ChiakiDocument.querySelector("h2") !== null) { //Starts the if condition
ChiakiFranchiseTitle = ChiakiDocument.querySelector("h2").innerText.split(' Watch Order')[0].replace(/[^a-zA-Z0-9]+/g, " ").trim(); //Get the anime title on the h2 element and remove the Watch Order text, symbols, and whitespaces
ChiakiFranchiseTitleWithSymbols = ChiakiDocument.querySelector("h2").innerText.split(' Watch Order')[0].trim(); //Get the anime title on the h2 element (with symbols) and remove the Watch Order text, and whitespaces
} //Finishes the if condition
ChiakiDocument.querySelectorAll("span.uk-text-muted.uk-text-small").forEach((TextElement, i) => { //Loop through the elements
ChiakientryidSArray.push(ChiakiDocument.querySelectorAll("span.uk-text-muted.uk-text-small > a:nth-child(1)")[i].href.match(/\d+/)[0]); //Add All Anime Links on chiaki to an Array
const TotalRawDuration = TextElement.textContent.split("×")[1].split("|")[0].trim(); //Creates a variable to hold the total unprocessed times
const ALLChiakiTitles = ChiakiDocument.querySelectorAll("span.wo_title")[i].innerText; //Creates a variable to get all the anime titles on chiaki site
const TotalEpisodes = TextElement.textContent.split("|")[2].match(/\d+|\?/g)[0]; //Creates a variable to hold the total episodes
const EpisodeType = TextElement.textContent.split("|")[1].trim(); //Creates a variable to get the episode types
var eps = ' eps'; //Create a variable called eps
var Duration = ''; //Creates a blank variable
var PerEp = ' per ep'; //Create a variable called PerEp
if (TotalEpisodes === '1') { //If the entry has only 1 ep
eps = ' ' + EpisodeType; //Change the variable called eps
PerEp = ''; //Change the variable called PerEp
} //Finishes the if condition
if (EpisodeType !== 'TV') { //If the entry type isn't TV
if (TotalEpisodes !== '1') { //If the entry doesn't have only 1 ep
eps = ' ' + EpisodeType + 's'; //Change the variable called eps
} //Finishes the if condition
Duration = ' of ' + TotalRawDuration + PerEp; //Defines the Duration variable if the episode type isn't TV
} //Finishes the if condition
ChiakiTextData.push(ALLChiakiTitles + ',, ' + TotalEpisodes + eps + Duration + ',\n'); //Add Everything to an Array
}); //Finishes the for condition
} //Finishes the onload event listener
}); //Finishes the xmlHttpRequest
GM.xmlHttpRequest({ //Starts the xmlHttpRequest
method: "GET",
url: "https://mydramalist.com/search?q=" + (hasAnime !== undefined ? ChiakiFranchiseTitle : document.querySelector("[itemprop*='name']").innerText.split('\n')[0]) + '&adv=titles&ty=68,77,83,86',
onload: (response) => { //Starts the onload event listener
const MyDramaListDocument = new DOMParser().parseFromString(response.responseText, 'text/html'); //Parses the fetch response
if (MyDramaListDocument.querySelector(".m-b-sm") === null) { //If MyDramaList did not return any results
MyDramaListText = ''; //Display to the user that MyDramaList Won't be opened if OK is clicked
MyDramaListCheck = '✖ NOT Found on MyDramaList.'; //Display the confirmation that the anime doesn't have any adaptations found on MyDramaList
} //Finishes the if condition
} //Finishes the onload event listener
}); //Finishes the xmlHttpRequest
copyButton.addEventListener("click", () => {
navigator.clipboard.writeText(document.querySelector("[itemprop*='name']").innerText.split('\n')[0]); //Copy the entry title with symbols
}); //Detect the single mouse click
copyButton.addEventListener("dblclick", () => {
navigator.clipboard.writeText(document.querySelector("[itemprop*='name']").innerText.split('\n')[0].replace(/[^a-zA-Z0-9]+/g, " ")); //Copy the entry title without symbols
}); //Detect the double mouse click
copyButton.addEventListener("contextmenu", (e) => { //Detect a mouse click
hasAnime !== undefined ? navigator.clipboard.writeText(ChiakiTextData.join('').trim()) : ''; //Copy the array to the clipboard
e.preventDefault(); //Don't show the right-click default context menu
}); //Detect the mouse right click
hasAnime !== undefined ? copyButton.setAttribute("title", "Click To Copy Entry Title (+ Symbols)\n2 Clicks To Copy Entry Title (Without Symbols)\n\nRight click to Copy ALL Anime Only Entry Titles on The Broadcast Order With EP Numbers, Entry Types and Duration Times") : copyButton.setAttribute("title", "1 Click To Copy Entry Title (+ Symbols)\n2 Clicks To Copy Entry Title (Without Symbols)"); //Detect a mouse hover on the button and shows an explanation text
copyButton.setAttribute("style", "cursor: pointer;margin-left: 13px;height: 10px;width: 10px;background-size: cover;display: inline-block;transform: scale(1.8);vertical-align: top;margin-top: 7px;"); //The CSS for the copy button
copyButton.style.backgroundImage = `url(${document.querySelector(".dark-mode") !== null ? 'https://i.imgur.com/hIfOM22.png' : 'https://i.imgur.com/vU0m0ye.png'})`; //The copy button image
findButton.addEventListener("click", async () => { //Detect the mouse click and search for the anime title
if (location.pathname.split('/')[1] === 'manga' || confirm('If you want to search using the Entry Title instead of the Franchise Title\nPress OK')) { //Show the confirmation alert box text
ChiakiFranchiseTitle = document.querySelector("[itemprop*='name']").innerText.split('\n')[0]; //Change the Franchise title we got from Chiaki to the entry title (to search on mydramalist)
ChiakiFranchiseTitleWithSymbols = document.querySelector("[itemprop*='name']").innerText.split('\n')[0]; //Change the Franchise title we got from Chiaki to the entry title (to search on the mal club)
} //Finishes the if condition
if ([...ChiakiDocument.querySelectorAll('span.uk-text-muted.uk-text-small')].find(el => el.innerText.includes('TV')) !== null) { //If the Franchise has at least 1 entry that the type is TV
const response = await (await fetch('https://myanimelist.net/clubs.php?cid=5450')).text(); //Fetch
new DOMParser().parseFromString(response, 'text/html').body.innerText.search(ChiakiFranchiseTitleWithSymbols) > -1 ? MalClubText = '👍 Found on the [[ Live Action Adaptations ]] MAL Club' : MalClubText = '✖ NOT found on the [[ Live Action Adaptations ]] MAL Club'; //If the title is found on the MALClub, display the confirmation whether or not the anime has adaptations found on the MALClub
MyDramaListCheck.match('👍') !== null || MalClubText.match('👍') !== null ? IMDBAsianWiki = 'IMDB, AsianWiki' : IMDBAsianWiki = 'IMDB and AsianWiki'; //Change the IMDBAsianWiki variable depending on if mydramalist or the mal club returned any results or not
if (confirm('Franchise Title: ' + ChiakiFranchiseTitle + '\n\n' + MyDramaListCheck + '\n' + MalClubText + '\n\nDo you want to open ' + IMDBAsianWiki + MyDramaListText + ' to confirm that information and get more detailed info?')) { //Show the confirmation alert box text
open("https://www.imdb.com/find?s=tt&q=" + ChiakiFranchiseTitle + "&ref_=nv_sr_sm", "_blank"); //Open IMDB on a new tab
open("https://asianwiki.com/index.php?title=Special%3ASearch&search=" + ChiakiFranchiseTitle, "_blank"); //Open AsianWiki on a new tab
if (MyDramaListCheck.match('NOT') === null) { //If MyDramaList returned any results
open("https://mydramalist.com/search?q=" + ChiakiFranchiseTitle + '&adv=titles&ty=68,77,83,86', "_blank"); //Open MyDramaList on a new tab
} //Open MyDramaList on a new tab only if any results were found on the website
} //Finishes the if condition
} //Finishes the if condition
else { //If the anime doesn't have any entry type = TV
alert("This Franchise doesn't even have any TV type entries, it's very likely that there are adaptations of any kind for this Franchise, so there's no need to search."); //Show a message to the user
} //Finishes the else condition
}); //Finishes the event listener
findButton.setAttribute("title", "Search for Live-Actions/Doramas"); //Detects a mouse hover on the button and show the text Find Live-Actions
findButton.setAttribute("style", "cursor: pointer;margin-left: 15px;height: 10px;width: 10px;background-size: cover;display: inline-block;transform: scale(1.8);vertical-align: top;margin-top: 7px;"); //The CSS for the findButton
findButton.style.backgroundImage = `url(${document.querySelector(".dark-mode") !== null ? 'https://i.imgur.com/TEPmlyF.png' : 'https://i.imgur.com/2XQm3qI.png'})`; //The find button image
function Append(element) { //Creates a new Append function
document.querySelector(".title-english") === null ? document.querySelector("[itemprop*='name']").append(element) : document.querySelector(".title-english").previousElementSibling.parentNode.insertBefore(element, document.querySelector(".title-english").previousElementSibling); //Append depending on if the entry has an English title or not
} //Finishes the Append function
chiakiButton.addEventListener('mousedown', async function(e) { //Detects when the user middle clicks on the chiakiButton
if (e.button === 1 && hasAnime !== undefined) //If the middle mouse button was clicked
{ //Starts the if condition
e.preventDefault(); //Prevent the default middle button action from executing
const response = await (await fetch('https://myanimelist.net/forum/?topicid=1890672')).text(); //Fetch
const GuideIndexnewDocument = new DOMParser().parseFromString(response, 'text/html'); //Parses the fetch response
const GuideIndexLinkElement = [...GuideIndexnewDocument.querySelectorAll('b')].find(el => el.innerText.includes('|' + entryid + '|')); //Gets the topic element that probably has the link of the Franchise and adds that to a variable
if (GuideIndexLinkElement !== undefined) { //If the anime id was found on the guide index
if (GuideIndexLinkElement.previousElementSibling.innerText.match('あ') !== null) { //If the anime name has the あ symbol in it on the guide index
alert('Recommended watch order:\nBroadcast order.'); //Shows an alert
} //Finishes the if condition
else { //If the anime name doesn't have the あ symbol in it on the guide index
alert('Recommended watch order:\nAEGC Guide Order.'); //Shows a text
} //Finishes the if condition
open(GuideIndexLinkElement.previousElementSibling.href, "_blank"); //Opens the GuideIndexLink on a new tab, and specifies that the GuideIndexLink should be opened on a new tab
} //Finishes the if condition
else { //If the anime ID was NOT found on the guide index
const NotFoundMessage = document.createElement("a"); //Creates an a element
NotFoundMessage.innerHTML = "<br>Not found on the AEGC Club!<br>Only chiaki.site will be opened.<br>"; //Defines the element text
NotFoundMessage.setAttribute("style", "font-size: 80%;text-decoration: none;"); //Set the CSS for the button
Append(NotFoundMessage); //Append the NotFoundMessage close to the title element
setTimeout(function() {
open("https://chiaki.site/?/tools/watch_order/id/" + entryid, "_blank");
}, 1000); //Open chiaki.site on a new tab
} //Finishes the else condition
const FinalArray = ChiakientryidSArray.filter(d => !GuideIndexnewDocument.querySelector(".body.clearfix").innerText.match(/(?<=\|\b)\d+/gi).includes(d)); //Get the ids that chiaki.site has and the Guide is missing
const GuideMissingIds = document.createElement("div"); //Creates a div element
GuideMissingIds.setAttribute("style", "font-size: 80%;display: none;"); //Set the CSS for the button
FinalArray.forEach(function(entryid) { //For every anime id that the guide index is missing
GuideMissingIds.innerHTML += GuideMissingIds.innerHTML = `<br><a href="https://myanimelist.net/anime/${entryid}">https://myanimelist.net/anime/${entryid}</a>`; //Add to the GuideMissingIds div a line break + the anime link with the link as text too
}); //Finishes the foreach condition
if (FinalArray.length !== 0 && FinalArray.length !== ChiakientryidSArray.length) { //If there's at least 1 missing id on the guide index and if the guide index is not missing the same amount of total links that Chiaki has for the franchise
var LinksButton = document.createElement("button"); //Creates a button element
LinksButton.innerHTML = 'Show AEGC Club Missing Links'; //Defines the element text
LinksButton.setAttribute("style", "margin-left: 10px;"); //Set the CSS for the button
LinksButton.onclick = function() { //Detects the mouse click on the Show Links Button
if (GuideMissingIds.style.display === "none") { //If the Show missing links button is hidden
GuideMissingIds.style.display = ''; //Show the missing links button
LinksButton.innerHTML = 'Hide AEGC Club Missing Links'; //Defines the element text
} else { //If the Show missing links button is being shown
GuideMissingIds.style.display = "none"; //Hide the missing links button
LinksButton.innerHTML = 'Show AEGC Club Missing Links'; //Defines the element text
} //Finishes the else condition
}; //FInishes the onclick event listener
Append(LinksButton); //Display the button to show the IDs that chiaki.site has and the Guide is missing
Append(GuideMissingIds); //Display the IDs that chiaki.site has and the Guide is missing
} //Finishes the if condition
if (GuideIndexLinkElement !== undefined && FinalArray.length === ChiakientryidSArray.length - 1) { //If the anime id was found on the guide index and the missing links are equal to all of the chiaki.site total links -1
LinksButton.remove(); //Remove the button that shows the missing links
const TwoFranchises = document.createElement("a"); //Creates an a element
TwoFranchises.innerHTML = "<br>It seems that this entry is related to 2 Anime Franchises.<br>Both chiaki.site and the AEGC Club will be opened."; //Defines the element text
TwoFranchises.setAttribute("style", "font-size: 80%;text-decoration: none;"); //Set the CSS for the button
Append(TwoFranchises); //Append the NotFoundMessage close to the title element
open("https://chiaki.site/?/tools/watch_order/id/" + entryid, "_blank"); //Opens chiaki.site on a new tab to show all the related anime entries on MAL on the correct watch order for the anime franchise and specifies that chiaki.site should be opened on a new tab
} //Finishes the if condition
if (GuideIndexnewDocument.querySelector(".body.clearfix").innerText.match(new RegExp('(?:\\|' + entryid + '\\|)', 'gi')).length > 1) { //If 2 identical anime ids were found on the guide index
const OtherFranchiseMessage = document.createElement("a"); //Creates an a element
OtherFranchiseMessage.innerHTML = "<br>According to the AEGC club this entry also has another related entry that chiaki.site consider as being from another franchise."; //Defines the element text
OtherFranchiseMessage.setAttribute("style", "font-size: 80%;text-decoration: none;"); //Set the CSS for the button
Append(OtherFranchiseMessage); //Append the OtherFranchiseMessage close to the title element
} //Finishes the if condition
} //Finishes the if condition
}); //Finishes the mousedown event listener
chiakiButton.addEventListener("click", () => { //Detect the mouse click
open(hasAnime !== undefined ? "https://chiaki.site/?/tools/watch_order/id/" + entryid : "https://relatedanime.com/manga/" + entryid, "_blank"); //Opens chiaki.site on a new tab to show all the related anime entries on MAL on the correct watch order for the anime franchise and specifies that chiaki.site should be opened on a new tab
}); //Finishes the addEventListener click
chiakiButton.addEventListener("contextmenu", (e) => { //Detect a mouse click
open(hasAnime !== undefined ? "https://relatedanime.com/anime/" + entryid : "https://relatedanime.com/manga/" + entryid, "_blank"); //Open relatedanime.com on a new tab to show all the related anime entries on MAL on the correct watch order for the anime franchise, including reading material
e.preventDefault(); //Don't show the right-click default context menu
}); //Detect the mouse right click
chiakiButton.setAttribute("style", "cursor: pointer;margin-left: 15px;height: 10px;width: 10px;background-size: cover;display: inline-block;transform: scale(1.8);vertical-align: top;margin-top: 7px;"); //The CSS for the chiakiButton
chiakiButton.setAttribute("title", hasAnime !== undefined ? "Click to see all related anime entries only on the Broadcast Watch Order\nMiddle Click to see all related anime entries only on the Broadcast/Chronological Watch Order\nRight Click to see all related entries on the Broadcast Watch Order. (Including reading material)" : "This franchise has no anime adaptations!\nClick to open relatedanime.com to show all related entries on the Broadcast Watch Order. (Including reading material)"); //Detects a mouse hover on the button and shows some text info
chiakiButton.style.backgroundImage = `url(${hasAnime !== undefined ? 'https://i.imgur.com/i635kBp.png' : 'https://i.imgur.com/7tUhvqf.png'})`; //The chiaki.site/relatedanime.com button favicon
Append(copyButton); //Append the button next to the title element
Append(findButton); //Append the button next to the title element
Append(chiakiButton); //Append the button next to the title element
} //Finishes the else condition
} //Finishes the Prog function
} //Finishes the if condition
Prog(); //Run the program
window.addEventListener('focus', () => { Prog(); }, { once: true }); //Run the program when the tab gets focus
})(); //Finishes the whole function