Average Reviews Calculator for MAL

Transform MAL into Rotten Tomatoes

05.11.2020 itibariyledir. En son verisyonu görün.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==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;
}
})()