MyAnimeList(MAL) - Extra

Show anime info inside your animelist

目前為 2016-01-08 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         MyAnimeList(MAL) - Extra
// @version      3.0.1
// @description  Show anime info inside your animelist
// @author       Cpt_mathix
// @match        *://myanimelist.net/animelist/*
// @match        *://myanimelist.net/mangalist/*
// @license      GPL version 2 or any later version; http://www.gnu.org/licenses/gpl-2.0.txt
// @grant        GM_xmlhttpRequest
// @namespace https://greasyfork.org/users/16080
// ==/UserScript==

// -----------------------------------------SETTINGS----------------------------------------- //

var transparentNotYetAired = true; // set to false if you don't want "Not Yet Aired" transparent

// ------------------------------------------------------------------------------------------ //

var dataMap = [];
var dataArray = [];
var href = document.location.href;
var user = href.substr(href.lastIndexOf('/') + 1);

var type = [];
if(window.location.href.indexOf("mangalist") > -1) {
    type = ["manga",65];
} else {
    type = ["anime",64];
}

var xmlDoc;

initList();

function initList() {
    var table = document.getElementById("list_surround").children;
    for (var i = 0; i < table.length; i++) {
        var cell = table[i].getElementsByTagName('td');

        for (var j = 0; j < cell.length; j++) {  
            var hasMore = cell[j].innerHTML.search('More');
            
            if (hasMore != -1) {
                // get anime title
                var animeTitle = cell[j].getElementsByClassName('animetitle')[0].innerText.replace(/ /g,"-");
                
                // get titleid
                var a = cell[j].getElementsByTagName("a");
                var titleid = a[1].getAttribute('onclick').match(/\d.*,/g).join("").replace(',',"");

                // get table color type
                var tdtype = cell[j].className.match(/\d/g).join("");

                // replace onclick function with my own
                a[1].removeAttribute('onclick');
                a[1].addEventListener('click', displayTable(animeTitle, titleid, tdtype) , true); 
            }

            // Not Yet Aired transparant
            var found = cell[j].innerHTML.search('Not Yet Aired');
            if (found != -1 && transparentNotYetAired) {
                cell[j].setAttribute('style', 'opacity:0.50 !important');
                // table[i].setAttribute('style', 'display:none !important');
            }
            
        }
    }
}

//--------------------------------//
//       Get Data Functions       //
//--------------------------------//

/* 
function getAnimeInfoExternal(animeid, table) {
    $.get('http://myanimelist.net/includes/ajax.inc.php?t=' + type[1] + '&id=' + animeid, function(data) {
        $(data).filter('.dark_text').each(function() {
            dataArray.push(this.nextSibling.textContent);
        });
    });
} 
*/

function getAnimeInfo(animeid, table) {
    
    if (xmlDoc === undefined) {
        xmlDoc = getUserListInfo();
    }
    
    $.get('http://myanimelist.net/' + type[0] + '/' + animeid, function(data) {
        $(data).find('#content > table > tbody > tr > td.borderClass > div:nth-child(n) > span').each(function() {
            var item = this.textContent.replace(/:/g,"");
            if (isNaN(item) && (this.nextElementSibling === null || item == "Ranked")) {
                dataMap.push(item);
                dataArray.push(this.nextSibling.textContent);
            } else if (isNaN(item) && item.indexOf(',') == -1) {
                dataMap.push(item);
                var information = this.parentNode.children[1].outerHTML;      
                for(var i = 2; i < this.parentNode.children.length && item != "Score"; i++) { 
                    information += ", " + this.parentNode.children[i].outerHTML;
                }
                dataArray.push(information);
            }
        });
        $(data).find('#content > table > tbody > tr > td:nth-child(2) > table > tbody > tr:nth-child(1) > td > span').each(function() {
            dataMap.push('Synopsis');
            dataArray.push(this.innerHTML);
        });
        $(data).find('#content > table > tbody > tr > td:nth-child(2) > table > tbody > tr:nth-child(2) > td > table.anime_detail_related_anime > tbody > tr:nth-child(n) > td.ar.fw-n.borderClass').each(function() {
            var related = this.textContent.replace(/:/g,"");
            if (related == "Parent story") {
                dataMap.push('Parent');
                dataArray.push(this.nextElementSibling.innerHTML);
            } else if (related == "Side story" && this.nextElementSibling.children.length <= 3) {
                dataMap.push('Side');
                dataArray.push(this.nextElementSibling.innerHTML);
            } else if (related == "Prequel") {
                dataMap.push('Prequel');
                dataArray.push(this.nextElementSibling.innerHTML);
            } else if (related == "Sequel") {
                dataMap.push('Sequel');
                dataArray.push(this.nextElementSibling.innerHTML);
            } else if (related == "Alternative version") {
                dataMap.push('Alternative');
                dataArray.push(this.nextElementSibling.innerHTML);
            }
        });
        table.innerHTML = displayAnimeInfo(animeid);
    });
}

