MyAnimeList(MAL) - Extra

Show anime/manga info inside your animelist/mangalist

当前为 2016-05-13 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         MyAnimeList(MAL) - Extra
// @version      5.0.3
// @description  Show anime/manga info inside your animelist/mangalist
// @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
// @namespace https://greasyfork.org/users/16080
// ==/UserScript==

(function($) {
	var store = (function() {
		var map = {};

		return {
			set: function (name, value) {
				map[name] = value;
			},
			get: function (name) {
				return map[name];
			}
		};
	})();

	var mal = {
		href: document.location.href,
		modern: false,
		user: '',
		type: [],
		xmlDoc: undefined
	};

	init();

	function init() {
		mal.user = mal.href.match(/[^/]*?(?=\?|$)/)[0];

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

		mal.modern = $('.header .header-menu .btn-menu > .username').length > 0;
		console.log(mal.modern);

		if (mal.modern) {
			initModernList();
		} else {
			initOldList();
		}
	}

	function initOldList() {
		$('#list_surround > table > tbody > tr > td[class*=td]:nth-child(2)').each( function() {
			var id = $(this).find('> a').attr('href').match(/\/(\d+)\//)[1];
			var tdtype = $(this).attr('class').match(/\d/)[0];
			var moreEl = $(this).find('> div > small > a:nth-child(2)');
			var memberId = $('#listUserId').val();
			var moreObject = $("#more" + id);

			$(moreEl).removeAttr('onclick');
			$(moreEl).on('click', displayTable(id, tdtype, moreObject, memberId));
		});
	}

	function initModernList() {
		$('#list-container > div.list-block > div > table > tbody[class=list-item] > tr.list-table-data > td.data.title').each( function() {
			console.log(this);
			var id = $(this).find('> a').attr('href').match(/\/(\d+)\//)[1];
			var moreEl = $(this).find('> div > span.more > a');
			var memberId = $('body')[0].dataset.ownerId;
			var moreObject = $("#more-" + id);

			var el = $(moreEl)[0],
				elClone = el.cloneNode(true);
			el.parentNode.replaceChild(elClone, el);
			$(elClone).on('click', displayTable(id, 1, moreObject, memberId));
		});
	}

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

	function getAnimeInfo(animeid, table) {

		if (mal.xmlDoc === undefined) {
			mal.xmlDoc = getUserListInfo();
		}

		var dataMap = store.get(animeid + 'MAP');
		var dataArray = store.get(animeid + 'Array');

		$.get('http://myanimelist.net/' + mal.type[0] + '/' + animeid, function(data) {
			$(data).find('#content > table > tbody > tr > td.borderClass > div > 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) > div > 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) > div > 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);
				}
			});

			// score is a little bit different to get with manga -.-
			if (mal.type[0] == "manga") {
				$(data).find('#content > table > tbody > tr > td.borderClass > div > div:nth-child(n) > span > span:nth-child(2)').each(function() {
					dataMap.push('Score');
					dataArray.push(this.innerHTML);
				});
			}

			table.innerHTML = displayAnimeInfo(animeid);

			if (mal.modern) {
				$(table).find('a').each( function() {
					$(this).hover(function (){
						$(this).css("text-decoration", "underline");
					}, function() {
						$(this).css("text-decoration", "none");
					});
				});
			}

			var synopsis = table.getElementsByClassName('synopsis')[0];
			var image = table.getElementsByClassName('image')[0];
			var information = table.getElementsByClassName('information')[0];
			var related = table.getElementsByClassName('related')[0];

			image.firstChild.onload = function() {
				var synopsisHeight = this.height - related.offsetHeight - information.offsetHeight;
				synopsis.setAttribute('style', 'max-height:' + synopsisHeight + 'px; overflow:auto; overflow-y: auto;');
			};
		});
	}

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

	function getDataFromOriginalMore(preData, animeid) {
		var dataMap = store.get(animeid + 'MAP');
		var dataArray = store.get(animeid + 'Array');
		
		// Time Spent Watching
		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     //
	//--------------------------------//

	function displayTable(animeid, tdtype, moreObject, memberId) {
		return function () {

			if (moreObject.is(":visible")) {
				moreObject.hide();
			} else if (moreObject.hasClass("extraLoaded")) {
				moreObject.show();
			} else {
				$.post("/includes/ajax-no-auth.inc.php?t=6", {color:tdtype,id:animeid,memId:memberId,type:mal.type[0]}, function(data) {
					if (mal.modern)
						moreObject.find(".more-content").html(data.html);
					else
						moreObject.html(data.html);
					moreObject.show();
					moreObject.addClass("extraLoaded");

					var table = $(moreObject).find('.td' + tdtype + '.borderRBL')[0];
					var dataMap = [];
					var dataArray = [];
					store.set(animeid + 'MAP', dataMap);
					store.set(animeid + 'Array', dataArray);
					if (table !== null && mal.type[0] != "manga") {
						getDataFromOriginalMore(table.innerHTML, animeid);
						table.innerHTML = "Fetching data";
						getAnimeInfo(animeid, table);
					} else if (table !== null) {
						table.innerHTML = "Fetching data";
						getAnimeInfo(animeid, table);
					}
				},"json");
			}
		};
	}

	function getDataValue(animeid, string) {
		var dataMap = store.get(animeid + 'MAP');
		var dataArray = store.get(animeid + 'Array');

		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 = mal.xmlDoc.getElementsByTagName(mal.type[0]);
		var entryid = mal.xmlDoc.getElementsByTagName('series_' + mal.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 dataMap = store.get(animeid + 'MAP');
		var dataArray = store.get(animeid + 'Array');

		var episodes = getDataValue(animeid, 'Episodes');
		var chapters = getDataValue(animeid, 'Chapters');
		var volumes = getDataValue(animeid, 'Volumes');
		var image = getXmlEntry(animeid, "image");
		var genres = getDataValue(animeid, 'Genres');
		var status = getDataValue(animeid, 'Status');
		var broadcast = getDataValue(animeid, 'Broadcast');
		var score = getDataValue(animeid, 'Score');
		var rank = getDataValue(animeid, 'Ranked').replace("#","");
		var popularity = getDataValue(animeid, 'Popularity').replace("#","");
		var studio = getDataValue(animeid, 'Studios');

		var parent = getDataValue(animeid, 'Parent');
		var side = getDataValue(animeid, 'Side');
		var prequel = getDataValue(animeid, 'Prequel');
		var sequel = getDataValue(animeid, 'Sequel');
		var alternative = getDataValue(animeid, 'Alternative');

		var synopsis = getDataValue(animeid, 'Synopsis').replace(/\(Source.*[\s\S]*/g,"").replace(/\[.*\]/g,"").replace(/(<br>|\s+)*$/,"");

		var timeSpentWatching;
		var timeNeeded;
		if (mal.type[0] == "anime") {
			timeSpentWatching = getDataValue(animeid, 'TimeSpentWatching').replace("tes,","tes");
			timeNeeded = '0';
			if (timeSpentWatching.indexOf("0 hours, 0 minutes and 0 seconds") > -1) {
				timeNeeded = calcTimeNeeded(getDataValue(animeid, '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 class=\"image\" valign=\"top\" rowspan=\"4\">" + "<img src=" + image + ">" + "<\/td>";
		strVar += "    <td class=\"information\" valign=\"top\" width=\"35%\">";
		strVar += (status.indexOf("Currently Airing") > -1) ? ("<b>" + "Broadcast: " + "<\/b>" + broadcast + "<br>") : ("");
		strVar += (mal.type[0] == "anime") ? ("<b>" + "Episodes: " + "<\/b>" + episodes + "<br>") : ("<b>" + "Volumes: " + "<\/b>" + volumes + "<br>" + "<b>" + "Chapters: " + "<\/b>" + chapters + "<br>");
		strVar += "    <b>" + "Score: " + "<\/b>" + score + "<br>";
		strVar += "    <b>" + "Rank: " + "<\/b>" + rank + "<br>";
		strVar += "    <b>" + "Popularity: " + "<\/b>" + popularity + "<br>";
		strVar += (studio.indexOf("add some") == -1 && mal.type[0] != "manga") ? ("<b>" + "Studio: " + "<\/b>" + studio + "<br>") : ("");
		strVar += (mal.type[0] == "anime") ? ("<b>" + "Aired: " + "<\/b>" + startDate + endDate + "<br>") : ("<b>" + "Published: " + "<\/b>" + startDate + endDate + "<br>");
		strVar += "    <\/td>";
		strVar += "    <td class=\"genres\" valign=\"top\" align=\"right\" width=\"65%\">" + genres + "<\/td>";
		strVar += "  <\/tr>";
		strVar += "  <tr>";
		strVar += "    <td valign=\"top\" colspan=\"2\" width=\"100%\" height=\"100%\"><div class=\"synopsis\">" + "<br>" + synopsis + "<br><br>";
		strVar += "    <a href=\"/forum/?" + mal.type[0] + "id=" + animeid + "\" target=\"_blank\"><small>Discuss " + mal.type[0].charAt(0).toUpperCase() + mal.type[0].slice(1) + "</small></a></div><\/td>";
		strVar += "  <\/tr>";
		strVar += "  <tr>";
		strVar += "    <td class=\"related\" valign=\"bottom\" align=\"left\" height=\"5px\" width=\"50%\">";
		strVar += (parent != "Unavailable") ? ("<small>" + "<b>" + "Parent story: " + "<\/b>" + parent + "<\/small>") : ("");
		strVar += (side != "Unavailable") ? ("<br>" + "<small>" + "<b>" + "Side story: " + "<\/b>" + side + "<\/small>") : ("");
		strVar += (prequel != "Unavailable") ? ("<br>" + "<small>" + "<b>" + "Prequel: " + "<\/b>" + prequel + "<\/small>") : ("");
		strVar += (sequel != "Unavailable") ? ("<br>" + "<small>" + "<b>" + "Sequel: " + "<\/b>" + sequel + "<\/small>") : ("");
		strVar += (alternative != "Unavailable") ? ("<br>" + "<small>" + "<b>" + "Alternative version: " + "<\/b>" + alternative + "<\/small>") : ("");
		strVar += "    <\/td>";
		strVar += (mal.type[0] == "anime") ? ("<td class=\"timeNeeded\" 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;
	}
})(jQuery);