MyKirito Helper

讓你可以更星爆

目前為 2020-06-19 提交的版本,檢視 最新版本

// ==UserScript==
// @name         MyKirito Helper
// @version      0.3
// @description  讓你可以更星爆
// @author       ganmaRRRRR
// @match        https://mykirito.com/*
// @require      https://cdn.jsdelivr.net/gh/CoeJoder/[email protected]/waitForKeyElements.js
// @require      https://unpkg.com/@popperjs/core@2
// @require      https://unpkg.com/tippy.js@6
// @grant        none
// @run-at       document-start
// @namespace https://gf.qytechs.cn/users/600262
// ==/UserScript==

const pkWinTable = [[6, 9, 18, 30, 32, 35, 37], [9, 14, 28, 45, 48, 52, 55], [62, 85, 97, 103, 133], [81, 120, 130, 140, 150]];
const pkWinMul = [2.5, 3.75];
const pkLoseTable = [20, 35, 50, 60];
const actTable = ["15~19", "15", "13~19", "18", "18", "15", "15", "430", "820", "1610", "3200"];
const expTable = [0, 30, 60, 100, 150, 200, 250, 300, 370, 450, 500, 650, 800, 950, 1200, 1450, 1700, 1950, 2200, 2500, 2800, 3100, 3400, 3700, 4000, 4400, 4800, 5200, 5600, 6000, 6500, 7000, 7500, 8000, 8500, 9100, 9700, 10300, 11000, 11800, 12600, 13500, 14400, 15300, 16200, 17100, 18000, 19000, 20000, 21000, 23000, 25000, 27000, 29000, 31000, 33000, 35000, 37000, 39000, 41000, 44000, 47000, 50000, 53000, 56000, 59000, 62000, 65000, 68000, 71000];
const rattrCSS = ".fYZyZu {color: #00b5b5;}";
const buttonAniCSS = ".tippy-box[data-animation=shift-away-subtle][data-state=hidden]{opacity:0}.tippy-box[data-animation=shift-away-subtle][data-state=hidden][data-placement^=top]{transform:translateY(5px)}.tippy-box[data-animation=shift-away-subtle][data-state=hidden][data-placement^=bottom]{transform:translateY(-5px)}.tippy-box[data-animation=shift-away-subtle][data-state=hidden][data-placement^=left]{transform:translateX(5px)}.tippy-box[data-animation=shift-away-subtle][data-state=hidden][data-placement^=right]{transform:translateX(-5px)}";

//config
var yuukiMod = false;
var delay = 500; // 一些東西的延遲 (以防抓不到網頁元素)
var inited = false;

var myK;
var otherK;
(async function() {
    'use strict';

    // 抓Ajax Event
    function ajaxEventTrigger(event) {
        let ajaxEvent = new CustomEvent(event, { detail: this });
        window.dispatchEvent(ajaxEvent);
    }
    let oldXHR = window.XMLHttpRequest;
    function newXHR() {
        let realXHR = new oldXHR();
        // this指向window
        realXHR.addEventListener('readystatechange', function() { ajaxEventTrigger.call(this, 'ajaxReadyStateChange'); }, false);
        return realXHR;
    }
    window.XMLHttpRequest = newXHR;
    window.addEventListener('ajaxReadyStateChange', function (e) {
        // 處理成功的Request
        if (e.detail.readyState === oldXHR.DONE && e.detail.status === 200) {
            ajaxEventHandler(e.detail.responseURL, JSON.parse(e.detail.response));
        }
    });

    // 抓fetch event
    let nativeFetch = window.fetch; // must be on the global scope
    window.fetch = function(...args) {
        let promise = nativeFetch(...args);
        promise.then((r) => {
            return (r.url.match('report') && r.ok) ? r.clone().json() : false; })
            .then((j) => {
            if (j) { reportThree(j); }; });
        return promise;
    }

    waitForKeyElements("div#root > nav", init);
})();

function ajaxEventHandler(url, response) {
    let page = window.location.pathname.split("/")[1];
    if (url === "https://mykirito.com/api/my-kirito") {
        myK = response;
    }
    switch (page) {
        case "":// 我的桐人
            myKirito(url, response);
            break;
        case "profile": // 別的桐人
            otherKirito(url, response);
            break;
    }
}

