Cpt_mathix / MyAnimeList(MAL) - Anime/Manga Entries Compare

// ==UserScript==
// @name           MyAnimeList(MAL) - Anime/Manga Entries Compare
// @description    This script compares anime and manga entries from your userlists with entries from anime detail page and bold similar ones
// @include        /^https?:\/\/myanimelist\.net\/(anime|manga)\/\d+/
// @include        *://myanimelist.net/(anime|manga).php?id=*
// @exclude        /^https?:\/\/myanimelist\.net\/(anime|manga)\/[^0-9]+/
// @exclude        /^https?:\/\/myanimelist\.net\/(anime|manga)\/\d+\/.+\/.+/
// @version        1.1.8
// @author         Cpt_mathix
// @grant          GM_getValue
// @grant          GM_setValue
// @licence        GPL-2.0+; http://www.gnu.org/licenses/gpl-2.0.txt
// @namespace https://greasyfork.org/users/16080
// ==/UserScript==

// get user
var user = document.getElementsByClassName('header-profile-link')[0];
if (user) {
	user = user.textContent;
	init();
} else {
	console.log('Not logged in (Anime/Manga Entries Compare)');
}

var version = "1.1.8";
var requestCount = 0;

var allElements;

function init() {
	// get header (copy of bastvera's script)
	var AnchorLink;
	var allTextareas = document.getElementsByTagName('H2');
	for(var element in allTextareas){
		if(/EditRelated/.test(allTextareas[element].textContent))
			AnchorLink = allTextareas[element];
	}

	if (AnchorLink) {
        // get Anime/Manga Entries on current page
        allElements = document.evaluate(
            '//*[contains(@class, "anime_detail_related_anime")]//a[@href]',
            document,
            null,
            XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
            null);

		activateScript();
	}
}

function activateScript() {
    console.log('Running script: Anime/Manga Entries Compare');
    loadRSS(user, "anime", "rw");
    loadRSS(user, "manga", "rm");
}

function runScript(type, list) {
    var linkEl, href, self;
    if (type === "anime") {
        for (var i = 0; i < allElements.snapshotLength; i++){
            linkEl= allElements.snapshotItem(i);
            href = linkEl.href;

            // compare Anime Entries with your list
            if (/http.*:\/\/myanimelist\.net\/anime\/\d+/.test(href)) {
                var animeid = href.match(/\d+/g)[0];
                self = animeid.search(document.location.href.match(/\d+/g)[0]);
                if (self == -1 && haveListHit(list, animeid)) {
                    linkEl.style.fontWeight="bold";
                }
            }
        }
    } else if (type === "manga") {
        for (var j = 0; j < allElements.snapshotLength; j++){
            linkEl= allElements.snapshotItem(j);
            href = linkEl.href;

            // compare Manga Entries with your list
            if (/http.*:\/\/myanimelist\.net\/manga\/\d+/.test(href)) {
                var mangaid = href.match(/\d+/g)[0];
                self = mangaid.search(document.location.href.match(/\d+/g)[0]);
                if (self == -1 && haveListHit(list, mangaid)) {
                    linkEl.style.fontWeight= "bold";
                }
            }
        }
    }
}

function haveListHit(list, id) {
    return list[id];
}

function loadRSS(user, type, query) {
    makeRequest('GET', '/rss.php?type=' + query + '&u=' + user).then(function(rss) {
        var lastUpdate = rss.getElementsByTagName('pubDate')[0].textContent;
        var cachedDate = getCacheDate(type + "rss");

        if (lastUpdate == cachedDate) {
            console.log('Processing cached ' + type + 'list...');
            runScript(type, getUserList(type));
        } else {
            console.log('Cached ' + type + ' data not up to date!');
            setCacheDate(type + "rss", lastUpdate);

            loadUserList(user, type);
        }
    }).catch(function(err) {
        console.log(err);
        console.log(type + ' RSS feed failed to load');
        var lastUpdate = new Date();
        var cachedDate = new Date(getCacheDate(type + "list"));

        if (lastUpdate - cachedDate < 86400000 && lastUpdate - cachedDate > 0) {
            console.log('Processing cached ' + type + 'list...');
            runScript(type, getUserList(type));
        } else {
            console.log('Cached ' + type + ' data not up to date!');

            loadUserList(user, type);
        }
    });
}

function loadUserList(user, type) {
    makeRequest('GET', '/malappinfo.php?u=' + user + '&status=all&type=' + type + '').then(function (data) {
        var xmlDocument = data;

        // create a list that I can cache
        var rawList = xmlDocument.getElementsByTagName('series_' + type + 'db_id');
        var statusList = xmlDocument.getElementsByTagName('my_status');
        var set = {};
        for (var i = 0; i < rawList.length; i++) {
            set[rawList[i].textContent] = true;
        }

        setCacheDate(type + "list", new Date());
        setUserList(type, set);

        runScript(type, set);
    }).catch(function (err) {
        console.log("failed to load list, trying to grab cached list");
        runScript(type, getUserList(type));
    });
}

function makeRequest(method, url) {
    return new Promise(function (resolve, reject) {
        var xhr = new XMLHttpRequest();
        xhr.open(method, url);
        xhr.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                resolve(xhr.responseXML);
            } else {
                reject();
            }
        };
        xhr.onerror = function () {
            reject();
        };
        xhr.send();
    });
}

function getUserList(type) {
    var object = GM_getValue('MAL' + type + 'list');
    if (object)
        return JSON.parse(object);
    else {
        console.log("failed to get lists");
        return false;
    }
}

function setUserList(type, list) {
    GM_setValue('MAL' + type + 'list', JSON.stringify(list));
}

function getCacheDate(type) {
    var object = GM_getValue('CacheDate' + type + version);
    if (object)
        return JSON.parse(object);
    else
        return null;
}

function setCacheDate(type, value) {
    GM_setValue('CacheDate' + type + version, JSON.stringify(value));
}