function getUserListInfo() {
    var xhr = new XMLHttpRequest();
    var url = 'http://myanimelist.net/malappinfo.php?u=' + user + '&status=all&type=' + type[0] + '';
    xhr.open("GET", url, false);
    xhr.setRequestHeader('Content-Type', 'text/xml');
    xhr.send();
    var xmlDocument = xhr.responseXML;
    return xmlDocument;
}

function getDataFromOriginalMore(preData) {
    var start = preData.indexOf('Time Spent Watching');
    var end = preData.indexOf('<small>(');
    dataMap.push('TimeSpentWatching');
    dataArray.push(preData.substring(start + 21, end));
    start = end;
    end = preData.indexOf('per episode');
    var episodeTime = preData.substring(start + 8, end);
    dataMap.push('EpisodeTime');
    dataArray.push(episodeTime);
}

//--------------------------------//
//     Display Data Functions     //
//--------------------------------//

// if this fails to function, look at getExpand(arg1, arg2) function on the myanimelist page
function displayTable(animetitle, animeid, tdtype) {   
    return function () {
        var moreObject = $('#more'+animeid);
        var memberId = $('#listUserId').val();

        if (moreObject.css('display') == 'block') {		// Hide if loaded
            moreObject.hide();
            return false;
        } 

        if (moreObject.children().length != 0 && xmlDoc !== undefined && moreObject[0].className == "Hide extraLoaded") {		// Show if data is already loaded
            moreObject.show();
            return false;
        }

        $.post("/includes/ajax-no-auth.inc.php?t=6", {color:tdtype,id:animeid,memId:memberId,type:$('#listType').val()}, function(data) {
            moreObject.html(data.html).show();

            // change info with info from API request
            var hiddendiv = "more" + animeid;
            var table = document.getElementById(hiddendiv).getElementsByClassName('td' + tdtype + ' borderRBL')[0];
            dataMap.length = 0;
            dataArray.length = 0;
            if (table !== null && type[0] != "manga") {
                getDataFromOriginalMore(table.innerHTML);
                table.innerHTML = "Fetching data";
                getAnimeInfo(animeid, table);
            } else if (table !== null) {
                table.innerHTML = "Fetching data";
                getAnimeInfo(animeid, table);
            }
            moreObject[0].className = moreObject[0].className + " extraLoaded";
        }, "json");
    };
}

function getDataValue(string) {
    var elementPos = dataMap.map(function(x) {return x; }).indexOf(string);
    if (dataArray[elementPos] === undefined)
        return "Unavailable";
    return dataArray[elementPos];
}

function getXmlEntry(animeid, string) {
    var entry = xmlDoc.getElementsByTagName(type[0]);
    var entryid = xmlDoc.getElementsByTagName('series_' + type[0] + 'db_id');    
    for(var k = 0; k < entryid.length; k++) {
        if (entryid[k].textContent == animeid) {
            return entry[k].getElementsByTagName('series_' + string)[0].textContent;
        }
    }
}

function calcTimeNeeded(episodeTime, totalEpisodes) {
    if (totalEpisodes.trim() == "0" || totalEpisodes == "Unknown") {
        return 'Unknown';
    } else if (episodeTime.indexOf("0 hours, 0 minutes, and 0 seconds") > -1) {
        return 'Unknown';
    } else if (totalEpisodes.trim() == "1") {
        return episodeTime;
    } else {
        var str = episodeTime.split(' ');
        
        var totalSeconds = parseInt(str[5]) * totalEpisodes + (parseInt(str[2]) * totalEpisodes * 60) + (parseInt(str[0]) * totalEpisodes * 60 * 60);
        var seconds = totalSeconds % 60;
        var totalMinutes = Math.floor(totalSeconds/60);
        var minutes = totalMinutes % 60;
        var hours = Math.floor(totalMinutes/60);
        
        return hours + " hours, " + minutes + " minutes and " + seconds + " seconds";
    }
}

