您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Allows to find missing relations and entries with wrong chapter/episode count.
当前为
// ==UserScript== // @name MyAnimeList (MAL) Track Missing Relations // @namespace https://greasyfork.org/users/7517 // @description Allows to find missing relations and entries with wrong chapter/episode count. // @version 1.0.2 // @author akarin // @include /^http\:\/\/myanimelist\.net\/editlist\.php\?type=anime$/ // @include /^http\:\/\/myanimelist\.net\/panel\.php\?go=editmanga$/ // @grant none // @noframes // ==/UserScript== ;(function() { if ($('#malLogin').length > 0) { return } const GET_DELAY = 300 const ANIME_T = 'anime' const MANGA_T = 'manga' const LIST_TYPE = document.URL.match(/\?type=anime$/) ? ANIME_T : MANGA_T const NICKNAME = $('ul#nav li:first > ul > li > a:contains(Profile)').prop('href').match(/(?!.*\/).*$/)[0] cacheVersion('Cache_1.0') var total var calc = -1 var left = [] var right = [] var $relBody = $('<div id="mr_body"></div>') .css({ 'text-align': 'center', 'width': '650px', 'height': 'auto' }) .append('<div style="font-size: 1.1em; font-weight: bold; color: #000;">Missing Titles</div>') .append($(' <small></small>').append( $('<a href="javascript:void(0);">refresh</a>').click(function() { $.fancybox.close() if (true === confirm('Are you sure you want to recalculate missing relations?')) { recalculate($('#content')) } }) )) .append('<br/>') .append('<hr size="1" color="#ccc" width="98%" noshade>') var $relList = $('<div id="mr_list"></div>').appendTo($relBody) var content = loadValue('relList', null) if (content !== null) { $relList.html(content) } else { $relList.html('<br><small>No missing relations found.</small>') } restyle($relList) $('<div style="display: none;"></div>').append($relBody).insertAfter('#content') $('<span id="mr_link"></span>') .append('<span> | </span>') .append($('<a href="#mr_body">Missing Relations</a>').fancybox({ 'hideOnContentClick': false, 'hideOnOverlayClick': true, 'titleShow': false, 'transitionIn': 'none', 'transitionOut': 'none', 'scrolling': 'no' })) .append(' (') .append($('<small></small>').append( $('<a href="javascript:void(0);">refresh</a>').click(function() { if (true === confirm('Are you sure you want to recalculate missing relations?')) { recalculate($('#content')) } }) )) .append(') ') .append('<span id="mr_status" style="color: green;"></span>') .appendTo('#content > div:first') function cacheVersion(ver) { var v = loadValue('cache', null) if (v === null || v !== ver) { localStorage.clear() saveValue('cache', ver) } } function recalculate(context) { if (calc > -1) { return } var $links = $('strong + a', context) total = $links.length if (total === 0) { $relList.html('<br><small>No missing relations found.</small>') return } calc = total $('span#mr_status').text(total - calc + '/' + total) $('span[id^="mr_id_"]').empty() left = [] right = [] $relList.html('<br><small>Calculating missing relations...</small>') $links.each(function(index) { var id = $(this).prop('href').match(/\d+$/)[0] var $span = $(this).parent().find('span[id="mr_' + id + '"]') if ($span.length === 0) { $('<span id="mr_id_' + id + '" style="float: right; margin: 0 7px;"></span>').appendTo($(this).parent()) } left.push(parseInt(id)) setTimeout(function() { $.get('/' + LIST_TYPE + '/' + id, function(data) { checkRelations(id, data) checkCorrectInfo(id, data) $('span[id="mr_id_' + id + '"]').html('<small style="color: green;">done</small>') $('span#mr_status').text(total - (--calc) + '/' + total) finalize() }) }, GET_DELAY * index) }) } function checkRelations(id, data) { var title = data.match(/<div id="contentWrapper">[\s\S]*?<h1><div [\s\S]*?<\/div>(.+?)</)[1].trim() var cnEx = LIST_TYPE === ANIME_T ? /<h2>Related Anime<\/h2>[\s\S]*?<h2>/ : /<h2>Related Manga<\/h2>[\s\S]*?<h2>/ var idEx = LIST_TYPE === ANIME_T ? /\/anime\/(\d+)\// : /\/manga\/(\d+)\// $('a', '<context>' + data.match(cnEx) + '</context>').each(function() { var idData = $(this).prop('href').match(idEx) if (idData !== null && idData.length > 1) { right.push({ lId: parseInt(id), lTitle: title, rId: parseInt(idData[1]), rTitle: $(this).text().trim() }) } }) } function checkCorrectInfo(id, data) { var correct = true do { var title = data.match(/<div id="contentWrapper">[\s\S]*?<h1><div [\s\S]*?<\/div>(.+?)</)[1].trim() var status = data.match(/>Status:<\/span>([\s\S]*?)<\/div>/)[1].trim() var myStatus = data.match(/selected>(.*?)<\/option/)[1].trim() if (status === (LIST_TYPE === ANIME_T ? 'Not yet aired' : 'Not yet published')) { if (myStatus !== (LIST_TYPE === ANIME_T ? 'Plan to Watch' : 'Plan to Read')) { correct = false break } } else if (status === (LIST_TYPE === ANIME_T ? 'Currently Airing' : 'Publishing')) { if (myStatus === 'Completed') { correct = false break } } if (LIST_TYPE === ANIME_T) { var eps = data.match(/>Episodes:<\/span>([\s\S]*?)<\/div>/)[1].trim() var myEps = data.match(/name="myinfo_watchedeps"[\s\S]*?value="(\d*)"/)[1].trim() if (eps !== 'Unknown') { if (parseInt(myEps) > parseInt(eps) || (myStatus === 'Completed' && parseInt(myEps) !== parseInt(eps))) { correct = false break } } } else { var vols = data.match(/>Volumes:<\/span>([\s\S]*?)<\/div>/)[1].trim() var myVols = data.match(/id="myinfo_volumes"[\s\S]*?value="(\d*)"/)[1].trim() if (vols !== 'Unknown') { if (parseInt(myVols) > parseInt(vols) || (myStatus === 'Completed' && parseInt(myVols) !== parseInt(vols))) { correct = false break } } var chap = data.match(/>Chapters:<\/span>([\s\S]*?)<\/div>/)[1].trim() var myChap = data.match(/id="myinfo_chapters"[\s\S]*?value="(\d*)"/)[1].trim() if (chap !== 'Unknown') { if (parseInt(myChap) > parseInt(chap) || (myStatus === 'Completed' && parseInt(myChap) !== parseInt(chap))) { correct = false break } } } } while (false); if (correct === false) { right.push({ lId: parseInt(id), lTitle: title, rId: -1, rTitle: '' }) } } function finalize() { if (calc > 0) { return } if (right.length === 0) { $relList.html('<br><small>No missing relations found.</small>') return } var $table = $('<table id="relTable" border="0" cellpadding="0" cellspacing="0" width="100%"></table>') .append($('<tr></tr>').html( '<th>You\'ve watched this…</th>' + '<th>…so you might want to check this:</th>' )) right.sort(function(a, b) { return a.rId > b.rId }) var prev = -1 for (var i = 0; i < right.length; ++i) { if (right[i].rId < 0) { continue } if (right[i].rId === prev || left.indexOf(right[i].rId) > -1) { right.splice(i--, 1) } else { prev = right[i].rId } } right.sort(function(a, b) { if (a.lTitle === b.lTitle) { return b.rId < 0 || a.rTitle > b.rTitle } return a.lTitle > b.lTitle }) prev = -1 var count = 0 $.each(right, function(index, rel) { var leftLink = '' var rightLink = '' var className = '' if (rel.lId !== prev) { leftLink = '<a href="/' + LIST_TYPE + '/' + rel.lId + '" target="_blank">' + rel.lTitle + '</a>' className = ' class="first_row"' if (rel.rId < 0) { rightLink = '<div class="mr_warning">Wrong status or ' + (LIST_TYPE === ANIME_T ? 'episode' : 'chapter') + ' count</div>' } } if (rel.rId > -1) { rightLink = '<div class="mr_count"><small>' + (++count) + '</small></div>' + '<a href="/' + LIST_TYPE + '/' + rel.rId + '" target="_blank">' + rel.rTitle + '</a>' } $table.append($('<tr></tr>').html( '<td' + className + '>' + leftLink + '</td>' + '<td' + className + '>' + rightLink + '</td>' )) prev = rel.lId }) $relList.empty().append($table) saveValue('relList', $relList.html()) restyle($relList) calc = -1 } function restyle(context) { $(context).css({ 'width': '98%', 'height': '700px', 'overflow-y': 'auto', 'margin': '0 auto 15px' }) $('#relTable th', context).css({ 'width': '50%', 'background-color': '#f5f5f5', 'padding': '0.5em 1em', 'font-weight': 'bold', 'text-align': 'left' }) $('#relTable td', context).css({ 'width': '50%', 'padding': '0.2em 1em', 'font-weight': 'normal', 'text-align': 'left', 'border-top': '1px solid #eee' }) $('#relTable td.first_row', context).css({ 'border-top': '2px solid #bebebe' }) $('#relTable tr:last-of-type td', context).css({ 'border-bottom': '1px solid #eee' }) $('#relTable td:last-of-type > div.mr_warning', context).css({ 'color': '#E43', 'font-weight': 'bold' }) $('#relTable td:last-of-type > div.mr_count', context).css({ 'width': '25px', 'float': 'right', 'color': '#666', 'text-align': 'center' }) } function loadValue(name, defaultValue) { var value = localStorage.getItem(NICKNAME + '#' + LIST_TYPE + '#' + name) return value ? value : defaultValue } function saveValue(name, value) { localStorage.setItem(NICKNAME + '#' + LIST_TYPE + '#' + name, value) } })()