您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Export CN POE data.
当前为
// ==UserScript== // @name CN POE Export // @namespace https://github.com/cn-poe-community/cn-poe-export-monkey // @version 0.0.17 // @description Export CN POE data. // @author me1ting // @match https://poe.game.qq.com/my-account // @match https://poe.game.qq.com/account/view-profile/* // @match https://poe.game.qq.com/forum // @icon https://poecdn.game.qq.com/gen/image/WzI1LDE0LHsiZiI6IjJESXRlbXMvQ3VycmVuY3kvU2NvdXRpbmdSZXBvcnQiLCJ3IjoxLCJoIjoxLCJzY2FsZSI6MX1d/584635f3c8/ScoutingReport.png // @require https://unpkg.com/[email protected]/dist/translator.global.js // @require https://unpkg.com/[email protected]/dist/db.global.js // @require https://unpkg.com/[email protected]/dist/creater.global.js // @require https://unpkg.com/[email protected]/dist/pako_deflate.min.js // @require https://unpkg.com/[email protected]/dist/axios.min.js // @require https://unpkg.com/[email protected]/dist/vue.global.prod.js // @grant none // @license MIT // ==/UserScript== (function(){ const { defineComponent, ref, reactive, computed, onMounted, openBlock, createElementBlock, Fragment, createElementVNode, withDirectives, vModelText, renderList, toDisplayString, vModelSelect, createCommentVNode, pushScopeId, popScopeId, createBlock, createApp } = Vue; (function() { "use strict"; try { if (typeof document != "undefined") { var elementStyle = document.createElement("style"); elementStyle.appendChild(document.createTextNode("#exportContainer {\n position: fixed;\n bottom: 20px;\n left: 10px;\n z-index: 99999;\n}\n\n.line-container[data-v-f270e9a2] {\n display: flex;\n margin: 3px 0;\n min-height: 25px;\n}\n.line-container select[data-v-f270e9a2] {\n min-height: 25px;\n margin-right: 4px;\n min-width: 100px;\n}\n.line-container input[data-v-f270e9a2] {\n margin-right: 4px;\n}")); document.head.appendChild(elementStyle); } } catch (e) { console.error("vite-plugin-css-injected-by-js", e); } })(); (function polyfill() { const relList = document.createElement("link").relList; if (relList && relList.supports && relList.supports("modulepreload")) { return; } for (const link of document.querySelectorAll('link[rel="modulepreload"]')) { processPreload(link); } new MutationObserver((mutations) => { for (const mutation of mutations) { if (mutation.type !== "childList") { continue; } for (const node of mutation.addedNodes) { if (node.tagName === "LINK" && node.rel === "modulepreload") processPreload(node); } } }).observe(document, { childList: true, subtree: true }); function getFetchOpts(link) { const fetchOpts = {}; if (link.integrity) fetchOpts.integrity = link.integrity; if (link.referrerPolicy) fetchOpts.referrerPolicy = link.referrerPolicy; if (link.crossOrigin === "use-credentials") fetchOpts.credentials = "include"; else if (link.crossOrigin === "anonymous") fetchOpts.credentials = "omit"; else fetchOpts.credentials = "same-origin"; return fetchOpts; } function processPreload(link) { if (link.ep) return; link.ep = true; const fetchOpts = getFetchOpts(link); fetch(link.href, fetchOpts); } })(); const PROFILE_URL = "api/profile"; const GET_CHARACTERS_URL = "/character-window/get-characters"; const GET_ITEMS_URL = "/character-window/get-items"; const GET_PASSIVE_SKILLS_URL = "/character-window/get-passive-skills"; async function profile() { try { const { data } = await axios.get(PROFILE_URL); return data; } catch (e) { throw requestError(e); } } async function getCharacters(accountName, realm2) { const form = new URLSearchParams(); form.append("accountName", accountName); form.append("realm", realm2); try { const { data } = await axios.post(GET_CHARACTERS_URL, form); return data; } catch (e) { throw requestError(e); } } async function getItems(accountName, character, realm2) { const form = new URLSearchParams(); form.append("accountName", accountName); form.append("character", character); form.append("realm", realm2); try { const { data } = await axios.post(GET_ITEMS_URL, form); return data; } catch (e) { throw requestError(e); } } async function getPassiveSkills(accountName, character, realm2) { const form = new URLSearchParams(); form.append("accountName", accountName); form.append("character", character); form.append("realm", realm2); try { const { data } = await axios.post(GET_PASSIVE_SKILLS_URL, form); return data; } catch (e) { throw requestError(e); } } function requestError(err) { if (err instanceof axios.AxiosError) { if (err.response) { const status = err.response.status; if (status === 401) { const rtnErr = new Error("未登陆"); rtnErr.stack = String(err); return rtnErr; } else if (status === 403) { const rtnErr = new Error("账户不存在或已隐藏"); rtnErr.stack = String(err); return rtnErr; } else if (status === 429) { const headers = err.response.headers; if (headers) { const limit = rateLimit(headers); if (limit.length > 0) { const rtnErr2 = new Error(`请求过于频繁,请等待 ${limit} 后再试`); rtnErr2.stack = String(err); return rtnErr2; } } const rtnErr = new Error("请求过于频繁,请稍后再试"); rtnErr.stack = String(err); return rtnErr; } } } else if (err instanceof Error) { return err; } return new Error(String(err)); } function rateLimit(headers) { let max = 0; for (const [key, value] of Object.entries(headers)) { if (/^x-rate-limit-.+-state$/.test(key)) { const states = value.split(","); const limits = states.map((s) => { const pieces = s.split(":"); return Number(pieces[pieces.length - 1]); }); for (let i = 0; i < limits.length; i++) { if (limits[i] > max) { max = limits[i]; } } } } if (max > 3600) { const h = Math.floor(max / 3600); const m = Math.floor(max % 3600 / 60); const s = max % 60; return `${h}小时${m}分钟${s}秒`; } if (max > 60) { const m = Math.floor(max % 3600 / 60); const s = max % 60; return `${m}分钟${s}秒`; } if (max > 0) { return `${max}秒`; } return ""; } const poeapi = { profile, getCharacters, getItems, getPassiveSkills }; const _withScopeId = (n) => (pushScopeId("data-v-f270e9a2"), n = n(), popScopeId(), n); const _hoisted_1 = { class: "line-container" }; const _hoisted_2 = ["disabled"]; const _hoisted_3 = { class: "line-container" }; const _hoisted_4 = { key: 0 }; const _hoisted_5 = ["value"]; const _hoisted_6 = ["value"]; const _hoisted_7 = ["disabled"]; const _hoisted_8 = { key: 1 }; const _hoisted_9 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ createElementVNode("select", { disabled: "" }, null, -1)); const _hoisted_10 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ createElementVNode("select", { disabled: "" }, null, -1)); const _hoisted_11 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ createElementVNode("button", { disabled: "" }, "导出", -1)); const _hoisted_12 = [ _hoisted_9, _hoisted_10, _hoisted_11 ]; const _hoisted_13 = { class: "line-container" }; const _hoisted_14 = ["value"]; const _hoisted_15 = ["disabled"]; const realm = "pc"; const _sfc_main$1 = /* @__PURE__ */ defineComponent({ __name: "Exporter", props: ["createBuilding", "startup"], setup(__props) { const props = __props; const accountName = ref(""); const characters = ref([]); const leagues = ref([]); const leagueMap = ref(/* @__PURE__ */ new Map()); const currLeague = ref(""); const currCharacters = ref([]); const currCharacter = ref(""); const buildingCode = ref(""); const state = reactive({ accountName, realm, characters, leagues, leagueMap, currLeague, currCharacters, currCharacter, buildingCode }); const getCharactersReady = computed(() => { return state.accountName.length > 0; }); const selectReady = computed(() => { return state.characters.length > 0; }); const exportReady = computed(() => { return state.characters.length > 0 && Boolean(state.currCharacter); }); function handleLeageSelect() { state.currCharacters = state.leagueMap.get(state.currLeague); state.currCharacter = state.currCharacters[0].name; } async function handleCharactersQuery() { state.characters = []; state.leagues = []; const realm2 = state.realm; const accountName2 = state.accountName; var data = null; try { data = await poeapi.getCharacters(accountName2, realm2); } catch (e) { if (e instanceof Error) { alert(e.message); } else { alert(e); } return; } const characters2 = data; state.characters = characters2; let leagueMap2 = /* @__PURE__ */ new Map(); for (const character of characters2) { const leagueName = character.league; let list = leagueMap2.get(leagueName); if (list === void 0) { list = []; leagueMap2.set(leagueName, list); } list.push(character); } state.leagueMap = leagueMap2; const leagues2 = Array.from(leagueMap2.keys()); state.leagues = leagues2; if (leagues2.length > 0) { state.currLeague = leagues2[0]; handleLeageSelect(); } } async function handleExport() { state.buildingCode = ""; const accountName2 = state.accountName; const character = state.currCharacter; const realm2 = state.realm; let items = null; let passiveSkills = null; try { items = await poeapi.getItems(accountName2, character, realm2); passiveSkills = await poeapi.getPassiveSkills(accountName2, character, realm2); state.buildingCode = await props.createBuilding(items, passiveSkills); } catch (e) { if (e instanceof Error) { alert(e.message); } else { alert(e); } return; } } function handleCopy() { navigator.clipboard.writeText(state.buildingCode); } function getInitialAccountName() { let accountName2 = getAccountNameFromProfileLink(window.location.href); if (accountName2 !== null) { return accountName2; } const profileLinkNode = document.querySelector("#statusBar .profile-link a"); if (profileLinkNode !== null) { accountName2 = getAccountNameFromProfileLink(profileLinkNode.href); if (accountName2 !== null) { return accountName2; } } return ""; } const pattern = new RegExp("/account/view-profile/([^/?]+)"); function getAccountNameFromProfileLink(link) { const match = pattern.exec(link); if (match) { return decodeURI(match[1]); } return null; } onMounted(() => { state.accountName = getInitialAccountName(); if (props.startup) { props.startup(); } }); return (_ctx, _cache) => { return openBlock(), createElementBlock(Fragment, null, [ createElementVNode("span", _hoisted_1, [ withDirectives(createElementVNode("input", { type: "text", placeholder: "输入论坛账户名", maxlength: "50", "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => state.accountName = $event) }, null, 512), [ [ vModelText, state.accountName, void 0, { trim: true } ] ]), createElementVNode("button", { onClick: handleCharactersQuery, disabled: !getCharactersReady.value }, "开始", 8, _hoisted_2) ]), createElementVNode("span", _hoisted_3, [ selectReady.value ? (openBlock(), createElementBlock("div", _hoisted_4, [ selectReady.value ? withDirectives((openBlock(), createElementBlock("select", { key: 0, "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => state.currLeague = $event), onChange: handleLeageSelect }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(leagues.value, (item) => { return openBlock(), createElementBlock("option", { key: item, value: item }, toDisplayString(item), 9, _hoisted_5); }), 128)) ], 544)), [ [vModelSelect, state.currLeague] ]) : createCommentVNode("", true), selectReady.value ? withDirectives((openBlock(), createElementBlock("select", { key: 1, "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => state.currCharacter = $event) }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(state.currCharacters, (item) => { return openBlock(), createElementBlock("option", { key: item.name, value: item.name }, toDisplayString(item.name) + "," + toDisplayString(item.level) + "," + toDisplayString(item.class), 9, _hoisted_6); }), 128)) ], 512)), [ [vModelSelect, state.currCharacter] ]) : createCommentVNode("", true), selectReady.value ? (openBlock(), createElementBlock("button", { key: 2, disabled: !exportReady.value, onClick: handleExport }, "导出", 8, _hoisted_7)) : createCommentVNode("", true) ])) : (openBlock(), createElementBlock("div", _hoisted_8, _hoisted_12)) ]), createElementVNode("span", _hoisted_13, [ createElementVNode("input", { disabled: "", maxlength: "50", value: state.buildingCode }, null, 8, _hoisted_14), createElementVNode("button", { onClick: handleCopy, disabled: state.buildingCode.length === 0 }, "复制", 8, _hoisted_15) ]) ], 64); }; } }); const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const Exporter = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-f270e9a2"]]); const _sfc_main = /* @__PURE__ */ defineComponent({ __name: "Monkey", setup(__props) { const factory = new CnPoeTranslator.BasicTranslatorFactory(CnPoeExportDb); const jsonTranslator = factory.getJsonTranslator(); async function createBuilding(items, passiveSkills) { jsonTranslator.translateItems(items); jsonTranslator.translatePassiveSkills(passiveSkills); const building = BuildingCreater.transform(items, passiveSkills); const compressed = window.pako.deflate(building.toString()); const code = btoa(String.fromCharCode(...compressed)).replaceAll("+", "-").replaceAll("/", "_"); return code; } return (_ctx, _cache) => { return openBlock(), createBlock(Exporter, { "create-building": createBuilding }); }; } }); const container = document.createElement("div"); container.id = "exportContainer"; document.body.appendChild(container); createApp(_sfc_main).mount("#exportContainer"); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址