Approved Entries Notifier - MAL

Auto-perform a few checks daily to notify you when specific anime/manga entries get approved or denied.

Installer dette script?
Skaberens foreslåede script

Du vil måske også kunne lide Forum Spoilers Hider - MAL

Installer dette script
  1. // ==UserScript==
  2. // @name Approved Entries Notifier - MAL
  3. // @namespace NotifyWhenApproved
  4. // @version 18
  5. // @description Auto-perform a few checks daily to notify you when specific anime/manga entries get approved or denied.
  6. // @author hacker09
  7. // @match https://myanimelist.net/*
  8. // @match https://purarue.xyz/mal_unapproved/*
  9. // @exclude https://purarue.xyz/mal_unapproved/
  10. // @icon https://t3.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://myanimelist.net&size=64
  11. // @run-at document-end
  12. // @grant GM_setClipboard
  13. // @grant GM_notification
  14. // @grant GM_deleteValue
  15. // @grant GM_listValues
  16. // @grant GM_openInTab
  17. // @grant GM_getValue
  18. // @grant GM_setValue
  19. // ==/UserScript==
  20.  
  21. (async function() {
  22. 'use strict';
  23. const TabTitle = document.title; //Save the current tab title
  24. const ActualTime = new Date().valueOf(); //Save the actual time in a variable
  25. const Three_Hours_From_LastTime = new Date().setTime(GM_getValue('Last_Check_Hour') + 2 * 3600000); //Check when it's going to be 2 hours from the last check time
  26. var ApprovedAnimeLinks = [], ApprovedMangaLinks = [], UnnapprovedAnimes = [], UnnapprovedMangas = [], CheckApprovedAnimes = [], CheckApprovedMangas = []; //Create new blank arrays
  27. //Convert the variable Three_Hours_From_LastTime from ms to the locale date new Date(new Date().setTime(Three_Hours_From_LastTime)).toLocaleString()
  28.  
  29. if (GM_getValue('HentaiNotifications') === undefined) //If the user didn't set the Hentai Notifications option
  30. { //Starts the if condition
  31. GM_setValue('HentaiNotifications', false); //Get and save the Hentai Notifications user choice, default the choice to false
  32. if (confirm('Click OK if you want to be notified when all new Hentai Anime entries are approved/denied')) //Ask the user choice
  33. { //Starts the if condition
  34. GM_setValue('HentaiNotifications', true); //Get and save the Hentai Notifications user choice
  35. } //Finishes the if condition
  36. } //Finishes the if condition
  37.  
  38. GM_listValues().forEach(function(el) { //For each stored value on tampermonkey
  39. if (el.match('anime') !== null) //If the saved value is an anime id
  40. { //Starts the if condition
  41. CheckApprovedAnimes.push(el); //Add the stored anime id to an array
  42. } //Finishes the if condition
  43. if (el.match('manga') !== null) //If the saved value is a manga id
  44. { //Starts the if condition
  45. CheckApprovedMangas.push(el); //Add the stored manga id to an array
  46. } //Finishes the if condition
  47. }); //Add all Entry IDs and types on tampermonkey to the array
  48.  
  49. if (location.host === 'myanimelist.net' && GM_getValue('Last_Check_Hour') === undefined || ActualTime >= Three_Hours_From_LastTime && GM_listValues().length > 1) { //If the Last_Check_Hour variable wasn't set yet, or if 2 or more hours since the last check time has passed, and if there's at least 1 stored entry on tampermonkey, and if the user is on MAL
  50. document.title = 'Checking Approved Entries'; //Change the tab title
  51. GM_setValue('Last_Check_Hour', ActualTime); //Get and save the last check hour
  52. const newDocument = await (await fetch('https://purarue.xyz/mal_unapproved/api/anime')).json(); //Parses the fetch response
  53. newDocument.forEach(function(el) { //For each currently unapproved anime
  54. if (GM_getValue('HentaiNotifications') === true && el.nsfw === true) //If the user wants to get hentai notifications and the unapproved anime is hentai
  55. { //Starts the if condition
  56. GM_setValue(el.id + 'anime', ''); //Get and save the Hentai Entry ID and the Entry type
  57. } //Finishes the if condition
  58. UnnapprovedAnimes.push(el.id); //Store all unapproved anime entries on the array
  59. }) //Finishes the For each loop
  60.  
  61. const newDocument2 = await (await fetch('https://purarue.xyz/mal_unapproved/api/manga')).json(); //Parses the fetch response
  62. newDocument2.forEach(el => UnnapprovedMangas.push(el.id)); //Store all unnapproved manga entries on the array
  63.  
  64. const FinalApprovedAnimesArray = CheckApprovedAnimes.filter(el => !UnnapprovedAnimes.includes(parseInt(el.match(/\d+/)[0]))); //Get the entry ids that the user is waiting to be approved but purarue's website is missing
  65. const FinalApprovedMangasArray = CheckApprovedMangas.filter(el => !UnnapprovedMangas.includes(parseInt(el.match(/\d+/)[0]))); //Get the entry ids that the user is waiting to be approved but purarue's website is missing
  66.  
  67. if (FinalApprovedAnimesArray.length !== 0 || FinalApprovedMangasArray.length !== 0) //If there's at least 1 entry ID we want to know that got approved and is not on purarue's website (the entry got approved)
  68. { //Starts the if condition
  69. FinalApprovedAnimesArray.forEach(el => ApprovedAnimeLinks.push('https://myanimelist.net/anime/' + el.match(/\d+/)[0])); //Create an array of approved anime links
  70. FinalApprovedMangasArray.forEach(el => ApprovedMangaLinks.push('https://myanimelist.net/manga/' + el.match(/\d+/)[0])); //Create an array of approved manga links
  71.  
  72. window.onload = function() { //Starts the function when the website finished loading
  73. GM_notification({ //Shows a browser notification
  74. title: 'Found Approved Entries',
  75. text: 'Click here to open or copy the approved entries links',
  76. image: 'https://i.imgur.com/RmsXhIl.jpg',
  77. highlight: true,
  78. silent: true,
  79. timeout: 15000, //Define the browser notification details
  80. onclick: () => { //If the browser notification is clicked
  81.  
  82. const JoinedArrays = ApprovedAnimeLinks.concat(ApprovedMangaLinks); //Join both arrays
  83. if (confirm('Click on OK to open ' + JoinedArrays.length + ' approved entries links\nClick on Cancel to copy ' + JoinedArrays.length + ' approved entries links')) { //Give an option to the user
  84. JoinedArrays.forEach(el => GM_openInTab(el)); //Open all the approved entries links
  85. FinalApprovedAnimesArray.forEach(el => GM_deleteValue(el)); //Erase all the approved animes IDs stored on tampermonkey
  86. FinalApprovedMangasArray.forEach(el => GM_deleteValue(el)); //Erase all the approved mangas IDs stored on tampermonkey
  87. } //Finishes the if condition
  88. else //If the user clicks on Cancel
  89. { //Starts the else condition
  90. GM_setClipboard(JoinedArrays.join('\n')); //Copy the approved entries links
  91. FinalApprovedAnimesArray.forEach(el => GM_deleteValue(el)); //Erase all the approved animes IDs stored on tampermonkey
  92. FinalApprovedMangasArray.forEach(el => GM_deleteValue(el)); //Erase all the approved mangas IDs stored on tampermonkey
  93. } //Finishes the else condition
  94.  
  95. window.focus(); //Refocus on the actual tab
  96. } //Finishes the onclick event listener
  97. }); //Finishes the browser notification definitions
  98. }; //Finishes the onload event listener
  99.  
  100. } //Finishes the if condition
  101. document.title = TabTitle; //Return the original tab title
  102. } //Finishes the if condition
  103.  
  104. if (CheckApprovedAnimes.length !== 0 && CheckApprovedMangas.length !== 0) //If both arrays have values in them
  105. { //Starts the if condition
  106. var ALLAnimesAndMangasArray = CheckApprovedAnimes.concat(CheckApprovedMangas); //Get ALL the entry IDs that the user is waiting to be approved
  107. } //Finishes the if condition
  108. else if (CheckApprovedAnimes.length !== 0) //If the CheckApprovedAnimes array has values in it
  109. { //Starts the else condition
  110. ALLAnimesAndMangasArray = CheckApprovedAnimes; //Get ALL anime entry IDs that the user is waiting to be approved
  111. } //Finishes the else condition
  112. else //Only the CheckApprovedMangas array has values in it
  113. { //Starts the else condition
  114. ALLAnimesAndMangasArray = CheckApprovedMangas; //Get ALL manga entry IDs that the user is waiting to be approved
  115. } //Finishes the else condition
  116.  
  117. if (location.host === 'purarue.xyz') //If the user is on the purarue.xyz website
  118. { //Starts the if condition
  119. document.querySelector("div.buttons").insertAdjacentHTML('beforeend', '<a class="button" id="Storage" href="javascript:void(0);">Show only script ' + location.href.split('/')[4] + ' entries</a>'); //Add a BTN on the page
  120. document.querySelector("#Storage").onclick = function() { //When the script BTN is clicked
  121. document.querySelectorAll("#mal-unapproved > ol > li").forEach(function(el) { //For each currently unapproved entry
  122. if (ALLAnimesAndMangasArray.includes(el.innerText.match(/\d+/)[0] + location.href.split('/')[4]) !== true) //If the unapproved entry is not on the script storage
  123. { //Starts the if condition
  124. el.remove(); //Remove of the website view
  125. } //Finishes the if condition
  126. }) //Finishes the forEach condition
  127. }; //Finishes the onclick event listener
  128. } //Finishes the if condition
  129.  
  130. if (document.querySelector("span.disabled-btn-user-status-add-list") !== null && location.host === 'myanimelist.net') //If an unapproved entry was opened and if the user is on MAL
  131. { //Starts the if condition
  132. document.querySelector("span.disabled-btn-user-status-add-list").className = 'btn-user-status-add-list js-form-user-status js-form-user-status-btn myinfo_addtolist'; //Make the button look better
  133.  
  134. const entryid = location.pathname.match(/\d+/)[0]; //Detect the entry id
  135. if (ALLAnimesAndMangasArray.includes(entryid + location.pathname.split('/')[1]) === true) //If the current entry id is on the waiting to be approved script list
  136. { //Starts the if condition
  137. document.querySelector("span.btn-user-status-add-list.js-form-user-status.js-form-user-status-btn.myinfo_addtolist").innerText = 'Already waiting for Approval'; //Show to the user that the user will already get notified to know when the entry gets approved
  138. } //Finishes the if condition
  139. else //If the current entry ID is not the waiting for Approval script list
  140. { //Starts the else condition
  141. document.querySelector("span.btn-user-status-add-list.js-form-user-status.js-form-user-status-btn.myinfo_addtolist").innerText = 'Notify when Approved'; //Give the user the option to get notified to know when the entry gets approved
  142. document.querySelector("span.btn-user-status-add-list.js-form-user-status.js-form-user-status-btn.myinfo_addtolist").onclick = function() //If the Notify when Approved button is clicked
  143. { //Starts the onclick listener
  144. GM_notification({ //Shows a browser notification
  145. title: "You will be notified when this entry gets approved!",
  146. text: ' ',
  147. image: 'https://i.imgur.com/RmsXhIl.jpg',
  148. highlight: true,
  149. silent: true,
  150. timeout: 2000, //Define the browser notification details
  151. onclick: () => { //If the browser notification is clicked
  152. window.focus(); //Refocus on the tab
  153. } //Finishes the onclick event listener
  154. }); //Finishes the browser notification definitions
  155.  
  156. GM_setValue(location.pathname.match(/\d+/)[0] + location.pathname.split('/')[1], ''); //Get and save the Entry id and entry type
  157. }; //Finishes the onclick listener
  158. } //Finishes the else condition
  159. document.querySelector("div.js-myinfo-error.badresult-text.al.pb4").remove(); //Remove the error message
  160. } //Finishes the if condition
  161. })();