Average Reviews Calculator for MAL

Transform MAL into Rotten Tomatoes

Per 05-11-2020. 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_link:Tampermonkey}.

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 Average Reviews Calculator for MAL
// @namespace Transform MAL into Rotten Tomatoes
// @version 0.3
// @description Transform MAL into Rotten Tomatoes
// @author Only_Brad
// @include /^https:\/\/myanimelist\.net\/(anime|manga)\/[\d]+\/.*\/reviews/
// @run-at document-end
// @grant GM_addStyle
// ==/UserScript==
(async function(){
const
REVIEWS_TAB_SELECTOR = "#content > table > tbody > tr > td:nth-child(2) > div.js-scrollfix-bottom-rel",
SCORE_TABLES_SELECTOR = "table.borderClass",
OVERALL_RATING_SELECTOR = "tbody > tr > td:nth-child(2) > strong",
SEPERATOR_SELECTOR = ".reviews-horiznav-nav-sort-block";

const
currentUrl = window.location.href,
firstPageUrl = getFirstPageUrl(),
currentPage = getCurrentPage(),
score = setPlaceholderScore();

showAverageOverallScore();

function setPlaceholderScore() {
const separator = document.querySelector(SEPERATOR_SELECTOR);
const score = document.createElement("div");
score.style = "padding: 15px 0 15px 10px;";
score.textContent = "Calculating total average review score...";
separator.insertAdjacentElement("afterend",score);
return score;
}

async function showAverageOverallScore() {
const overallScores = await getAllOverallScore();
const average = overallScores.reduce((acc,val)=>acc+val,0)/overallScores.length;
score.textContent = "Average score: "+average.toFixed(2);
}

async function getAllOverallScore() {
        const NB_OF_SIMULTANOUS_DL = 5;
        const overallScores = [];

        let httpRequests = [];
        let i = 1;
        let loopCount = 1;

        while (true) {
            for (i; i <= NB_OF_SIMULTANOUS_DL * loopCount; i++) {
                httpRequests.push(getDocument(i));
            }
            const documents = await Promise.all(httpRequests);

            for (const currentDocument of documents) {
                if (hasReviews(currentDocument))
                    overallScores.push(getOverallScores(currentDocument));
                else
                    return overallScores.flat();
            }

            httpRequests = [];
            loopCount++;
        }
    }

async function getDocument(pageNumber) {
let currentDocument;
if(pageNumber === currentPage) currentDocument = document;
else {
const url = pageNumber === 1 ? firstPageUrl : `${firstPageUrl}?p=${pageNumber}`;
const response = await fetch(url);
const html = await response.text();
currentDocument = new DOMParser().parseFromString(html,"text/html");
}
return currentDocument;
}

function getOverallScores(document) {
const reviewsTab = document.querySelector(REVIEWS_TAB_SELECTOR);
const scoreTables = reviewsTab.querySelectorAll(SCORE_TABLES_SELECTOR);
return [...scoreTables].map(table => parseInt(table.querySelector(OVERALL_RATING_SELECTOR).textContent));
}

function hasReviews(document) {
const reviewsTab = document.querySelector(REVIEWS_TAB_SELECTOR);
const scoreTables = reviewsTab.querySelectorAll(SCORE_TABLES_SELECTOR);
return scoreTables.length > 0;
}

function getFirstPageUrl() {
const PAGE_REGEX = /\?p=[\d]+/;
const search = currentUrl.search(PAGE_REGEX);

if(search !== -1) return currentUrl.substring(0,search);
return currentUrl;
}

function getCurrentPage() {
const PAGE_REGEX = /\?p=[\d]+/;
const match = currentUrl.match(PAGE_REGEX);

if(match) return parseInt(match[1]);
else return 1;
}
})()