function init() {
    // Navbar置頂 (from https://gf.qytechs.cn/zh-TW/scripts/404006-kirito-tools)
    let root = document.querySelector("div#root");
    let navbar = document.querySelector("div#root > nav");
    let navbarHeight = navbar.offsetHeight;
    root.style.paddingTop = `calc(${navbarHeight}px + 18px)`; // height + margin bottom
    navbar.style.position = "fixed";
    navbar.style.top = "0";

    // 加上選單按鈕
    let button = document.createElement("a");
    button.className = "sc-fzqAui eoGDzK";
    button.innerHTML = '<svg style="filter: invert(1);" width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd"><path d="M12 8.666c-1.838 0-3.333 1.496-3.333 3.334s1.495 3.333 3.333 3.333 3.333-1.495 3.333-3.333-1.495-3.334-3.333-3.334m0 7.667c-2.39 0-4.333-1.943-4.333-4.333s1.943-4.334 4.333-4.334 4.333 1.944 4.333 4.334c0 2.39-1.943 4.333-4.333 4.333m-1.193 6.667h2.386c.379-1.104.668-2.451 2.107-3.05 1.496-.617 2.666.196 3.635.672l1.686-1.688c-.508-1.047-1.266-2.199-.669-3.641.567-1.369 1.739-1.663 3.048-2.099v-2.388c-1.235-.421-2.471-.708-3.047-2.098-.572-1.38.057-2.395.669-3.643l-1.687-1.686c-1.117.547-2.221 1.257-3.642.668-1.374-.571-1.656-1.734-2.1-3.047h-2.386c-.424 1.231-.704 2.468-2.099 3.046-.365.153-.718.226-1.077.226-.843 0-1.539-.392-2.566-.893l-1.687 1.686c.574 1.175 1.251 2.237.669 3.643-.571 1.375-1.734 1.654-3.047 2.098v2.388c1.226.418 2.468.705 3.047 2.098.581 1.403-.075 2.432-.669 3.643l1.687 1.687c1.45-.725 2.355-1.204 3.642-.669 1.378.572 1.655 1.738 2.1 3.047m3.094 1h-3.803c-.681-1.918-.785-2.713-1.773-3.123-1.005-.419-1.731.132-3.466.952l-2.689-2.689c.873-1.837 1.367-2.465.953-3.465-.412-.991-1.192-1.087-3.123-1.773v-3.804c1.906-.678 2.712-.782 3.123-1.773.411-.991-.071-1.613-.953-3.466l2.689-2.688c1.741.828 2.466 1.365 3.465.953.992-.412 1.082-1.185 1.775-3.124h3.802c.682 1.918.788 2.714 1.774 3.123 1.001.416 1.709-.119 3.467-.952l2.687 2.688c-.878 1.847-1.361 2.477-.952 3.465.411.992 1.192 1.087 3.123 1.774v3.805c-1.906.677-2.713.782-3.124 1.773-.403.975.044 1.561.954 3.464l-2.688 2.689c-1.728-.82-2.467-1.37-3.456-.955-.988.41-1.08 1.146-1.785 3.126"/></svg>';
    button.id = "mykirito_helper";
    navbar.insertBefore(button, navbar.lastChild);
    tippy(button, {
        placement: 'bottom',
        content: `<div style="text-align: center;">MyKirito Helper</div>`+
        `<p><label><input type="checkbox" id="yuuki_mod"}> 牙紀整形 (測試中)</label></p>`+
        `<input type="range" id="delay" min="100" max="5000" step="100" value="500"><p id="show_delay" style="display: inline;"> 500</p>`+
        `ms Delay<p>有問題請嘗試調大此值</p><p style="text-align: right;"><a href="https://gf.qytechs.cn/zh-TW/scripts/405599-mykirito-helper/feedback" target="_blank" style="color: aqua;">回報問題</a></p>`,
        allowHTML: true,
        interactive: true,
        trigger: 'mouseenter focus click',
        onShown(instance) {
            if (!inited){
                document.getElementById("show_delay").innerHTML = ` ${document.getElementById("delay").value}`;
                document.getElementById("yuuki_mod").addEventListener('input', () => { (document.getElementById("yuuki_mod").checked) ? yuukiMod = true : yuukiMod = false; });
                document.getElementById("delay").addEventListener('input', () => {
                    delay = document.getElementById("delay").value;
                    document.getElementById("show_delay").innerHTML = ` ${document.getElementById("delay").value}`;});
                inited = true;
            }
        },
    });

    // 要求通知權限
    if (Notification.permission === 'default' || Notification.permission === 'undefined') {
        Notification.requestPermission();
    }

    injectCSS(rattrCSS);
    injectCSS(buttonAniCSS);
    giveYuukiBack();
}

