Better Related Anime/Manga Reader

Adds line breaks between each Synonyms/Spin-offs/Alternative versions/Sequels/Summary/Others and Side stories titles on entry pages.

安装此脚本?
作者推荐脚本

您可能也喜欢Approved Entries Notifier - MAL

安装此脚本
  1. // ==UserScript==
  2. // @name Better Related Anime/Manga Reader
  3. // @namespace ReadeableSequels
  4. // @version 13
  5. // @description Adds line breaks between each Synonyms/Spin-offs/Alternative versions/Sequels/Summary/Others and Side stories titles on entry pages.
  6. // @author hacker09
  7. // @include /^https:\/\/myanimelist\.net\/((anime|manga)(id=)?(\.php\?id=)?)(\/)?([\d]+)/
  8. // @icon https://t3.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://myanimelist.net&size=64
  9. // @run-at document-end
  10. // @connect api.myanimelist.net
  11. // @grant GM.xmlHttpRequest
  12. // @grant GM_deleteValue
  13. // @grant GM_listValues
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // ==/UserScript==
  17.  
  18. (function() {
  19. 'use strict';
  20. if (document.body.innerText.search("Synonyms:") > -1) //If the text "Synonyms:" exists on the page
  21. { //Starts the if condition
  22. function findTheSynonymsText() { //Create a function to get the Synonyms: Titles text
  23. return [...[...document.querySelectorAll("h2")].find(h2 => h2.textContent === "Information").parentNode.querySelectorAll("div")].find(info => info.innerText.includes("Synonyms:")).querySelector("span"); //Return the div that contains the Synonyms text
  24. } //Find the Synonyms text that's inside the information h2 element
  25.  
  26. if (GM_listValues().length >= 100) //If there's 100 anime ids and Synonyms titles stored on tampermonkey
  27. { //Starts the if condition
  28. GM_listValues().forEach(a => GM_deleteValue(a)); //Erase all the 100 stored anime IDs and their Synonyms titles stored on tampermonkey
  29. } //Finishes the if condition
  30.  
  31. if (findTheSynonymsText().nextSibling.textContent.match(', ') !== null) //If there's any commas on the Synonyms titles
  32. { //Starts the if condition
  33. var StoredEntryIDsArray = []; //Creates a new blank array
  34. const EntryID = location.pathname.match(/\d+/)[0]; //Store the Entry ID
  35. const EntryType = location.pathname.split('/')[1]; //Store the Entry Type
  36. GM_listValues().forEach(a => StoredEntryIDsArray.push('^' + a)); //Add all Entry IDs and types on tampermonkey to the array
  37. const StoredEntryIDsRegex = new RegExp(StoredEntryIDsArray.join('$|')); //Create a new variable and regex containing all the values saved on tampermonkey and replace the , separator with the or $| regex symbols
  38.  
  39. async function GetSynonyms() //Creates a function to get the Synonyms titles
  40. { //Starts the function
  41. var SynonymsTitlesAPI = await new Promise((resolve) => GM.xmlHttpRequest({ //Starts the xmlHttpRequest
  42. url: `https://api.myanimelist.net/v2/anime/${EntryID}?fields=alternative_titles`,
  43. headers: {
  44. "x-mal-client-id": "8ef0267fd86a187d479e6fcd7e1bb42a"
  45. },
  46. onload: r => resolve(r)
  47. })); //Finishes the xmlHttpRequest
  48. await new Promise(r => setTimeout(r, 500)); //Wait the xmlHttpRequest request to complete
  49.  
  50. if (SynonymsTitlesAPI.status !== 200) //If the API is being rated
  51. { //Starts the if condition
  52. throw ('The MAL API is being time rate limited!'); //Stop the script
  53. } //Finishes the if condition
  54.  
  55. findTheSynonymsText().parentNode.innerHTML = '<span class="dark_text">Synonyms:</span><div>' + JSON.parse(SynonymsTitlesAPI.responseText).alternative_titles.synonyms.join('<br><br>') + '</div>'; //Add the Synonyms Titles with break lines to the page
  56. GM_setValue(EntryType + EntryID, JSON.parse(SynonymsTitlesAPI.responseText).alternative_titles.synonyms.join('<br><br>')); //Get and save the Entry id, type and Synonyms Titles with break lines as a variable
  57. } //Finishes the async function
  58.  
  59. const EntryTypeANDID = EntryType + EntryID; //Join the Entry Type and ID into 1 string to use match latter
  60. if (EntryTypeANDID.match(StoredEntryIDsRegex) !== null && StoredEntryIDsRegex.toLocaleString() !== '/(?:)/') //If the current url Entry id and type matches an Entry id and type that is stored on tampermonkey, and if the Regex contains 1 or more Entry ids
  61. { //Starts the if condition
  62. findTheSynonymsText().parentNode.innerHTML = '<span class="dark_text" style="cursor: pointer;">Synonyms:</span><div>' + GM_getValue(EntryTypeANDID) + '</div>'; //Add the Synonyms Titles text content on the Synonyms: bold text
  63.  
  64. [...[...document.querySelectorAll("h2")].find(h2 => h2.textContent === "Information").parentNode.querySelectorAll("div")].find(info => info.innerText.includes("Synonyms:")).querySelector("span").addEventListener("click", function() { //When the bold Synonyms: text is clicked
  65. GetSynonyms(); //Update the Synonyms Titles
  66. }); //Finishes the onclick advent listener
  67. } //Finishes the if condition
  68. else //If the current url Entry id and type does NOT match any Entry id and type that is stored on tampermonkey
  69. { //Starts the else condition
  70. var TimesExecuted = 0; //Creates a new variable
  71.  
  72. window.onscroll = async function() { //Creates a new function to run when the page is scrolled
  73. TimesExecuted += 1; //Sum the amount of times that the page is scrolled
  74. if (TimesExecuted === 1) { //On the first time that the page is hovered
  75. GetSynonyms(); //Starts the function GetSynonyms
  76. } // //Finishes the if condition
  77. }; //Finishes the onscroll event listener
  78. } //Finishes the else condition
  79. } //Finishes the if condition
  80. } //Finishes the if condition
  81.  
  82. document.querySelectorAll("td[width*='100%']").forEach(function(el) { //For each listed entry rows
  83. el.childNodes.forEach(function(node) { //For each listed entry row childNodes elements
  84. node.nodeType === 3 ? node.replaceWith(document.createElement("br")) : ''; //If the element type is = 3 replace it with a line break
  85. }) //Finishes the for each loop
  86. }) //Finishes the for each loop
  87. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址