// ==UserScript==
// @name NGA Smiles Manager
// @namespace http://greasyfork.icu/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
// ==/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 = `
<div class="right_" style="margin-bottom: 5px;">
<table class="stdbtn" cellspacing="0">
<tbody>
<tr></tr>
</tbody>
</table>
</div>
<div class="clear"></div>
`;
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 = `<a href="javascript:void(0)" class="nobr silver">${module.name}</a>`;
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 = `
<div class="s-table-wrapper">
<table class="s-table forumbox">
<thead>
<tr class="block_txt_c0">
<th class="c1">标题</th>
<th class="c2">异常信息</th>
<th class="c3" width="1">同步时间</th>
<th class="c4" width="1">是否启用</th>
<th class="c5" width="1">操作</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
`;
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 = `
<td class="c1">
<a href="/read.php?pid=${pid}" class="b nobr">${name}</a>
</td>
<td class="c2">
<span class="nobr">${error}</span>
</td>
<td class="c3">
<span class="nobr">${ui.time2dis(syncDate / 1000)}</span>
</td>
<td class="c4">
<div style="text-align: center;">
<input type="checkbox" ${
enabled ? `checked="checked"` : ""
} />
</div>
</td>
<td class="c5">
<div class="s-button-group">
<button>同步</button>
<button>删除</button>
</div>
</td>
`;
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 = `
<td class="c1" colspan="4">
<div class="s-input-wrapper">
<input value="" />
</div>
</td>
<td class="c5">
<div class="s-button-group">
<button>添加</button>
</div>
</td>
`;
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 = `
<div class="s-table-wrapper">
<table class="s-table forumbox">
<thead>
<tr class="block_txt_c0">
<th class="c1">标题</th>
<th class="c2" width="1">是否启用</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
`;
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 = `
<td class="c1">
<span class="nobr">${name}</span>
</td>
<td class="c2">
<div style="text-align: center;">
<input type="checkbox" ${
hiddenSmiles.includes(name) ? "" : `checked="checked"`
} />
</div>
</td>
`;
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 += `
<div>自动同步设置</div>
<div></div>
`;
[
{
label: "1小时",
value: 3600,
},
{
label: "1天",
value: 3600 * 24,
},
{
label: "从不",
value: 0,
},
].forEach(({ label, value }) => {
const ele = document.createElement("SPAN");
ele.innerHTML += `
<label style="cursor: pointer;">
<input type="radio" name="syncInterval" ${
syncInterval === value && "checked"
}>${label}
</label>
`;
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 += `
<br/>
<div>显示最近表情</div>
<div></div>
`;
[
{
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 += `
<label style="cursor: pointer;">
<input type="radio" name="showRecent" ${
showRecent === value && "checked"
}>${label}
</label>
`;
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<text.length){fragment.appendChild(createText(text.slice(i),true))}subnode.parentNode.replaceChild(fragment,subnode)}}return node}function parseString(str,options){return replace(str,function(rawText){var ret=rawText,iconId=grabTheRightIcon(rawText),src=options.callback(iconId,options),attrib,attrname;if(iconId&&src){ret="<img ".concat('class="',options.className,'" ','draggable="false" ','alt="',rawText,'"',' src="',src,'"');attrib=options.attributes(rawText,iconId);for(attrname in attrib){if(attrib.hasOwnProperty(attrname)&&attrname.indexOf("on")!==0&&ret.indexOf(" "+attrname+"=")===-1){ret=ret.concat(" ",attrname,'="',escapeHTML(attrib[attrname]),'"')}}ret=ret.concat("/>")}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<unicodeSurrogates.length){c=unicodeSurrogates.charCodeAt(i++);if(p){r.push((65536+(p-55296<<10)+(c-56320)).toString(16));p=0}else if(55296<=c&&c<=56319){p=c}else{r.push(c.toString(16))}}return r.join(sep||"-")}}();
// emoji 转换
(() => {
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);