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 30-10-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.10
// @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 ApprovedAnimeLinks = []; //Create a new blank array
  var ApprovedMangaLinks = []; //Create a new blank array
  var entryid = location.pathname.match(/\d+/)[0]; //Detect the entry id
  var ActualTime = new Date().valueOf(); //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 CheckApprovedAnimes = []; //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 Three_Hours_From_LastTime = new Date().setTime(GM_getValue('Last_Check_Hour') + 3 * 3600000); //Check when it's going to be 3 hours from the last check time
  //Convert the variable Three_Hours_From_LastTime from ms to the locale date new Date(new Date().setTime(Three_Hours_From_LastTime)).toLocaleString()

  if (GM_getValue('HentaiNotifications') === undefined) //If the user didn't set the Hentai Notifications option
  { //Starts the if condition
    GM_setValue('HentaiNotifications', false); //Get and save the Hentai Notifications user choice,default the choice to false
    if (confirm('Click OK if you want to be notified when all new Hentai Anime entries are approved/denied')) //Ask the user choice
    { //Starts the if condition
      GM_setValue('HentaiNotifications', true); //Get and save the Hentai Notifications user choice
    } //Finishes the if condition
  } //Finishes the if condition

  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
      CheckApprovedAnimes.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 || ActualTime >= Three_Hours_From_LastTime && GM_listValues().length > 1) { //If the Last_Check_Hour variable wasn't set yet, or if 3 or more hours since the last check time has passed, and if there's at least 1 stored entry on tampermonkey
    GM_setValue('Last_Check_Hour', ActualTime); //Get and save the last check hour
    var TabTitle = document.title; //Save the current tab title
    document.title = 'Checking Approved Entries'; //Change the tab title

    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(function(a) { //For each currently unnaproved anime
      if (GM_getValue('HentaiNotifications') === true && a.innerText.match(/\n(\d+)(?= (.+)\n\[NSFW\])/) !== null) //If the user want's to get hentai notifications and the unnapproved anime is hentai
      { //Starts the if condition
        GM_setValue('anime' + a.innerText.match(/\n(\d+)(?= (.+)\n\[NSFW\])/)[1], ''); //Get and save the Entry type and Hentai Entry ID
      } //Finishes the if condition
      UnnapprovedAnimes.push(a.innerText.match(/\d+/)[0]); //Store all unnapproved anime entries on the array
    }) //Finishes the For each loop

    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 = CheckApprovedAnimes.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 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
                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 if condition
              else //If the user clicked on Cancel
              { //Starts the else condition
                GM_setClipboard(JoinedArrays.join('\n')); //Copy the approved entries links
                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 else condition
            } //Finishes the if condition

            window.focus(); //Refocus on the actual tab
          } //Finishes the onclick event listener
        }); //Finishes the browser notification definitions
      }; //Finishes the onload event listener

    } //Finishes the if condition
    document.title = TabTitle; //Return the original tab title
  } //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

    if (CheckApprovedAnimes.length !== 0 && CheckApprovedMangas.length !== 0) //If both arrays have values in them
    { //Starts the if condition
      var ALLAnimesAndMangasArray = CheckApprovedAnimes.push(CheckApprovedMangas); //Get ALL the entry ids that the user is waiting to be approved
    } //Finishes the if condition
    else if (CheckApprovedAnimes.length !== 0) //If the CheckApprovedAnimes array has values in it
    { //Starts the else condition
      ALLAnimesAndMangasArray = CheckApprovedAnimes; //Get ALL anime entry ids that the user is waiting to be approved
    } //Finishes the else condition
    else //Only the CheckApprovedMangas array has values in it
    { //Starts the else condition
      ALLAnimesAndMangasArray = CheckApprovedMangas; //Get ALL manga entry ids that the user is waiting to be approved
    } //Finishes the else condition

    if (ALLAnimesAndMangasArray.includes(entryid) === true) //If there current entry id is on the waiting to be approved script list
    { //Starts the if condition
      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
    } //Finishes the if condition
    else //If there current entry id is not the waiting for Approval script list
    { //Starts the else condition
      document.querySelector("span.btn-user-status-add-list.js-form-user-status.js-form-user-status-btn.myinfo_addtolist").innerText = 'Alredy waiting for Approval'; //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").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(location.pathname.match(/\d+/)[0] + location.pathname.split('/')[1], ''); //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 else condition
  } //Finishes the if condition
})();