function displayAnimeInfo(animeid) {
    var episodes = getDataValue('Episodes');
    var image = getXmlEntry(animeid, "image");
    var genres = getDataValue('Genres');
    var status = getDataValue('Status');
    var broadcast = getDataValue('Broadcast');
    var score = getDataValue('Score');
    var rank = getDataValue('Ranked').replace("#","");
    var popularity = getDataValue('Popularity').replace("#","");
    var studio = getDataValue('Studios');
    
    var parent = getDataValue('Parent');
    var side = getDataValue('Side');
    var prequel = getDataValue('Prequel');
    var sequel = getDataValue('Sequel');
    var alternative = getDataValue('Alternative');
    
    var synopsis = getDataValue('Synopsis').replace(/\(Source.*[\s\S]*/g,"").replace(/\[.*\]/g,"");
    
    var timeSpentWatching = getDataValue('TimeSpentWatching').replace("tes,","tes");
    var timeNeeded = 0;
    if (timeSpentWatching.indexOf("0 hours, 0 minutes and 0 seconds") > -1) {
        timeNeeded = calcTimeNeeded(getDataValue('EpisodeTime'), episodes);
    }
    
    var startDate = getXmlEntry(animeid, 'start').replace(/\d\d\d\d-\d\d-\d\d/g, function(s) {    
        var dmy = s.split('-');    
        return dmy[2] + '/' + dmy[1] + '/' + dmy[0];    
    });
    var endDate = "";
    if (startDate == "00/00/0000") {
        startDate = "N/A";
    } else {
        endDate = getXmlEntry(animeid, 'end').replace(/\d\d\d\d-\d\d-\d\d/g, function(s) {    
            var dmy = s.split('-');    
            return dmy[2] + '/' + dmy[1] + '/' + dmy[0];    
        }); 
        if (episodes.trim() == "1") {
            endDate = "";
        } else if (endDate == "00/00/0000") {
            endDate = " " + "to N/A";
        } else {
            endDate = " to " + endDate;
        }
    }

    // console.log(dataMap);
    // console.log(dataArray);

    var strVar="";
    strVar += "<body>";
    strVar += "<table>";
    strVar += "  <tr>";
    strVar += "    <td valign=\"top\" rowspan=\"4\">" + "<img src=" + image + ">" + "<\/td>";
    strVar += "    <td valign=\"top\" width=\"35%\">";
    if (status.indexOf("Currently Airing") > -1)
        strVar += "<b>" + "Broadcast:   " + "<\/b>" + broadcast + "<br>";
    strVar += "    <b>" + "Episodes: " + "<\/b>" + episodes + "<br>";
    strVar += "    <b>" + "Score:    " + "<\/b>" + score + "<br>";
    strVar += "    <b>" + "Rank: " + "<\/b>" + rank + "<br>";
    strVar += "    <b>" + "Popularity: " + "<\/b>" + popularity + "<br>";
    if (studio.indexOf("add some") == -1)
        studio.indexOf(",") > -1 ? (strVar += "<b>" + "Studios: " + "<\/b>" + studio + "<br>") : (strVar += "<b>" + "Studio: " + "<\/b>" + studio + "<br>");
    strVar += "    <b>" + "Aired: " + "<\/b>" + startDate + endDate + "<br>";
    strVar += "    <\/td>";
    strVar += "    <td valign=\"top\" align=\"right\" width=\"65%\">" + genres + "<\/td>";   
    strVar += "  <\/tr>";
    strVar += "  <tr>";
    strVar += "    <td valign=\"top\" colspan=\"2\" width=\"100%\" height=\"100%\">" + "<br>" + synopsis + "<\/td>";
    strVar += "  <\/tr>";
    strVar += "  <tr>";
    strVar += "    <td valign=\"bottom\" align=\"left\" height=\"5px\" width=\"50%\">";
    if (parent != "Unavailable")
        strVar += "<small>" + "<b>" + "Parent story: " + "<\/b>" + parent + "<\/small>";
    if (side != "Unavailable")
        strVar += "<br>" + "<small>" + "<b>" + "Side story: " + "<\/b>" + side + "<\/small>";
    if (prequel != "Unavailable")
        strVar += "<br>" + "<small>" + "<b>" + "Prequel: " + "<\/b>" + prequel + "<\/small>";
    if (sequel != "Unavailable")
        strVar += "<br>" + "<small>" + "<b>" + "Sequel: " + "<\/b>" + sequel + "<\/small>";
    if (alternative != "Unavailable")
        strVar += "<br>" + "<small>" + "<b>" + "Alternative version: " + "<\/b>" + alternative + "<\/small>";
    strVar += "    <\/td>";
    strVar += "    <td valign=\"bottom\" align=\"right\" colspan=\"2\">" + "<br>" + "<small>" + (timeNeeded == 0 ? ("<b>" + "Time Spent Watching: " + "<\/b>" + timeSpentWatching) : ("<b>" + "Time To Complete: " + "<\/b>" + timeNeeded)) + "<\/small>" + "<\/td>";
    strVar += "  <\/tr>";
    strVar += "<\/table>";
    strVar += "<\/body>";
        
    return strVar;
}