Approved Entries Notifier - MAL

This script auto performs a few checks daily to notify you when specific anime/manga entries gets approved or denied.

Per 29-06-2021. Zie de nieuwste versie.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         Approved Entries Notifier - MAL
// @namespace    NotifyWhenApproved
// @version      0.1
// @description  This script auto performs a few checks daily to notify you when specific anime/manga entries gets approved or denied.
// @author       hacker09
// @match        https://myanimelist.net/*
// @icon         https://www.google.com/s2/favicons?domain=myanimelist.net
// @run-at       document-end
// @grant        GM_setClipboard
// @grant        GM_notification
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(async function() {
  'use strict';
  var ActualTime = new Date().getHours(); //Save the actual time in a variable
  var UnnapprovedAnimes = []; //Store all the unapproved animes in this array later
  var UnnapprovedMangas = []; //Store all the unapproved mangas in this array later
  var ChecknapprovedAnimes = []; //Store all the animes stored in tampermonkey in this array later
  var CheckapprovedMangas = []; //Store all the mangas stored in tampermonkey in this array later
  var ApprovedAnimeLinks = []; //Create a new blank array
  var ApprovedMangaLinks = []; //Create a new blank array
  var Three_Hours_From_LastTime = new Date(new Date().setHours(GM_getValue('Last_Check_Hour') + 3)).getHours(); //Check when it's going to be 3 hours from the last check time
  var EntryType = location.pathname.split('/')[1]; //Store the Entry type
  var EntryID = location.pathname.match(/\d+/)[0]; //Store the Entry ID

  GM_listValues().forEach(function(a) { //For each stored value on tampermonkey
    if (a.match('anime') !== null) //If the saved value is an anime id
    { //Starts the if condition
      ChecknapprovedAnimes.push(a.match(/\d+/)[0]); //Add the stored anime id to an array
    } //Finishes the if condition
    if (a.match('manga') !== null) //If the saved value is a manga id
    { //Starts the if condition
      CheckapprovedMangas.push(a.match(/\d+/)[0]); //Add the stored manga id to an array
    } //Finishes the if condition
  }); //Add all Entry IDs and types on tampermonkey to the array

  if (GM_getValue('Last_Check_Hour') === undefined || GM_getValue('Last_Day_MAL_Was_Opened') === undefined || GM_getValue('Last_Check_Hour') >= Three_Hours_From_LastTime || (GM_getValue('Last_Check_Hour') <= Three_Hours_From_LastTime && new Date().getDate() !== GM_getValue('Last_Day_MAL_Was_Opened'))) //If the Last_Check_Hour or the Last_Day_MAL_Was_Opened variables wasn't set yet
  //Or if 3 or more hours since the last check time has passed
  //Or if the actual time is before the 3 hours from the last check time and if today is a another day
  { //Starts the if condition
    GM_setValue('Last_Check_Hour', ActualTime); //Get and save the last check hour
    GM_setValue('Last_Day_MAL_Was_Opened', new Date().getDate()); //Get and save the Last_Day_MAL_Was_Opened

    const response = await fetch(`https://api.allorigins.win/raw?url=${encodeURIComponent('https://sean.fish/mal_unapproved/anime')}`); //Fetch
    const html = await response.text(); //Gets the fetch response
    const newDocument = new DOMParser().parseFromString(html, 'text/html'); //Parses the fetch response
    newDocument.querySelectorAll("#mal-unapproved > ol > li").forEach(a => UnnapprovedAnimes.push(a.innerText.match(/\d+/)[0])); //Store all unnapproved anime entries on the array
    const response2 = await fetch(`https://api.allorigins.win/raw?url=${encodeURIComponent('https://sean.fish/mal_unapproved/manga')}`); //Fetch
    const html2 = await response2.text(); //Gets the fetch response
    const newDocument2 = new DOMParser().parseFromString(html2, 'text/html'); //Parses the fetch response
    newDocument2.querySelectorAll("#mal-unapproved > ol > li").forEach(a => UnnapprovedMangas.push(a.innerText.match(/\d+/)[0])); //Store all unnapproved manga entries on the array

    var FinalApprovedAnimesArray = ChecknapprovedAnimes.filter(d => !UnnapprovedAnimes.includes(d)); //Get the entry ids that the user is waiting to be approved but sean's website are missing
    var FinalApprovedMangasArray = CheckapprovedMangas.filter(d => !UnnapprovedMangas.includes(d)); //Get the entry ids that the user is waiting to be approved but sean's website are missing

    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 sean's website (the entry got approved)
    { //Starts the if condition
      FinalApprovedAnimesArray.forEach(a => ApprovedAnimeLinks.push('https://myanimelist.net/anime/' + a)); //Create an array of approved anime links
      FinalApprovedMangasArray.forEach(a => ApprovedMangaLinks.push('https://myanimelist.net/manga/' + a)); //Create an array of approved manga links

      window.onload = function() { //Starts the function when the website finished loading
        GM_notification({ //Shows a browser notification
          title: 'Found Approved Entries',
          text: 'Click on here to open or copy the approved entries links',
          image: 'https://i.imgur.com/RmsXhIl.jpg',
          highlight: true,
          silent: true,
          timeout: 15000, //Define the browser notification details
          onclick: () => { //If the browser notification is clicked

            if (FinalApprovedAnimesArray.length !== 0 || FinalApprovedMangasArray.length !== 0) //If there's at least 1 entry id we want to know when is approved is not on sean's website (the anime got approved)
            { //Starts the if condition
              var JoinedArrays = ApprovedAnimeLinks.concat(ApprovedMangaLinks); //Join both arrays
              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
                JoinedArrays.forEach(a => window.open(a, '_blank')); //Open all the approved entries links
              } //Finishes the if condition
              else //If the user clicked on Cancel
              { //Starts the else condition
                GM_setClipboard(JoinedArrays.join('\n')); //Copy the approved entries links
              } //Finishes the else condition
            } //Finishes the if condition

            window.focus(); //Refocus on the actual tab
            FinalApprovedAnimesArray.forEach(a => GM_deleteValue('anime' + a)); //Erase all the approved animes IDs stored on tampermonkey
            FinalApprovedMangasArray.forEach(a => GM_deleteValue('manga' + a)); //Erase all the approved mangas IDs stored on tampermonkey
          } //Finishes the onclick event listener
        }); //Finishes the browser notification definitions
      }; //Finishes the onload event listener

    } //Finishes the if condition
  } //Finishes the if condition

  if (document.querySelector("span.disabled-btn-user-status-add-list") !== null) //If an unapproved entry was opened
  { //Starts the if condition
    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
    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
    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
    { //Starts the onclick listener
      GM_notification({ //Shows a browser notification
        title: "You will be notified when this entry get's approved!",
        text: ' ',
        image: 'https://i.imgur.com/RmsXhIl.jpg',
        highlight: true,
        silent: true,
        timeout: 2000, //Define the browser notification details
        onclick: () => { //If the browser notification is clicked
          window.focus(); //Refocus on the tab
        } //Finishes the onclick event listener
      }); //Finishes the browser notification definitions
      GM_setValue(EntryType + EntryID, ''); //Get and save the Entry type and entry id
    } //Finishes the onclick listener
    document.querySelector("div.js-myinfo-error.badresult-text.al.pb4").remove(); //Remove the error message
  } //Finishes the if condition
})();