Greasy Fork

Greasy Fork is available in English.

NGA Smiles Manager

表情管理器,支持快速添加表情包,自动同步表情包,隐藏系统表情,显示最近表情,emoji转换

目前为 2022-09-08 提交的版本。查看 最新版本

// ==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={"&":"&amp;","<":"&lt;",">":"&gt;","'":"&#39;",'"':"&quot;"},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);