Greasy Fork 支持简体中文。

bangumi-auto-relate-infobox

帮助 Bangumi 维基人自动关联 infobox 信息

// ==UserScript==
// @name        bangumi-auto-relate-infobox
// @namespace   https://greasyfork.org/users/1203219
// @author      harutya
// @match       *://bgm.tv/subject/*/add_related/person
// @match       *://chii.in/subject/*/add_related/person
// @match       *://bangumi.tv/subject/*/add_related/person
// @match       *://bgm.tv/person/*
// @match       *://chii.in/person/*
// @match       *://bangumi.tv/person/*
// @exclude     /^https?://((bgm|bangumi)\.tv|chii\.in)/person/\d+/.*/
// @license     MIT
// @version     1.2.2
// @description 帮助 Bangumi 维基人自动关联 infobox 信息
// ==/UserScript==

(function () {

    'use strict';

    // 此 Map 用于处理:(1)查询不到; (2)人物原名为条目填写名称的子集,如原名:あきやま,条目填写:あきやまえんま
    let bgmIdMap = {
        "KADOKAWA": 19306
        , "斉藤壮馬": 14604
        , "週刊ビッグコミックスピリッツ": 7620
        , "あきやまえんま": 30863
    };

    // infobox 填写的人员字符串分割规则,自行按需修改
    const SPLIT_RULE = /[()\[\]{}()<>《》「」『』【】+×·→//、,,;;::&&\\]/;

    const FILTER_WORDS = ['CV:', 'CV\\.', 'feat\\.', '\\*'];

    let jobMap, infoMap, idxMap, failSet, staffSet, repeatSet, count, total;

    $('#columnCrtRelatedA .board').after(`
        <input type='button' id='autoRelate' class='inputBtn' value='自动关联' style='float:right; margin-bottom: 7px'/>
        <div id='staffs' hidden='hidden'>${typeof genPrsnStaffList == 'function' && genPrsnStaffList(-1)}</div>
        <div id="TB_load" style="display: none;"><img src="/img/loadingAnimation.gif"></div>
    `);
    $('#autoRelate').on('click', autoRelate);
    $('#staffs select').removeAttr('name');

    $('li.collect').prepend('<span style="color:#999; cursor:pointer; float:left" class="collect"><a id="addToMap"></a></span>');
    $('#addToMap').text(isCollect() ? '取消关联' : '加入关联').addClass(isCollect() ? 'break' : '').hover(() => $(this).css("color", "#F09199"), () => $(this).css("color", "#999")).on('click', addIntoMap);

    let newPrsnName = localStorage.getItem('newPrsnName');
    if (newPrsnName) {
        $('#crt_name').val(newPrsnName);
        localStorage.removeItem('newPrsnName');
        $('#columnInSubjectA td').eq(1).append(`
            <label style='font-size: 14px; color: #333; margin:0px 3px'>快速查找</label>
            <a class='fastSearch' href='/subject_search/${encodeURIComponent(newPrsnName)}?cat=all&legacy=1'>Bangumi</a>
            <a class='fastSearch' href='https://www.google.com/search?q=${encodeURIComponent(newPrsnName)}'>Google</a>
        `);
        $('.fastSearch').attr('target', '_blank').css({ 'border': '1px solid #999', 'padding': '3px', 'font-size': '14px', 'margin-left': '3px' });
    }

    bindDblClickEvent();

    function autoRelate() {
        $('#autoRelate').prop('disabled', true);

        jobMap = new Map();
        $('#staffs option').each(function () {
            let text = $(this).text(), parts = text.split(' / ');
            let job = parts.length > 1 ? (parts[0].trim() || parts[parts.length - 1].trim()) : text.trim();
            jobMap.set(job, $(this).val());
        });

        idxMap = new Map();
        infoMap = new Map();
        $('#infobox li').each(function (idx) {
            let text = $(this).text();
            let job = text.slice(0, text.indexOf(':')).trim();
            let staffs = text.slice(text.indexOf(':') + 1).trim();
            if (jobMap.get(job) && staffs) {
                idxMap.set(jobMap.get(job), idx);
                infoMap.set(job, staffs);
            } else {
                $(this).css('text-decoration', 'line-through');
            }
        });

        staffSet = new Set();
        repeatSet = new Set();
        $('#crtRelateSubjects .clearit').each(function () {
            let job = $(this).find('select').val();
            let staff = $(this).find('.l').text();
            let id = $(this).find('.l').attr('href');
            staffSet.add(job + id.substr(id.lastIndexOf('/')));
            staffSet.has(job + staff) ? repeatSet.add(job + staff) : staffSet.add(job + staff);
        });

        count = 0;
        total = 0;
        failSet = new Set();
        bgmIdMap = getLastestMap();
        $('#infobox a').removeAttr('class href target').css('color', 'black').off('click');
        $('#TB_load').show();
        infoMap.forEach(function (staffs, job) {
            let arr = Array.from(new Set(staffs.replace(new RegExp(FILTER_WORDS.join('|'), 'g'), ',').split(SPLIT_RULE)));
            for (let i in arr) {
                let staff = arr[i].trim();
                if (staff) {
                    ++total;
                    setTimeout(function () {
                        crtRelate(jobMap.get(job), staff);
                    }, (i % 5 + 1) * 300);
                }
            }
        });

        if (total == 0) {
            $('#autoRelate').prop('disabled', false);
            $('#TB_load').hide();
            alertMsg('无可关联内容!');
        }
    }

    function crtRelate(job, staff) {
        $.ajax({
            type: "GET",
            url: '/json/search-person/' + encodeURIComponent(trans(staff)),
            dataType: 'json',
            success: function (res) {
                if (Object.keys(res).length) {
                    let related = false;
                    for (let id in res) {
                        if (staff === res[id].name || bgmIdMap[staff] == id) {
                            if (!staffSet.has(job + '/' + id)) {
                                staffSet.add(job + '/' + id);
                                staffSet.has(job + staff) ? repeatSet.add(job + staff) : staffSet.add(job + staff);

                                subjectList[id] = res[id];
                                addRelateSubject(id, 'searchResult');
                                $('#crtRelateSubjects select').eq(0).val(job);
                                addSbjListener();
                                colorSbjList();
                            }
                            related = true;
                        }
                    }
                    !related && colorInfobox(job, staff);
                } else {
                    colorInfobox(job, staff);
                }

                $('#autoRelate').val(`进度:${++count} / ${total}`);
                if (count == total) {
                    $('#autoRelate').prop('disabled', false);
                    $('#TB_load').hide();
                    $('.noExist').each(function () {
                        $(this).css('color', 'red').attr('href', '/person/new').attr('target', '_blank').on('click', function () {
                            localStorage.setItem('newPrsnName', $(this).text());
                        })
                    });
                    alertMsg('任务完成!' + (failSet.size ? '未匹配的内容已被标红了喵!' : '全都关联上了喵!')
                        + (repeatSet.size ? '</br><font color="red">有同名人物关联到同一职位,请去重喵!</font>' : ''));
                    repeatSet.size && $('#autoRelate').val(`重复:${repeatSet.size}`);
                }
            },
            error: function () {
                setTimeout(function () {
                    crtRelate(job, staff);
                }, 1500);
            }
        });
    }

    function trans(staff) {
        let id = bgmIdMap[staff];
        return id ? ('bgm_id=' + id) : staff;
    }

    function addSbjListener() {
        $('#crtRelateSubjects .rr').off('click').on('click', function () {
            let li = $(this).parents('li.clearit');
            let job = li.find('select').val();
            let staff = li.find('.l').text();
            let item = (job ? job : li.find('option[selected="true"]').val()) + staff;
            colorSbjList(item);
            li.remove();
        });
    }

    function colorInfobox(job, staff) {
        if (!failSet.has(job + staff)) {
            failSet.add(job + staff);
            let idx = idxMap.get(job);
            let html = $('#infobox li').eq(idx).html();
            $('#infobox li').eq(idx).html(html.replace(new RegExp(staff, 'g'), `<a class='noExist'>${staff}</a>`));
        }
    }

    function colorSbjList(item) {
        let map = new Map();
        $('#crtRelateSubjects .clearit').each(function (idx) {
            let job = $(this).find('select').val();
            let staff = $(this).find('.l').text();
            let key = job + staff;
            map.get(key) instanceof Array ? map.get(key).push(idx) : map.set(key, [idx]);

            if (!item) {
                let arr = map.get(key);
                let len = arr.length;
                if (len == 2) {
                    colorItem(arr[0], true);
                    colorItem(arr[1], true);
                } else if (len > 2) {
                    colorItem(arr[len - 1], true);
                }
            }
        });
        if (item && map.get(item).length == 2) {
            colorItem(map.get(item)[0]);
            colorItem(map.get(item)[1]);
            repeatSet.delete(item);
            $('#autoRelate').val(repeatSet.size ? '重复:' + repeatSet.size : '去重完成');
        }
    }

    function colorItem(idx, flag) {
        $('#crtRelateSubjects .clearit').eq(idx).css('background-color', flag ? '#eef4c9' : '');
    }

    function alertMsg(msg) {
        $("#robot_speech").html(msg);
        $("#robot").fadeIn(300).animate({ opacity: 1 }, 2000, () => { !repeatSet.size && $('#autoRelate').val('自动关联') }).fadeOut(500);
    }

    function addIntoMap() {
        let map = getLastestMap();
        let name = $('.nameSingle a').text();
        let id = $('.nameSingle a').attr('href');
        if ($('#addToMap').hasClass('break')) {
            delete map[name];
            $('#addToMap').text('加入关联').removeClass('break');
        } else {
            map[name] = id.substr(id.lastIndexOf('/') + 1);
            $('#addToMap').text('取消关联').addClass('break');
        }
        localStorage.setItem('localPrsnMap', JSON.stringify(map));
    }

    function isCollect() {
        bgmIdMap = getLastestMap();
        let name = $('.nameSingle a').text();
        return bgmIdMap[name];
    }

    function getLastestMap() {
        let json = localStorage.getItem('localPrsnMap');
        try {
            let obj = JSON.parse(json);
            bgmIdMap = { ...bgmIdMap, ...obj };
        } catch (e) {
            localStorage.setItem('localPrsnMap', '{}');
        }
        return bgmIdMap;
    }

    function bindDblClickEvent() {
        $('#infobox li').not('.sub_container, .sub, .sub_section').each(function () {
            $(this).on('dblclick', function () {
                let job = $(this).find('.tip').text();
                let text = $(this).text().replace(job, '');
                $(this).html(`<span class="tip">${job}</span><textarea>${text}</textarea>`);

                let textarea = $(this).find('textarea');
                textarea.focus().on('blur', function () {
                    $(this).parent().html(`<span class="tip">${job}</span>${$(this).val()}`);
                }).on('input', function () {
                    this.style.height = this.scrollHeight + 'px';
                }).css({
                    width: '100%', boxSizing: 'border-box', minHeight: '30px'
                });
                textarea[0].style.height = textarea[0].scrollHeight + 'px';
            });
        });
    }

})();