// ==UserScript== // @name NGA Smiles Manager // @namespace https://greasyfork.org/users/263018 // @version 1.2.2 // @author snyssss // @description 表情管理器,支持快速添加表情包,自动同步表情包,隐藏系统表情,显示最近表情,emoji转换 // @match *://bbs.nga.cn/* // @match *://ngabbs.com/* // @match *://nga.178.com/* // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_addValueChangeListener // @grant GM_xmlhttpRequest // @grant GM_registerMenuCommand // @noframes // @downloadURL none // ==/UserScript== ((ui, poster, smiles, basePath) => { if (!ui) return; if (!poster) return; if (!smiles) return; if (!basePath) return; // 数据操作 const manager = (() => { const KEY = `NGA_SMILES_MANAGER`; const RECENT_KEY = `NGA_SMILES_RECENT`; const data = {}; const fetchData = (pid) => new Promise((resolve, reject) => { const api = `/read.php?pid=${pid}`; fetch(api) .then((res) => res.blob()) .then((blob) => { const reader = new FileReader(); reader.onload = async () => { const parser = new DOMParser(); const doc = parser.parseFromString(reader.result, "text/html"); const verify = doc.querySelector("#m_posts"); if (verify) { const subject = doc.querySelector("#postsubject0").innerHTML; const content = doc.querySelector("#postcontent0").innerHTML; const items = content.match(/(?<=\[img\])(.+?)(?=\[\/img\])/g); if (items.length) { resolve({ name: subject, items, }); } else { reject("图楼内容有误"); } } else { reject(doc.title); } }; reader.readAsText(blob, "GBK"); }) .catch(() => { reject("服务器异常"); }); }); const assign = (next) => { Object.getOwnPropertyNames(data).forEach((property) => { delete data[property]; }); Object.getOwnPropertyNames(next).forEach((property) => { data[property] = next[property]; }); }; const save = () => { GM_setValue(KEY, data); }; const load = () => { assign( GM_getValue(KEY) || { [0]: { syncInterval: 3600, hiddenSmiles: [], showRecent: 0, }, } ); }; const settings = () => { if (Object.keys(data).length < 1) { load(); } return data[0]; }; const updateSettings = (values) => { const entity = settings(); Object.getOwnPropertyNames(values).forEach((property) => { entity[property] = values[property]; }); save(); }; const list = () => { if (Object.keys(data).length < 1) { load(); } return Object.keys(data) .filter((key) => key > 0) .reduce((root, key) => { return [...root, data[key]]; }, []); }; const get = (pid) => { return list().find((item) => item.pid === pid); }; const set = (pid, values) => { const entity = get(pid); if (entity) { Object.getOwnPropertyNames(values).forEach((property) => { entity[property] = values[property]; }); } else { const index = Math.max(...Object.keys(data), 0) + 1; data[index] = { pid, name: `#${pid}`, error: "", enabled: true, syncDate: null, ...values, }; } save(); }; const sync = async (pid) => { const { syncInterval } = settings(); const syncDate = new Date().getTime(); const entity = get(pid); if ( syncInterval > 0 && entity && entity.syncDate + syncInterval * 1000 > syncDate ) { return false; } try { const { name, items } = await fetchData(pid); set(pid, { name: name || `#${pid}`, error: "", syncDate, }); GM_setValue(pid, items); } catch (error) { set(pid, { error, syncDate, }); return false; } return true; }; const add = async (url) => { const params = new URLSearchParams(url.substring(url.indexOf("?"))); const pid = params.get("pid"); if (pid === null) { alert("图楼地址有误"); return false; } await sync(pid); return true; }; const remove = (pid) => { GM_deleteValue(pid); Object.keys(data).forEach((key) => { if (data[key].pid === pid) { delete data[key]; } }); save(); }; const listRecent = () => { return GM_getValue(RECENT_KEY) || []; }; const pushRecent = (value) => { const { showRecent } = settings(); const list = listRecent(); GM_setValue( RECENT_KEY, [value, ...list.filter((item) => item !== value)].slice(0, showRecent) ); }; GM_addValueChangeListener(KEY, function (_, prev, next) { assign(next); }); return { add, set, sync, remove, list, listRecent, pushRecent, settings, updateSettings, }; })(); // STYLE GM_addStyle(` .s-user-info-container:not(:hover) .ah { display: none !important; } .s-table-wrapper { height: calc((2em + 10px) * 11 + 3px); overflow-y: auto; } .s-table { margin: 0; } .s-table th, .s-table td { position: relative; white-space: nowrap; } .s-table th { position: sticky; top: 2px; z-index: 1; } .s-table input:not([type]), .s-table input[type="text"] { margin: 0; box-sizing: border-box; height: 100%; width: 100%; } .s-input-wrapper { position: absolute; top: 6px; right: 6px; bottom: 6px; left: 6px; } .s-text-ellipsis { display: flex; } .s-text-ellipsis > * { flex: 1; width: 1px; overflow: hidden; text-overflow: ellipsis; } .s-button-group { margin: -.1em -.2em; } `); // UI const u = (() => { const modules = {}; const tabContainer = (() => { const c = document.createElement("div"); c.className = "w100"; c.innerHTML = `
`; return c; })(); const tabPanelContainer = (() => { const c = document.createElement("div"); c.style = "width: 600px;"; return c; })(); const content = (() => { const c = document.createElement("div"); c.append(tabContainer); c.append(tabPanelContainer); return c; })(); const addModule = (() => { const tc = tabContainer.getElementsByTagName("tr")[0]; const cc = tabPanelContainer; return (module) => { const tabBox = document.createElement("td"); tabBox.innerHTML = `${module.name}`; const tab = tabBox.childNodes[0]; const toggle = () => { Object.values(modules).forEach((item) => { if (item.tab === tab) { item.tab.className = "nobr"; item.content.style = "display: block"; item.refresh(); } else { item.tab.className = "nobr silver"; item.content.style = "display: none"; } }); }; tc.append(tabBox); cc.append(module.content); tab.onclick = toggle; modules[module.name] = { ...module, tab, toggle, }; return modules[module.name]; }; })(); return { content, modules, addModule, }; })(); // 列表 (() => { const content = (() => { const c = document.createElement("div"); c.style = "display: none"; c.innerHTML = `
标题 异常信息 同步时间 是否启用 操作
`; return c; })(); const refresh = (() => { const container = content.getElementsByTagName("tbody")[0]; const func = () => { container.innerHTML = ""; Object.values(manager.list()).forEach((item) => { const { pid, name, error, enabled, syncDate } = item; const tc = document.createElement("tr"); tc.className = `row${ (container.querySelectorAll("TR").length % 2) + 1 }`; tc.innerHTML = ` ${name} ${error} ${ui.time2dis(syncDate / 1000)}
`; const enabledElement = tc.querySelector(`INPUT[type="checkbox"]`); const save = () => { manager.set(pid, { enabled: enabledElement.checked ? 1 : 0, }); }; enabledElement.onchange = save; const actions = tc.getElementsByTagName("button"); actions[0].onclick = async () => { await manager.sync(pid); refresh(); }; actions[1].onclick = () => { if (confirm("是否确认?")) { manager.remove(pid); refresh(); } }; container.appendChild(tc); }); { const tc = document.createElement("tr"); tc.className = `row${ (container.querySelectorAll("TR").length % 2) + 1 }`; tc.innerHTML = `
`; const inputElement = tc.querySelector("INPUT"); const actions = tc.getElementsByTagName("button"); actions[0].onclick = async () => { if (inputElement.value) { if (await manager.add(inputElement.value)) { refresh(); } } }; container.appendChild(tc); } }; return func; })(); u.addModule({ name: "列表", content, refresh, }); })(); // 系统 (() => { const content = (() => { const c = document.createElement("div"); c.style = "display: none"; c.innerHTML = `
标题 是否启用
`; return c; })(); const refresh = (() => { const container = content.getElementsByTagName("tbody")[0]; const func = () => { container.innerHTML = ""; const hiddenSmiles = manager.settings().hiddenSmiles || []; Object.values(smiles).forEach((item) => { const { _______name: name } = item; if (name) { const tc = document.createElement("tr"); tc.className = `row${ (container.querySelectorAll("TR").length % 2) + 1 }`; tc.innerHTML = ` ${name}
`; const enabledElement = tc.querySelector(`INPUT[type="checkbox"]`); const save = () => { manager.updateSettings({ hiddenSmiles: hiddenSmiles .filter((item) => item !== name) .concat(enabledElement.checked ? [] : [name]), }); refresh(); }; enabledElement.onchange = save; container.appendChild(tc); } }); }; return func; })(); u.addModule({ name: "系统", content, refresh, }); })(); // 通用设置 (() => { const content = (() => { const c = document.createElement("div"); c.style = "display: none"; return c; })(); const refresh = (() => { const container = content; const func = () => { container.innerHTML = ""; // 自动同步 { const syncInterval = manager.settings().syncInterval || 0; const tc = document.createElement("div"); tc.innerHTML += `
自动同步设置
`; [ { label: "1小时", value: 3600, }, { label: "1天", value: 3600 * 24, }, { label: "从不", value: 0, }, ].forEach(({ label, value }) => { const ele = document.createElement("SPAN"); ele.innerHTML += ` `; const items = ele.querySelector("input"); items.onchange = () => { if (items.checked) { manager.updateSettings({ syncInterval: value, }); } }; tc.querySelectorAll("div")[1].append(ele); }); container.appendChild(tc); } // 显示最近表情 { const showRecent = manager.settings().showRecent || 0; const tc = document.createElement("div"); tc.innerHTML += `
显示最近表情
`; [ { label: "0", value: 0, }, { label: "10", value: 10, }, { label: "20", value: 20, }, { label: "50", value: 50, }, ].forEach(({ label, value }) => { const ele = document.createElement("SPAN"); ele.innerHTML += ` `; const items = ele.querySelector("input"); items.onchange = () => { if (items.checked) { manager.updateSettings({ showRecent: value, }); } }; tc.querySelectorAll("div")[1].append(ele); }); container.appendChild(tc); } }; return func; })(); u.addModule({ name: "设置", content, refresh, }); })(); // 增加菜单项 (() => { const title = "表情管理"; let window; ui.mainMenu.addItemOnTheFly(title, null, () => { if (window === undefined) { window = ui.createCommmonWindow(); } u.modules["列表"].toggle(); window._.addContent(null); window._.addTitle(title); window._.addContent(u.content); window._.show(); }); })(); // 判断是否为系统表情 const isSystemSmile = (value) => { const result = value.match(/\[s:(.{1,10}?)\]/); if (result) { const [group, item] = parseInt(result[1], 10) ? [0, result[1]] : result[1].split(":"); if (smiles[group || 0] && smiles[group || 0][item]) { return `${basePath}/post/smile/${smiles[group || 0][item]}`; } } return null; }; // 加载表情 const loadSmile = (content, list) => { const { correctAttachUrl } = ui; content.innerHTML = ``; list.forEach((item) => { const smile = document.createElement("IMG"); const path = isSystemSmile(item); if (path) { smile.src = path; smile.onclick = () => { poster.selectSmilesw._.hide(); poster.addText(item); }; } else { smile.src = item.indexOf("http") < 0 ? correctAttachUrl(item) : item; smile.style = "max-height: 200px"; smile.onclick = () => { poster.selectSmilesw._.hide(); poster.addText(`[img]${item}[/img]`); manager.pushRecent(item); }; } content.appendChild(smile); }); }; // 加载表情 const loadSmiles = (loaded) => { if (loaded) return; const tabs = poster.selectSmilesw._.__c.firstElementChild; const contents = poster.selectSmilesw._.__c.lastElementChild; const hiddenSmiles = manager.settings().hiddenSmiles || []; [...tabs.querySelectorAll("button.block_txt_big")].forEach((item) => { const name = item.innerHTML; if (hiddenSmiles.includes(name)) { item.style.display = "none"; } }); manager.list().forEach((item) => { const { pid, name, enabled } = item; if (enabled) { const tab = document.createElement("BUTTON"); const content = document.createElement("DIV"); tab.className = "block_txt_big"; tab.innerText = name; tab.onclick = async () => { tabs.firstChild.innerHTML = ``; contents.childNodes.forEach((item) => { if (item !== content) { item.style.display = "none"; } else { item.style.display = ""; } }); if (content.childNodes.length === 0) { await manager.sync(pid); const list = GM_getValue(pid) || []; loadSmile(content, list); } }; tabs.appendChild(tab); contents.appendChild(content); } }); }; // 加载最近表情 const loadRecent = () => { const list = manager.listRecent(); if (list.length) { const contents = poster.selectSmilesw._.__c.lastElementChild; const recentElementId = `smile_recent`; const recentElement = contents.querySelector(`[id="smile_recent"]`) || document.createElement("DIV"); if (!recentElement.id) { recentElement.id = recentElementId; contents.appendChild(recentElement); } contents.childNodes.forEach((item) => { if (item !== recentElement) { item.style.display = "none"; } else { item.style.display = ""; } }); loadSmile(recentElement, list); } }; // 加载脚本 (() => { const hookFunction = (object, functionName, callback) => { ((originalFunction) => { object[functionName] = function () { const returnValue = originalFunction.apply(this, arguments); callback.apply(this, [returnValue, originalFunction, arguments]); return returnValue; }; })(object[functionName]); }; hookFunction(poster, "selectSmiles", (returnValue) => { loadSmiles(returnValue); loadRecent(); }); hookFunction(poster, "addText", (returnValue, _, arguments) => { const path = isSystemSmile(arguments[0]); if (path) { manager.pushRecent(arguments[0]); } }); })(); // twemoji /*! Copyright Twitter Inc. and other contributors. Licensed under MIT */ var twemoji=function(){"use strict";var twemoji={base:"https://twemoji.maxcdn.com/v/14.0.2/",ext:".png",size:"72x72",className:"emoji",convert:{fromCodePoint:fromCodePoint,toCodePoint:toCodePoint},onerror:function onerror(){if(this.parentNode){this.parentNode.replaceChild(createText(this.alt,false),this)}},parse:parse,replace:replace,test:test},escaper={"&":"&","<":"<",">":">","'":"'",'"':"""},re=/(?:\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83e\udef1\ud83c\udffb\u200d\ud83e\udef2\ud83c[\udffc-\udfff]|\ud83e\udef1\ud83c\udffc\u200d\ud83e\udef2\ud83c[\udffb\udffd-\udfff]|\ud83e\udef1\ud83c\udffd\u200d\ud83e\udef2\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\udef1\ud83c\udffe\u200d\ud83e\udef2\ud83c[\udffb-\udffd\udfff]|\ud83e\udef1\ud83c\udfff\u200d\ud83e\udef2\ud83c[\udffb-\udffe]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1|\ud83d\udc6b\ud83c[\udffb-\udfff]|\ud83d\udc6c\ud83c[\udffb-\udfff]|\ud83d\udc6d\ud83c[\udffb-\udfff]|\ud83d\udc8f\ud83c[\udffb-\udfff]|\ud83d\udc91\ud83c[\udffb-\udfff]|\ud83e\udd1d\ud83c[\udffb-\udfff]|\ud83d[\udc6b-\udc6d\udc8f\udc91]|\ud83e\udd1d)|(?:\ud83d[\udc68\udc69]|\ud83e\uddd1)(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf7c\udf84\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddaf-\uddb3\uddbc\uddbd])|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc70\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddcd-\uddcf\uddd4\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f|(?:\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83d\ude36\u200d\ud83c\udf2b\ufe0f|\u2764\ufe0f\u200d\ud83d\udd25|\u2764\ufe0f\u200d\ud83e\ude79|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc15\u200d\ud83e\uddba|\ud83d\udc3b\u200d\u2744\ufe0f|\ud83d\udc41\u200d\ud83d\udde8|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83d\ude2e\u200d\ud83d\udca8|\ud83d\ude35\u200d\ud83d\udcab|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f|\ud83d\udc08\u200d\u2b1b)|[#*0-9]\ufe0f?\u20e3|(?:[©®\u2122\u265f]\ufe0f)|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\u203c\u2049\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26a7\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f8\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75\udd90]|[\u261d\u26f7\u26f9\u270c\u270d])(?:\ufe0f|(?!\ufe0e))|(?:\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0\udecc]|\ud83e[\udd0c\udd0f\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\udd77\uddb5\uddb6\uddb8\uddb9\uddbb\uddcd-\uddcf\uddd1-\udddd\udec3-\udec5\udef0-\udef6]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udc8e\udc90\udc92-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\uded5-\uded7\udedd-\udedf\udeeb\udeec\udef4-\udefc\udfe0-\udfeb\udff0]|\ud83e[\udd0d\udd0e\udd10-\udd17\udd20-\udd25\udd27-\udd2f\udd3a\udd3c\udd3f-\udd45\udd47-\udd76\udd78-\uddb4\uddb7\uddba\uddbc-\uddcc\uddd0\uddde-\uddff\ude70-\ude74\ude78-\ude7c\ude80-\ude86\ude90-\udeac\udeb0-\udeba\udec0-\udec2\uded0-\uded9\udee0-\udee7]|[\u23e9-\u23ec\u23f0\u23f3\u267e\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f/g,UFE0Fg=/\uFE0F/g,U200D=String.fromCharCode(8205),rescaper=/[&<>'"]/g,shouldntBeParsed=/^(?:iframe|noframes|noscript|script|select|style|textarea)$/,fromCharCode=String.fromCharCode;return twemoji;function createText(text,clean){return document.createTextNode(clean?text.replace(UFE0Fg,""):text)}function escapeHTML(s){return s.replace(rescaper,replacer)}function defaultImageSrcGenerator(icon,options){return"".concat(options.base,options.size,"/",icon,options.ext)}function grabAllTextNodes(node,allText){var childNodes=node.childNodes,length=childNodes.length,subnode,nodeType;while(length--){subnode=childNodes[length];nodeType=subnode.nodeType;if(nodeType===3){allText.push(subnode)}else if(nodeType===1&&!("ownerSVGElement"in subnode)&&!shouldntBeParsed.test(subnode.nodeName.toLowerCase())){grabAllTextNodes(subnode,allText)}}return allText}function grabTheRightIcon(rawText){return toCodePoint(rawText.indexOf(U200D)<0?rawText.replace(UFE0Fg,""):rawText)}function parseNode(node,options){var allText=grabAllTextNodes(node,[]),length=allText.length,attrib,attrname,modified,fragment,subnode,text,match,i,index,img,rawText,iconId,src;while(length--){modified=false;fragment=document.createDocumentFragment();subnode=allText[length];text=subnode.nodeValue;i=0;while(match=re.exec(text)){index=match.index;if(index!==i){fragment.appendChild(createText(text.slice(i,index),true))}rawText=match[0];iconId=grabTheRightIcon(rawText);i=index+rawText.length;src=options.callback(iconId,options);if(iconId&&src){img=new Image;img.onerror=options.onerror;img.setAttribute("draggable","false");attrib=options.attributes(rawText,iconId);for(attrname in attrib){if(attrib.hasOwnProperty(attrname)&&attrname.indexOf("on")!==0&&!img.hasAttribute(attrname)){img.setAttribute(attrname,attrib[attrname])}}img.className=options.className;img.alt=rawText;img.src=src;modified=true;fragment.appendChild(img)}if(!img)fragment.appendChild(createText(rawText,false));img=null}if(modified){if(i")}return ret})}function replacer(m){return escaper[m]}function returnNull(){return null}function toSizeSquaredAsset(value){return typeof value==="number"?value+"x"+value:value}function fromCodePoint(codepoint){var code=typeof codepoint==="string"?parseInt(codepoint,16):codepoint;if(code<65536){return fromCharCode(code)}code-=65536;return fromCharCode(55296+(code>>10),56320+(code&1023))}function parse(what,how){if(!how||typeof how==="function"){how={callback:how}}return(typeof what==="string"?parseString:parseNode)(what,{callback:how.callback||defaultImageSrcGenerator,attributes:typeof how.attributes==="function"?how.attributes:returnNull,base:typeof how.base==="string"?how.base:twemoji.base,ext:how.ext||twemoji.ext,size:how.folder||toSizeSquaredAsset(how.size||twemoji.size),className:how.className||twemoji.className,onerror:how.onerror||twemoji.onerror})}function replace(text,callback){return String(text).replace(re,callback)}function test(text){re.lastIndex=0;var result=re.test(text);re.lastIndex=0;return result}function toCodePoint(unicodeSurrogates,sep){var r=[],c=0,p=0,i=0;while(i { const ENABLE_KEY = "EMOJI_CONVERTER_ENABLE"; const isEnable = GM_getValue(ENABLE_KEY) || false; if (isEnable) { GM_registerMenuCommand("Emoji转换:启用", () => { GM_setValue(ENABLE_KEY, false); location.reload(); }); } else { GM_registerMenuCommand("Emoji转换:禁用", () => { GM_setValue(ENABLE_KEY, true); location.reload(); }); } const getCurrentPostStat = async () => { if (poster.currentPostStat) { return poster.currentPostStat; } const data = await new Promise((resolve) => { const api = (() => { if (__CURRENT_TID) { return `/post.php?lite=js&tid=${__CURRENT_TID}`; } if (__CURRENT_FID) { return `/post.php?lite=js&fid=${__CURRENT_FID}`; } return null; })(); if (api) { fetch(api) .then((res) => res.blob()) .then((blob) => { const reader = new FileReader(); reader.onload = () => { const text = reader.result; const result = JSON.parse( text.replace("window.script_muti_get_var_store=", "") ); resolve(result.data); }; reader.readAsText(blob, "GBK"); }) .catch(() => { resolve({}); }); } else { resolve({}); } }); return data; }; const emojiConvert = async (str, size = 20) => { const cache = {}; const { attach_url, fid, auth } = await getCurrentPostStat(); if (auth) { twemoji.parse(str, { callback: (icon, options) => { const key = twemoji.convert.fromCodePoint(icon); const url = "".concat( options.base, options.size, "/", icon, options.ext ); if (cache[key] === undefined) { cache[key] = new Promise((resolve) => { GM_xmlhttpRequest({ url, responseType: "blob", onload: ({ response }) => { const canvas = document.createElement("CANVAS"); const ctx = canvas.getContext("2d"); const img = new Image(); canvas.width = size; canvas.height = size; img.onload = () => { ctx.drawImage(img, 1, 1, size - 2, size - 2); canvas.toBlob((blob) => { resolve(blob); }); }; img.src = URL.createObjectURL(response); }, onerror: () => { resolve(null); }, }); }); } return ""; }, }); await Promise.all( Object.entries(cache).map(async ([key, value]) => { try { cache[key] = await value .then((blob) => { const filename = `${twemoji.convert.toCodePoint(key)}.png`; const file = new File([blob], filename, { type: blob.type, lastModified: Date.now(), }); const formData = new FormData(); formData.append("v2", "1"); formData.append("func", "upload"); formData.append("attachment_file1", file); formData.append( "attachment_file1_url_utf8_name", poster.rawUrlEncode(filename) ); formData.append("attachment_file1_img", "1"); formData.append("attachment_file1_dscp", ""); formData.append("attachment_file1_auto_size", "0"); formData.append("fid", fid); formData.append("auth", auth); formData.append("__output", "11"); return fetch(attach_url, { method: "POST", body: formData }); }) .then((res) => res.json()) .then((res) => { return res; }); } catch { cache[key] = null; } }) ); return cache; } return null; }; if (isEnable) { ui.newPost = ((newPost) => { return async function (...arguments) { const data = await emojiConvert(arguments[8]); if (data) { arguments[8] = Object.entries(data).reduce((root, [key, item]) => { if (item) { return root.replaceAll(key, `[img]./${item.url}[/img]`); } return root; }, arguments[8]); arguments[11] = arguments[11] || ""; arguments[11] += Object.values(data) .filter((item) => item !== null) .map((item) => item.attachments) .join("\t"); arguments[12] = arguments[12] || ""; arguments[12] += Object.values(data) .filter((item) => item !== null) .map((item) => item.attachments_check) .join("\t"); } newPost.apply(this, arguments); }; })(ui.newPost); } })(); })(commonui, postfunc, ubbcode.smiles, __IMGPATH);