function myKirito(url, response) {
    let act = new URL(url).pathname.split("/");
    if (act[2] === "my-kirito") {
        switch (act[3]) {
            case undefined: // 自己的資料
                setTimeout(updateExpReq, delay);
                setTimeout(updateTeam, delay);
                setTimeout(addTooltip, delay);
                break;
            case "teammate": // 隊伍資料
                setTimeout(updateTeam, delay);
                break;
            case "doaction": // 行動
                response = response.myKirito;
                setTimeout(updateExpReq, delay);
                break;
        }
    }

    function updateExpReq() {
        let expReq = document.getElementById("exp_require");
        if (expReq == null) {
            waitForKeyElements("div#root table > tbody", addExpReq);
            expReq = document.getElementById("exp_require");
        }
        let lv = response.lv;
        let exp = response.exp;
        expReq.innerHTML = expTable[lv] - exp;

        function addExpReq(table) {
            let tr = table.lastChild.cloneNode(true);
            tr.childNodes[0].innerHTML = "距離升級";
            tr.childNodes[1].id = "exp_require";
            tr.removeChild(tr.lastChild);
            tr.removeChild(tr.lastChild);
            table.appendChild(tr);
        }
    }

    function updateTeam() {
        let teamRef = document.getElementById("team_ref");
        if (teamRef == null) {
            waitForKeyElements("div#root div > h3 ~ div ~ div ~ div", addTeamRef);
            teamRef = document.getElementById("team_ref");
        }
        let teammateUID = response.teammateUID;
        let teammateName = response.teammate;
        if (teammateName === undefined) {
            teammateName = document.querySelector("div ~ div > input").value;
        }
        if (teammateUID) {
            teamRef.href = `/profile/${teammateUID}`;
            teamRef.innerHTML = teammateName;
        }
        else {
            teamRef.href = "";
            teamRef.innerHTML = "";
        }

        function addTeamRef(team) {
            let a = document.createElement("a");
            a.id = "team_ref";
            team.appendChild(a);
        }
    }

    function addTooltip() {
        let buttons = document.querySelectorAll("button");
        let floorBtn = buttons[buttons.length - 12];
        try{
            let actBtns = [];
            for (let i = buttons.length - 11; i < buttons.length; i++) {
                actBtns.push(tippy(buttons[i], { content: `${actTable[i-(buttons.length-11)]} 經驗值` }));
            }
            tippy.createSingleton(actBtns.slice(0, 7), {
                delay: [200, 100],
                moveTransition: 'transform 0.2s ease-out',
                animation: 'shift-away-subtle',});
            tippy.createSingleton(actBtns.slice(7), {
                delay: [200, 100],
                moveTransition: 'transform 0.2s ease-out',
                animation: 'shift-away-subtle',});
            if (myK.floor > 0) {
                tippy(floorBtn, {
                    delay: [200, 100],
                    content: `${myK.floor*100} 經驗值`,
                    animation: 'shift-away-subtle',});
            }
        }
        catch(e) { console.log(e); }
    }
}

function otherKirito(url, response) {
    switch (url.split("/")[4]) {
        case "profile": // 別人的資料
            otherK = response.profile;
            setTimeout(showRattr, delay);
            setTimeout(addTooltip, delay);
            break;
    }

    function showRattr() {
        let btnDetail = document.querySelectorAll("button")[0];
        let btnCompare = document.querySelectorAll("button")[1];
        let rattrs = otherK.rattrs;
        let floor = otherK.floor;
        let achieveP = otherK.achievementPoints;
        btnSwitch();
        btnDetail.addEventListener('click', () => {setTimeout(btnSwitch, delay);});
        btnCompare.addEventListener('click', () => {setTimeout(btnSwitch, delay);});

        function btnSwitch() {
            // 詳細資料
            if (btnDetail.disabled) {
                let table = document.querySelector("div#root tbody");
                let count = 3;
                for (let k in rattrs) {
                    count++;
                    if (rattrs[k] === 0) {
                        continue;
                    }
                    let r = document.createElement("span");
                    r.className = "sc-fzoLsD fYZyZu";
                    r.innerHTML = ` (+${rattrs[k]})`;
                    table.childNodes[count].childNodes[1].appendChild(r);
                }

                // 一些有的沒的
                let tr = table.lastChild.cloneNode(true);
                tr.childNodes[0].innerHTML = "目前層數";
                tr.childNodes[1].innerHTML = floor;
                tr.childNodes[2].innerHTML = "成就點數";
                tr.childNodes[3].innerHTML = achieveP;
                table.appendChild(tr);
            }
            // 能力比對
            else {
                let table = document.querySelector("div#root table ~ table > tbody");
                let count = 5;
                for (let k in rattrs) {
                    count++;
                    if (rattrs[k] === 0) {
                        continue;
                    }
                    let r = document.createElement("span");
                    r.className = "sc-fzoLsD fYZyZu";
                    r.innerHTML = ` (+${rattrs[k]})`;
                    table.childNodes[count].childNodes[1].appendChild(r);
                }
            }
        }
    }

    function addTooltip() {
        let lvDiff = otherK.lv - myK.lv;
        let mul;
        switch (otherK.color) {
            case 'black':
                mul = 1;
                break;
            case 'orange':
                mul = 1.4;
                break;
            case 'red':
                mul = 1.7;
                break;
        }
        let buttons = document.querySelectorAll("button");
        let pkBtns = [];
        try{
            for (let i = 2; i < 4; i++) {
                let text;
                if (lvDiff > 3) {text = `${pkWinTable[i-2][3] + Math.floor(pkWinMul[i-2] * lvDiff)} / ${pkLoseTable[i-2]}`;}
                else if (lvDiff < -3) {text = `很少 / ${pkLoseTable[i-2]}`;}
                else {text = `${pkWinTable[i-2][lvDiff+3]} / ${pkLoseTable[i-2]}`;}
                pkBtns.push(tippy(buttons[i], { content: `${text} 經驗值` }));
            }
            tippy.createSingleton(pkBtns, {
                delay: [200, 100],
                moveTransition: 'transform 0.2s ease-out',
                placement: 'left',
                animation: 'shift-away-subtle',});
        }
        catch(e) { console.log(e); }
    }
}


function reportThree(report) {
    // boss戰
    if (report.type === 99) {}
    // 對戰
    else {
        let atkTable = document.querySelectorAll("tbody")[0];
        let defTable = document.querySelectorAll("tbody")[1];
        tableEnhance(report.a, report.b, atkTable);
        tableEnhance(report.b, report.a, defTable);

        function tableEnhance(data1, data2, table) {
            table.childNodes[3].childNodes[1].innerHTML = `<a href="/profile/${data1.uid}">${data1.nickname}</a>`
            table.childNodes[6].childNodes[1].innerHTML += pCompare(data1.hp, data2.hp);
            table.childNodes[7].childNodes[1].innerHTML += pCompare(data1.atk, data2.atk);
            table.childNodes[8].childNodes[1].innerHTML += pCompare(data1.def, data2.def);
            table.childNodes[9].childNodes[1].innerHTML += pCompare(data1.stm, data2.stm);
            table.childNodes[10].childNodes[1].innerHTML += pCompare(data1.agi, data2.agi);
            table.childNodes[11].childNodes[1].innerHTML += pCompare(data1.spd, data2.spd);
            table.childNodes[12].childNodes[1].innerHTML += pCompare(data1.tec, data2.tec);
            table.childNodes[13].childNodes[1].innerHTML += pCompare(data1.int, data2.int);
            table.childNodes[14].childNodes[1].innerHTML += pCompare(data1.lck, data2.lck);
            for (let i = 6; i < 15; i++) {
                table.childNodes[i].childNodes[1].style.display = "flex";
                table.childNodes[i].childNodes[1].style.justifyContent = "space-between";
            }

            function pCompare(p1, p2) {
                if (p1 > p2) { return `<span class="fYZyZu">+${p1-p2}</span>`; }
                else { return `<span style="color: red;">-${p2-p1}</span>`; }
            }
        }
    }
}

function giveYuukiBack() {
    waitForKeyElements('source', (pic) => {
        if (yuukiMod) {
            if (pic.srcset.match('yuuki.s')) {
                pic.srcset = "https://i.imgur.com/VJyzROs.png";
            }
            if (pic.srcset.match('yuuki')) {
                pic.srcset = "https://i.imgur.com/VWNyCjk.png";
            }
        }
    }, false, delay);
}

// from tippy.js
function injectCSS(css) {
    var style = document.createElement('style');
    style.textContent = css;
    var head = document.head;
    var firstStyleOrLinkTag = document.querySelector('head>style,head>link');

    if (firstStyleOrLinkTag) {
        head.insertBefore(style, firstStyleOrLinkTag);
    } else {
        head.appendChild(style);
    }
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址