{"id":10,"date":"2025-12-10T16:19:38","date_gmt":"2025-12-10T08:19:38","guid":{"rendered":"https:\/\/blog.jj.mr\/?p=10"},"modified":"2025-12-10T16:19:38","modified_gmt":"2025-12-10T08:19:38","slug":"%e3%80%90%e8%bd%ac%e8%bd%bd%e3%80%91%e5%88%86%e4%ba%ab%e4%b8%80%e4%b8%aa%e8%87%aa%e7%94%a8%e5%b0%8f%e8%84%9a%e6%9c%ac%ef%bc%9alinux-do-%e4%b8%bb%e6%a5%bc%e4%b8%80%e9%94%ae%e6%94%b6%e8%97%8f%e5%88%b0-w","status":"publish","type":"post","link":"https:\/\/blog.jj.mr\/index.php\/2025\/12\/10\/%e3%80%90%e8%bd%ac%e8%bd%bd%e3%80%91%e5%88%86%e4%ba%ab%e4%b8%80%e4%b8%aa%e8%87%aa%e7%94%a8%e5%b0%8f%e8%84%9a%e6%9c%ac%ef%bc%9alinux-do-%e4%b8%bb%e6%a5%bc%e4%b8%80%e9%94%ae%e6%94%b6%e8%97%8f%e5%88%b0-w\/","title":{"rendered":"\u3010\u8f6c\u8f7d\u3011\u5206\u4eab\u4e00\u4e2a\u81ea\u7528\u5c0f\u811a\u672c\uff1alinux.do \u4e3b\u697c\u4e00\u952e\u6536\u85cf\u5230 WordPress"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\" style=\"\n  margin:0 0 10px 0;\n  padding:7px 10px;\n  background:#f6f7f9;\n  border-left:3px solid #94a3b8;\n  border-radius:6px;\n  font-size:13.5px;\n  color:#475569;\n  line-height:1.7;\n\">\n  \u672c\u6587\u4e3a\u8f6c\u8f7d\u5185\u5bb9\uff0c\u4fdd\u7559\u539f\u5e16\u89c2\u70b9\u4e0e\u7ed3\u6784\uff1b\u5982\u6709\u4fb5\u6743\u8bf7\u8054\u7cfb\u6211\u5904\u7406\u3002\n<\/p>\n<p dir=\"auto\" style=\"margin: 0px 0px 14px; line-height: 1.8; font-size: 16px;\">\u6700\u8fd1\u901b <a href=\"http:\/\/linux.do\">linux.do<\/a> \u7ecf\u5e38\u770b\u5230\u597d\u5e16\uff0c\u60f3\u987a\u624b\u4fdd\u5b58\u5230\u81ea\u5df1 WordPress \u91cc\u505a\u4e2a\u4eba\u7b14\u8bb0\/\u6536\u85cf\uff0c\u6240\u4ee5\u5199\u4e86\u4e2a\u6d4f\u89c8\u5668\u811a\u672c\u5206\u4eab\u4e00\u4e0b\u3002<\/p>\n<p dir=\"auto\" style=\"margin: 0px 0px 14px; line-height: 1.8; font-size: 16px;\"><strong>\u8bf4\u660e\uff1a<\/strong><\/p>\n<ul dir=\"auto\" style=\"margin: 0px 0px 14px 20px; line-height: 1.8; font-size: 16px;\">\n<li style=\"margin: 4px 0px;\">\u811a\u672c\u53ea\u7528\u4e8e<strong>\u4e2a\u4eba\u6536\u85cf\/\u5b66\u4e60\u8bb0\u5f55<\/strong>\uff0c\u4e0d\u505a\u5546\u4e1a\u7528\u9014\u3002<\/li>\n<li style=\"margin: 4px 0px;\">\u8f6c\u8f7d\u5230 WP \u540e\u4f1a\u5728\u6587\u672b\u81ea\u52a8\u6807\u6ce8<strong>\u539f\u5e16\u94fe\u63a5<\/strong>\u548c<strong>\u539f\u4f5c\u8005<\/strong>\uff0c\u7248\u6743\u5f52\u539f\u4f5c\u8005\u6240\u6709\u3002<\/li>\n<li style=\"margin: 4px 0px;\">\u5982\u539f\u4f5c\u8005\u4e0d\u5e0c\u671b\u88ab\u8f6c\u8f7d\uff0c\u8bf7\u7559\u8a00\uff0c\u6211\u4f1a\u53ca\u65f6\u5220\u9664\u3002<\/li>\n<\/ul>\n<p dir=\"auto\" style=\"margin: 0px 0px 14px; line-height: 1.8; font-size: 16px;\"><strong>\u529f\u80fd\uff1a<\/strong><\/p>\n<ul dir=\"auto\" style=\"margin: 0px 0px 14px 20px; line-height: 1.8; font-size: 16px;\">\n<li style=\"margin: 4px 0px;\">\u53ea\u8f6c\u8f7d\u697c\u4e3b\u4e3b\u697c\u5185\u5bb9\uff08\u4e0d\u542b\u8bc4\u8bba\uff09<\/li>\n<li style=\"margin: 4px 0px;\">\u6807\u9898\u52a0\u3010\u8f6c\u8f7d\u3011<\/li>\n<li style=\"margin: 4px 0px;\">\u4fee\u590d\u61d2\u52a0\u8f7d\u56fe\u7247<\/li>\n<li style=\"margin: 4px 0px;\">\u53ef\u9009\u628a\u5916\u94fe\u56fe\u7247\u4e0b\u8f7d\u5230 WP \u5a92\u4f53\u5e93<\/li>\n<li style=\"margin: 4px 0px;\">\u53ef\u9009\u8349\u7a3f\/\u76f4\u63a5\u53d1\u5e03<\/li>\n<li style=\"margin: 4px 0px;\">\u6587\u672b\u81ea\u52a8\u8ffd\u52a0\u8f6c\u8f7d\u4fe1\u606f<\/li>\n<\/ul>\n<p dir=\"auto\" style=\"margin: 0px 0px 14px; line-height: 1.8; font-size: 16px;\"><strong>\u4f7f\u7528\u8bf4\u660e\uff1a<\/strong><\/p>\n<ol dir=\"auto\" style=\"margin: 0px 0px 14px 20px; line-height: 1.8; font-size: 16px;\">\n<li style=\"margin: 4px 0px;\">\u7535\u8111\u6d4f\u89c8\u5668\u5b89\u88c5 Tampermonkey\uff08\u6cb9\u7334\uff09\u3002<\/li>\n<li style=\"margin: 4px 0px;\">\u65b0\u5efa\u811a\u672c\uff0c\u628a\u4ee3\u7801\u5168\u90e8\u7c98\u8fdb\u53bb\u4fdd\u5b58\u3002<\/li>\n<li style=\"margin: 4px 0px;\">\u4fee\u6539\u811a\u672c\u9876\u90e8\u4e24\u5904\uff1a<\/li>\n<\/ol>\n<ul dir=\"auto\" style=\"margin: 0px 0px 14px 20px; line-height: 1.8; font-size: 16px;\">\n<li style=\"margin: 4px 0px;\"><code>WP_BASE = \"\u4f60\u7684\u535a\u5ba2\u5730\u5740\"<\/code><\/li>\n<li style=\"margin: 4px 0px;\"><code>@connect \u4f60\u7684\u535a\u5ba2\u57df\u540d<\/code><\/li>\n<\/ul>\n<ol start=\"4\" dir=\"auto\" style=\"margin: 0px 0px 14px 20px; line-height: 1.8; font-size: 16px;\">\n<li style=\"margin: 4px 0px;\"><strong>\u5148\u5728\u540c\u4e00\u6d4f\u89c8\u5668\u767b\u5f55\u4e00\u6b21 WordPress \u540e\u53f0<\/strong>\uff08\u5426\u5219\u65e0\u6cd5\u53d1\u5e03\uff09\u3002<\/li>\n<li style=\"margin: 4px 0px;\">\u6253\u5f00\u4efb\u610f <a href=\"http:\/\/linux.do\">linux.do<\/a> \u5e16\u5b50\u9875\u3002<\/li>\n<li style=\"margin: 4px 0px;\">\u53f3\u4e0b\u89d2\u4f1a\u51fa\u73b0 <strong>\u201c\u8f6c\u8f7d\u5230 WP\u201d<\/strong> \u6309\u94ae\u3002<\/li>\n<li style=\"margin: 4px 0px;\">\u70b9\u6309\u94ae \u2192 \u9009\u62e9\u5206\u7c7b\/\u662f\u5426\u56fe\u7247\u5165\u5e93\/\u8349\u7a3f\u6216\u53d1\u5e03 \u2192 \u53d1\u9001\u5373\u53ef\u3002<\/li>\n<\/ol>\n<p dir=\"auto\" style=\"margin: 0px 0px 14px; line-height: 1.8; font-size: 16px;\"><p style=\"margin: 0px 0px 14px; line-height: 1.8; font-size: 16px;\">iOS\uff1aSafari \u88c5 Userscripts \u6269\u5c55\u6216\u7528 Orion \u6d4f\u89c8\u5668\uff0c\u5bfc\u5165\u811a\u672c\u540e\u6b65\u9aa4\u4e00\u6837\u3002<\/p><p style=\"margin: 0px 0px 14px; line-height: 1.8; font-size: 16px;\">\u4e0b\u9762\u662f\u6b63\u5f0f\u7248\u4ee3\u7801\uff08\u5df2\u53ef\u7528\uff09\uff1a<\/p><\/p>\n<pre dir=\"auto\" class=\"codeblock-buttons\"><code class=\"lang-auto\">\/\/ ==UserScript==\n\/\/ @name         linux.do \u2192 WordPress \u7eaf\u8f6c\u8f7d \u6b63\u5f0f\u7248\uff08\u4e24\u6b65\u53d1\u5e03\u9632\u8d85\u65f6+\u65e0AI+\u65e0\u5feb\u6377\u952e+\u53ea\u4e3b\u697c+\u56fe\u7247\u5165\u5e93\u9650\u5e76\u53d1+\u53bb\u56fe\u7247\u540d+\u6b63\u6587\u4f18\u5316\u65e0\u76ee\u5f55+Gutenberg\u65e0\u7a7a\u884c+\u65e5\u5fd7\u6846\uff09\n\/\/ @namespace    http:\/\/tampermonkey.net\/\n\/\/ @version      7.0.0\n\/\/ @description  \u53ea\u8f6c\u8f7d linux.do \u4e3b\u697c\u5230 WordPress\uff1a\u65e0 AI\u3001\u65e0\u5feb\u6377\u952e\u3001\u6807\u9898\u524d\u52a0\u3010\u8f6c\u8f7d\u3011\uff1b\u6e05\u7406\u56fe\u7247\u6587\u4ef6\u540d\/\u54c8\u5e0c\/\u5c3a\u5bf8\/KB\/\u622a\u56fe\u8f6f\u4ef6\u540d\u7b49\u5143\u4fe1\u606f\uff08\u4ec5\u6e05\u6587\u672c\u4e0d\u4f24\u56fe\u7247\uff09\uff1b\u4fee\u590d\u61d2\u52a0\u8f7d\u56fe\u7247\uff1b\u6b63\u6587\u7ed3\u6784\u8f7b\u4f18\u5316\uff08\u6bb5\u843d\/\u5217\u8868\/\u56fe\u7247\/\u95f4\u8ddd\uff0c\u65e0\u76ee\u5f55\uff09\uff1b\u53ef\u9009\u5206\u7c7b\/\u8349\u7a3f\u6216\u53d1\u5e03\/\u56fe\u7247\u5165\u5e93\uff1b\u672b\u5c3e\u7f8e\u5316\u8f6c\u8f7d\u4fe1\u606f\u4e14\u4e0d\u88ab\u4e3b\u9898\u6253\u4e71\uff1bUI \u5185\u7f6e\u8fd0\u884c\u65e5\u5fd7\u6846\uff1b\u56fe\u7247\u5165\u5e93\u652f\u6301\u5e76\u53d1\u9650\u901f+\u8df3\u8fc7\u5927\u56fe+\u5931\u8d25\u4e0d\u4e2d\u65ad\uff1b\u53d1\u5e03\u91c7\u7528\u201c\u4e24\u6b65\u53d1\u7a3f\u201d\u9632 WP \u8d85\u65f6\uff1bintro \u4e3a Gutenberg \u6bb5\u843d\u5757\uff0c\u540e\u53f0\u7f16\u8f91\u5668\u65e0\u9996\u884c\u7a7a\u6bb5\u843d\u3002\n\/\/ @match        https:\/\/linux.do\/t\/*\n\/\/ @grant        GM_xmlhttpRequest\n\/\/ @connect      blog.qinnian.xyz\n\/\/ ==\/UserScript==\n \n(function () {\n  \"use strict\";\n \n  \/************** \u914d\u7f6e\u533a\uff08\u5fc5\u6539\uff09 **************\/\n  const WP_BASE = \"https:\/\/blog.qinnian.xyz\"; \/\/ \u4f60\u7684 WordPress\uff08\u4e0d\u8981\u4ee5 \/ \u7ed3\u5c3e\uff09\n  const DEFAULT_STATUS = \"draft\";             \/\/ draft \u8349\u7a3f \/ publish \u53d1\u5e03\n  const DEFAULT_DOWNLOAD_IMAGES = true;       \/\/ \u9ed8\u8ba4\u52fe\u9009\u201c\u56fe\u7247\u5165\u5e93\u201d\n  \/*******************************************\/\n \n  const WP_POSTS = `${WP_BASE}\/wp-json\/wp\/v2\/posts`;\n  const WP_CATEGORIES = `${WP_BASE}\/wp-json\/wp\/v2\/categories?per_page=100`;\n  const WP_MEDIA = `${WP_BASE}\/wp-json\/wp\/v2\/media`;\n  const WP_ADMIN = `${WP_BASE}\/wp-admin\/`;\n \n  let cachedNonce = null;\n  let cachedNonceAt = 0;\n \n  const $ = (sel, root = document) =&gt; root.querySelector(sel);\n \n  function escapeHtml(str = \"\") {\n    return str.replace(\/[&amp;&lt;&gt;\"']\/g, (ch) =&gt; ({\n      \"&amp;\": \"&amp;amp;\", \"&lt;\": \"&amp;lt;\", \"&gt;\": \"&amp;gt;\",\n      '\"': \"&amp;quot;\", \"'\": \"&amp;#39;\",\n    }[ch]));\n  }\n \n  function toErrorMessage(e) {\n    if (!e) return \"\u672a\u77e5\u9519\u8bef\";\n    if (typeof e === \"string\") return e;\n    if (e.message) return e.message;\n    try { return JSON.stringify(e); } catch { return String(e); }\n  }\n \n  \/\/ \u2705 \u9632\u5361\u6b7b\u7248 GM \u8bf7\u6c42\uff08\u5f3a\u5236\u8d85\u65f6\uff09\n  function gmRequest({ method, url, headers = {}, data = null, timeout = 60000, binary = false }) {\n    return new Promise((resolve, reject) =&gt; {\n      let finished = false;\n \n      const timer = setTimeout(() =&gt; {\n        if (finished) return;\n        finished = true;\n        reject(new Error(`\u8bf7\u6c42\u8d85\u65f6\uff08&gt;${timeout\/1000}s\uff09\uff1a${url}`));\n      }, timeout + 2000);\n \n      GM_xmlhttpRequest({\n        method, url, headers, data, timeout, binary,\n        anonymous: false,\n        onload: (resp) =&gt; {\n          if (finished) return;\n          finished = true;\n          clearTimeout(timer);\n          resolve(resp);\n        },\n        onerror: (err) =&gt; {\n          if (finished) return;\n          finished = true;\n          clearTimeout(timer);\n          reject(new Error(\"\u7f51\u7edc\u9519\u8bef\uff1a\" + toErrorMessage(err)));\n        },\n        ontimeout: () =&gt; {\n          if (finished) return;\n          finished = true;\n          clearTimeout(timer);\n          reject(new Error(\"GM \u8bf7\u6c42\u8d85\u65f6\"));\n        },\n      });\n    });\n  }\n \n  \/* ---------------- 0) \u83b7\u53d6 WP REST Nonce\uff08\u57fa\u4e8e\u767b\u5f55\u6001\uff09 ---------------- *\/\n \n  async function getRestNonce() {\n    const now = Date.now();\n    if (cachedNonce &amp;&amp; now - cachedNonceAt &lt; 10 * 60 * 1000) return cachedNonce;\n \n    const resp = await gmRequest({ method: \"GET\", url: WP_ADMIN, timeout: 60000 });\n    if (resp.status &lt; 200 || resp.status &gt;= 300) {\n      throw new Error(`\u83b7\u53d6\u540e\u53f0\u9875\u9762\u5931\u8d25(${resp.status})\uff0c\u8bf7\u786e\u8ba4\u5df2\u5728\u672c\u6d4f\u89c8\u5668\u767b\u5f55 WP \u540e\u53f0\u3002`);\n    }\n \n    const html = resp.responseText || \"\";\n    const m1 = html.match(\/wpApiSettings\\s*=\\s*{[^}]*\"nonce\"\\s*:\\s*\"([^\"]+)\"\/);\n    const m2 = html.match(\/\"rest_nonce\"\\s*:\\s*\"([^\"]+)\"\/);\n    const nonce = (m1 &amp;&amp; m1[1]) || (m2 &amp;&amp; m2[1]);\n \n    if (!nonce) {\n      throw new Error(\"\u672a\u80fd\u89e3\u6790 REST Nonce\uff0c\u8bf7\u68c0\u67e5\u662f\u5426\u6709\u5b89\u5168\u63d2\u4ef6\u79fb\u9664\u4e86\u540e\u53f0 nonce\u3002\");\n    }\n \n    cachedNonce = nonce;\n    cachedNonceAt = now;\n    return nonce;\n  }\n \n  \/* ---------------- 1) \u63d0\u53d6 linux.do \u4e3b\u697c + \u53ea\u6e05\u6587\u672c\u4e0d\u4f24\u56fe ---------------- *\/\n \n  function extractLinuxDoOP() {\n    const rawTitle =\n      $(\"#topic-title h1 a, #topic-title a\")?.innerText?.trim() ||\n      document.title.trim();\n \n    const title = `\u3010\u8f6c\u8f7d\u3011${rawTitle}`;\n \n    const firstPost = document.querySelector(\".post-stream article[data-post-id]\");\n    if (!firstPost) throw new Error(\"\u672a\u627e\u5230\u4e3b\u697c\uff08\u7b2c\u4e00\u4e2a\u5e16\u5b50\u5143\u7d20\u4e0d\u5b58\u5728\uff09\");\n \n    const author =\n      firstPost.dataset.username ||\n      firstPost.querySelector(\".username\")?.innerText?.trim() ||\n      \"\";\n \n    const cooked = firstPost.querySelector(\".cooked\");\n    if (!cooked) throw new Error(\"\u672a\u627e\u5230\u4e3b\u697c\u6b63\u6587\uff08.cooked\uff09\");\n \n    const clone = cooked.cloneNode(true);\n \n    clone.querySelectorAll(\n      \"script, style, nav, footer, .quote-controls, .post-menu-area, .onebox-metadata\"\n    ).forEach(n =&gt; n.remove());\n \n    clone.querySelectorAll(\"figcaption\").forEach(n =&gt; n.remove());\n \n    \/\/ \u6e05\u7406 a(img) \u5468\u56f4\u7684\u6587\u672c\n    clone.querySelectorAll(\"a\").forEach(a =&gt; {\n      if (a.querySelector(\"img\")) {\n        [...a.childNodes].forEach(node =&gt; {\n          if (node.nodeType === Node.TEXT_NODE &amp;&amp; node.textContent.trim()) node.remove();\n        });\n      }\n    });\n \n    \/\/ \u4fee\u590d\u61d2\u52a0\u8f7d\n    clone.querySelectorAll(\"img\").forEach(img =&gt; {\n      const src = img.getAttribute(\"src\") || \"\";\n      const dataSrc =\n        img.getAttribute(\"data-src\") ||\n        img.getAttribute(\"data-original\") ||\n        img.getAttribute(\"data-lazy-src\") ||\n        img.getAttribute(\"data-actualsrc\") ||\n        \"\";\n      if ((!src || src === \"about:blank\") &amp;&amp; dataSrc) {\n        img.setAttribute(\"src\", dataSrc);\n      }\n    });\n \n    \/\/ \u5224\u65ad\u662f\u5426\u662f\u201c\u56fe\u7247\u540d\/\u5c3a\u5bf8\/\u54c8\u5e0c\/KB\/\u622a\u56fe\u8f6f\u4ef6\u540d\u201d\u7b49\u5143\u6587\u672c\n    const isMetaText = (t = \"\") =&gt; {\n      const s = t.trim();\n      if (!s) return false;\n \n      const hasSize = \/\\d+\\s*[x\u00d7]\\s*\\d+\/.test(s);\n      const hasWeight = \/\\d+(\\.\\d+)?\\s*(kb|mb)\\b\/i.test(s);\n \n      const cleaned = s.replace(\/\\s+\/g, \"\");\n      const hexish = cleaned.match(\/[0-9A-Fa-f-]\/g) || [];\n      const ratio = hexish.length \/ cleaned.length;\n      const looksHash = cleaned.length &gt;= 8 &amp;&amp; ratio &gt; 0.9;\n \n      const shotName =\n        \/^(pixpin|snipaste|screenshot|screen_shot|img|wechat|wx_camera|photo|image|\u622a\u56fe|\u622a\u5c4f)[-_ ]*\/i.test(s);\n \n      return hasSize || hasWeight || looksHash || shotName;\n    };\n \n    \/\/ \u6e05\u6587\u5b57\u8282\u70b9\n    const walker = document.createTreeWalker(clone, NodeFilter.SHOW_TEXT, null);\n    const textNodes = [];\n    while (walker.nextNode()) textNodes.push(walker.currentNode);\n    textNodes.forEach(tn =&gt; { if (isMetaText(tn.textContent)) tn.remove(); });\n \n    \/\/ \u6e05\u5bb9\u5668\u5f0f\u5143\u6587\u672c\n    clone.querySelectorAll(\"p, div, span, li, code, em, strong\").forEach(el =&gt; {\n      const txt = el.textContent.trim();\n      if (isMetaText(txt) &amp;&amp; el.querySelectorAll(\"img\").length === 0) el.remove();\n    });\n \n    let html = clone.innerHTML.trim();\n    html = html.replace(\/&lt;p&gt;\\s*&lt;\\\/p&gt;\/gi, \"\");\n    html = html.replace(\/&lt;div&gt;\\s*&lt;\\\/div&gt;\/gi, \"\");\n \n    return {\n      title,\n      content: html,\n      author_name: author,\n      source_url: location.href.split(\"?\")[0],\n    };\n  }\n \n  \/* ---------------- 1.5) \u6b63\u6587\u7ed3\u6784\u8f7b\u4f18\u5316\uff08\u65e0\u76ee\u5f55\uff09 ---------------- *\/\n \n  function optimizeBodyHTML(html) {\n    if (!html) return html;\n \n    html = html\n      .replace(\/\\r\\n\/g, \"\\n\")\n      .replace(\/&lt;br\\s*\\\/?&gt;\\s*&lt;br\\s*\\\/?&gt;\/gi, \"\\n\\n\")\n      .replace(\/&lt;br\\s*\\\/?&gt;\/gi, \"\\n\");\n \n    const doc = new DOMParser().parseFromString(`&lt;div id=\"root\"&gt;${html}&lt;\/div&gt;`, \"text\/html\");\n    const root = doc.querySelector(\"#root\");\n \n    const textWalker = doc.createTreeWalker(root, NodeFilter.SHOW_TEXT, null);\n    const textNodes = [];\n    while (textWalker.nextNode()) textNodes.push(textWalker.currentNode);\n \n    textNodes.forEach(tn =&gt; {\n      const text = tn.textContent;\n      if (!text || !text.trim()) return;\n \n      const ptag = tn.parentElement?.tagName?.toLowerCase();\n      if ([\"code\",\"pre\",\"blockquote\",\"li\"].includes(ptag)) return;\n \n      const blocks = text.split(\/\\n{2,}\/).map(b =&gt; b.trim()).filter(Boolean);\n      if (blocks.length &lt;= 1) return;\n \n      const frag = doc.createDocumentFragment();\n \n      blocks.forEach(block =&gt; {\n        const lines = block.split(\"\\n\").map(l =&gt; l.trim()).filter(Boolean);\n \n        const isOL = lines.length &gt; 1 &amp;&amp; lines.every(l =&gt; \/^\\d+[\\.\\)]\\s+\/.test(l));\n        if (isOL) {\n          const ol = doc.createElement(\"ol\");\n          lines.forEach(l =&gt; {\n            const li = doc.createElement(\"li\");\n            li.textContent = l.replace(\/^\\d+[\\.\\)]\\s+\/, \"\");\n            ol.appendChild(li);\n          });\n          frag.appendChild(ol);\n          return;\n        }\n \n        const isUL = lines.length &gt; 1 &amp;&amp; lines.every(l =&gt; \/^[-\u2022*]\\s+\/.test(l));\n        if (isUL) {\n          const ul = doc.createElement(\"ul\");\n          lines.forEach(l =&gt; {\n            const li = doc.createElement(\"li\");\n            li.textContent = l.replace(\/^[-\u2022*]\\s+\/, \"\");\n            ul.appendChild(li);\n          });\n          frag.appendChild(ul);\n          return;\n        }\n \n        const p = doc.createElement(\"p\");\n        p.textContent = block;\n        frag.appendChild(p);\n      });\n \n      tn.parentNode.replaceChild(frag, tn);\n    });\n \n    \/\/ \u56fe\u7247\u5c45\u4e2d + \u81ea\u9002\u5e94\n    root.querySelectorAll(\"img\").forEach(img =&gt; {\n      const parent = img.parentElement;\n      if (parent &amp;&amp; parent.tagName.toLowerCase() === \"figure\") return;\n \n      const fig = doc.createElement(\"figure\");\n      fig.style.cssText = \"margin:16px auto;text-align:center;\";\n      img.style.cssText = (img.getAttribute(\"style\") || \"\") + \";max-width:100%;height:auto;border-radius:6px;\";\n \n      parent.insertBefore(fig, img);\n      fig.appendChild(img);\n    });\n \n    root.querySelectorAll(\"p\").forEach(p =&gt; {\n      p.style.cssText = (p.getAttribute(\"style\") || \"\") + \";margin:0 0 14px;line-height:1.8;font-size:16px;\";\n    });\n    root.querySelectorAll(\"ul,ol\").forEach(list =&gt; {\n      list.style.cssText = (list.getAttribute(\"style\") || \"\") + \";margin:0 0 14px 20px;line-height:1.8;font-size:16px;\";\n    });\n    root.querySelectorAll(\"li\").forEach(li =&gt; {\n      li.style.cssText = (li.getAttribute(\"style\") || \"\") + \";margin:4px 0;\";\n    });\n \n    \/\/ \u53bb\u6389\u7a7a\u5bb9\u5668\n    root.querySelectorAll(\"p,div,span\").forEach(el =&gt; {\n      if (!el.textContent.trim() &amp;&amp; el.querySelectorAll(\"img,video,pre,code,blockquote,ul,ol\").length === 0) {\n        el.remove();\n      }\n    });\n \n    return root.innerHTML.trim();\n  }\n \n  \/* ---------------- 2) \u62c9\u5206\u7c7b ---------------- *\/\n \n  async function fetchCategories() {\n    try {\n      const resp = await gmRequest({\n        method: \"GET\",\n        url: WP_CATEGORIES,\n        headers: { \"Content-Type\": \"application\/json\" }\n      });\n      if (resp.status &gt;= 200 &amp;&amp; resp.status &lt; 300) {\n        const arr = JSON.parse(resp.responseText || \"[]\");\n        return arr.map(c =&gt; ({ id: c.id, name: c.name }));\n      }\n    } catch (e) {\n      console.warn(\"\u62c9\u53d6\u5206\u7c7b\u5931\u8d25:\", e);\n    }\n    return [];\n  }\n \n  \/* ---------------- 3) \u56fe\u7247\u5165\u5e93\u76f8\u5173\uff08\u9650\u5e76\u53d1 + \u5927\u56fe\u8df3\u8fc7\uff09 ---------------- *\/\n \n  async function downloadImageAsArrayBuffer(url) {\n    const resp = await new Promise((resolve, reject) =&gt; {\n      GM_xmlhttpRequest({\n        method: \"GET\",\n        url,\n        responseType: \"arraybuffer\",\n        anonymous: true,\n        onload: r =&gt; resolve(r),\n        onerror: e =&gt; reject(new Error(\"\u56fe\u7247\u4e0b\u8f7d\u5931\u8d25\uff1a\" + toErrorMessage(e))),\n        ontimeout: () =&gt; reject(new Error(\"\u56fe\u7247\u4e0b\u8f7d\u8d85\u65f6\")),\n      });\n    });\n \n    if (resp.status &lt; 200 || resp.status &gt;= 300) {\n      throw new Error(`\u56fe\u7247\u4e0b\u8f7d\u5931\u8d25(${resp.status})`);\n    }\n    return resp;\n  }\n \n  async function uploadImageToMedia(url, nonce) {\n    const resp = await downloadImageAsArrayBuffer(url);\n    const arrayBuffer = resp.response;\n \n    const headers = resp.responseHeaders || \"\";\n    const m = headers.match(\/content-type:\\s*([^\\r\\n]+)\/i);\n    const contentType = m ? m[1].trim() : \"image\/jpeg\";\n \n    const urlObj = new URL(url);\n    let filename = urlObj.pathname.split(\"\/\").pop() || \"image\";\n    if (!\/\\.(png|jpe?g|gif|webp|svg)$\/i.test(filename)) {\n      if (\/png\/i.test(contentType)) filename += \".png\";\n      else if (\/webp\/i.test(contentType)) filename += \".webp\";\n      else if (\/gif\/i.test(contentType)) filename += \".gif\";\n      else if (\/svg\/i.test(contentType)) filename += \".svg\";\n      else filename += \".jpg\";\n    }\n \n    const uploadResp = await new Promise((resolve, reject) =&gt; {\n      GM_xmlhttpRequest({\n        method: \"POST\",\n        url: WP_MEDIA,\n        headers: {\n          \"Content-Type\": contentType,\n          \"Content-Disposition\": `attachment; filename=\"${filename}\"`,\n          \"X-WP-Nonce\": nonce,\n        },\n        data: arrayBuffer,\n        binary: true,\n        anonymous: false,\n        onload: r =&gt; resolve(r),\n        onerror: e =&gt; reject(new Error(\"\u56fe\u7247\u4e0a\u4f20\u5931\u8d25\uff1a\" + toErrorMessage(e))),\n        ontimeout: () =&gt; reject(new Error(\"\u56fe\u7247\u4e0a\u4f20\u8d85\u65f6\")),\n      });\n    });\n \n    if (uploadResp.status &lt; 200 || uploadResp.status &gt;= 300) {\n      throw new Error(`\u56fe\u7247\u4e0a\u4f20\u5931\u8d25(${uploadResp.status}): ${uploadResp.responseText}`);\n    }\n \n    const json = JSON.parse(uploadResp.responseText || \"{}\");\n    return json.source_url || \"\";\n  }\n \n  async function mapWithConcurrency(items, limit, mapper) {\n    const results = new Array(items.length);\n    let idx = 0;\n \n    async function worker() {\n      while (idx &lt; items.length) {\n        const current = idx++;\n        try {\n          results[current] = await mapper(items[current], current);\n        } catch (e) {\n          results[current] = { __error: e };\n        }\n      }\n    }\n \n    const workers = Array.from({ length: limit }, () =&gt; worker());\n    await Promise.all(workers);\n    return results;\n  }\n \n  async function downloadAndReplaceImages(post, nonce, log = null) {\n    const doc = new DOMParser().parseFromString(post.content, \"text\/html\");\n    const imgs = Array.from(doc.querySelectorAll(\"img\"));\n    if (!imgs.length) return post;\n \n    const wpHost = new URL(WP_BASE).host;\n    const base = post.source_url || location.href;\n    const cacheMap = {};\n \n    const CONCURRENCY = 3;\n    const MAX_SIZE_MB = 8;\n \n    const tasks = imgs.map(img =&gt; {\n      const src = img.getAttribute(\"src\");\n      if (!src) return null;\n \n      let abs;\n      try { abs = new URL(src, base).href; }\n      catch { return null; }\n \n      const host = new URL(abs).host;\n      if (host === wpHost) return null;\n \n      return { img, abs };\n    }).filter(Boolean);\n \n    if (log) log(`\u53d1\u73b0\u5916\u94fe\u56fe\u7247 ${tasks.length} \u5f20\uff0c\u5f00\u59cb\u5904\u7406\uff08\u5e76\u53d1=${CONCURRENCY}\uff09`);\n \n    await mapWithConcurrency(tasks, CONCURRENCY, async (t, i) =&gt; {\n      const { img, abs } = t;\n \n      if (cacheMap[abs]) {\n        img.setAttribute(\"src\", cacheMap[abs]);\n        if (log) log(`[#${i+1}] \u4f7f\u7528\u7f13\u5b58\uff1a${abs}`);\n        return;\n      }\n \n      try {\n        if (log) log(`[#${i+1}] \u4e0b\u8f7d\u56fe\u7247\uff1a${abs}`);\n        const resp = await downloadImageAsArrayBuffer(abs);\n \n        let sizeBytes = 0;\n        const h = resp.responseHeaders || \"\";\n        const m = h.match(\/content-length:\\s*(\\d+)\/i);\n        if (m) sizeBytes = parseInt(m[1], 10) || 0;\n        else sizeBytes = resp.response?.byteLength || 0;\n \n        const sizeMB = sizeBytes \/ (1024 * 1024);\n \n        if (sizeMB &gt; MAX_SIZE_MB) {\n          if (log) log(`[#${i+1}] \u56fe\u7247\u8fc7\u5927(${sizeMB.toFixed(1)}MB) \u8df3\u8fc7\u5165\u5e93`);\n          return;\n        }\n \n        if (log) log(`[#${i+1}] \u4e0a\u4f20\u5a92\u4f53\u5e93(${sizeMB.toFixed(1)}MB)`);\n        const newUrl = await uploadImageToMedia(abs, nonce);\n \n        if (newUrl) {\n          cacheMap[abs] = newUrl;\n          img.setAttribute(\"src\", newUrl);\n          if (log) log(`[#${i+1}] \u5165\u5e93\u6210\u529f \u2192 ${newUrl}`);\n        } else {\n          if (log) log(`[#${i+1}] \u5165\u5e93\u5931\u8d25\uff08\u7a7a\u8fd4\u56de\uff09`);\n        }\n      } catch (e) {\n        if (log) log(`[#${i+1}] \u5165\u5e93\u5f02\u5e38\uff1a${toErrorMessage(e)}\uff0c\u4fdd\u7559\u5916\u94fe`);\n      }\n    });\n \n    if (log) log(\"\u56fe\u7247\u5904\u7406\u5b8c\u6210\");\n    return { ...post, content: doc.body.innerHTML };\n  }\n \n  \/* ---------------- 4) \u4e24\u6b65\u53d1\u5e03\uff08\u9632\u8d85\u65f6\uff09 ---------------- *\/\n \n  async function updatePostContent(postId, content, nonce, log) {\n    const resp = await gmRequest({\n      method: \"POST\",\n      url: `${WP_POSTS}\/${postId}`,\n      headers: {\n        \"Content-Type\": \"application\/json\",\n        \"X-WP-Nonce\": nonce,\n      },\n      data: JSON.stringify({ content }),\n      timeout: 90000,\n    });\n \n    if (resp.status &gt;= 200 &amp;&amp; resp.status &lt; 300) {\n      if (log) log(\"\u4e8c\u6b21\u66f4\u65b0\u6b63\u6587\u6210\u529f\");\n      return JSON.parse(resp.responseText || \"{}\");\n    }\n    throw new Error(`\u4e8c\u6b21\u66f4\u65b0\u5931\u8d25(${resp.status}): ${resp.responseText}`);\n  }\n \n  async function updatePostStatus(postId, status, nonce, log) {\n    const resp = await gmRequest({\n      method: \"POST\",\n      url: `${WP_POSTS}\/${postId}`,\n      headers: {\n        \"Content-Type\": \"application\/json\",\n        \"X-WP-Nonce\": nonce,\n      },\n      data: JSON.stringify({ status }),\n      timeout: 60000,\n    });\n \n    if (resp.status &gt;= 200 &amp;&amp; resp.status &lt; 300) {\n      if (log) log(`\u72b6\u6001\u66f4\u65b0\u6210\u529f \u2192 ${status}`);\n      return JSON.parse(resp.responseText || \"{}\");\n    }\n    throw new Error(`\u72b6\u6001\u66f4\u65b0\u5931\u8d25(${resp.status}): ${resp.responseText}`);\n  }\n \n  async function sendPostToWordPress(post, { categoryId, status, nonce, log }) {\n    const now = new Date().toLocaleString(\"zh-CN\", { hour12: false });\n \n    \/\/ \u2705 intro\uff1aGutenberg \u6bb5\u843d\u5757\u5f00\u5934\uff0c\u540e\u53f0\u65e0\u9996\u884c\u7a7a\u6bb5\u843d\n    const intro =\n`&lt;!-- wp:paragraph --&gt;\n&lt;p style=\"\n  margin:0 0 10px 0;\n  padding:7px 10px;\n  background:#f6f7f9;\n  border-left:3px solid #94a3b8;\n  border-radius:6px;\n  font-size:13.5px;\n  color:#475569;\n  line-height:1.7;\n\"&gt;\n  \u672c\u6587\u4e3a\u8f6c\u8f7d\u5185\u5bb9\uff0c\u4fdd\u7559\u539f\u5e16\u89c2\u70b9\u4e0e\u7ed3\u6784\uff1b\u5982\u6709\u4fb5\u6743\u8bf7\u8054\u7cfb\u6211\u5904\u7406\u3002\n&lt;\/p&gt;\n&lt;!-- \/wp:paragraph --&gt;`;\n \n    \/\/ \u2705 footer\uff1adiv + span inline\uff0c\u4e3b\u9898\u4e0d\u4f1a\u4e71\n    const footer =\n`&lt;div style=\"margin-top:18px;\"&gt;\n  &lt;hr style=\"border:0;height:1px;background:#e2e8f0;margin:16px 0;\"&gt;\n \n  &lt;div style=\"\n    padding:12px 14px;\n    background:#f8fafc;\n    border:1px dashed #d0d7de;\n    border-radius:12px;\n    font-size:14px;\n    color:#334155;\n    line-height:1.8;\n  \"&gt;\n    &lt;div style=\"margin:0 0 8px 0;font-weight:700;color:#0f172a;font-size:15px;\"&gt;\n      \ud83d\udccc \u8f6c\u8f7d\u4fe1\u606f\n    &lt;\/div&gt;\n \n    &lt;div style=\"margin:0 0 6px 0;\"&gt;\n      &lt;span style=\"color:#64748b;display:inline;font-weight:600;\"&gt;\u6765\u6e90\uff1a&lt;\/span&gt;\n      &lt;a href=\"${post.source_url}\" target=\"_blank\" rel=\"nofollow noopener\"\n         style=\"display:inline;color:#2563eb;text-decoration:underline;word-break:break-all;\"&gt;\n        ${post.source_url}\n      &lt;\/a&gt;\n    &lt;\/div&gt;\n \n    ${post.author_name ? `\n    &lt;div style=\"margin:0 0 6px 0;\"&gt;\n      &lt;span style=\"color:#64748b;display:inline;font-weight:600;\"&gt;\u539f\u4f5c\u8005\uff1a&lt;\/span&gt;\n      &lt;span style=\"display:inline;font-weight:600;\"&gt;${escapeHtml(post.author_name)}&lt;\/span&gt;\n    &lt;\/div&gt;` : \"\"}\n \n    &lt;div style=\"margin:0;\"&gt;\n      &lt;span style=\"color:#64748b;display:inline;font-weight:600;\"&gt;\u8f6c\u8f7d\u65f6\u95f4\uff1a&lt;\/span&gt;\n      &lt;span style=\"display:inline;\"&gt;${now}&lt;\/span&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n&lt;\/div&gt;`;\n \n    let optimizedBody = optimizeBodyHTML(post.content).trim();\n \n    \/\/ \u2705 \u5f7b\u5e95\u6e05\u6389\u6b63\u6587\u5f00\u5934\u7a7a\u767d\/\u7a7a\u6bb5\u843d\/&amp;nbsp;\/br\n    optimizedBody = optimizedBody.replace(\n      \/^(\\s|&amp;nbsp;|&lt;br\\s*\\\/?&gt;|&lt;p&gt;\\s*(?:&amp;nbsp;|\\u00a0|&lt;br\\s*\\\/?&gt;|\\s)*&lt;\\\/p&gt;)+\/i,\n      \"\"\n    );\n \n    const finalContent = intro.trim() + optimizedBody + footer.trim();\n \n    \/\/ \u2705 \u7b2c\u4e00\u6b65\uff1a\u5360\u4f4d\u8349\u7a3f\uff08\u79d2\u8fd4\u56de\uff09\n    const firstPayload = {\n      title: post.title,\n      content: \"&lt;p&gt;\u8349\u7a3f\u5360\u4f4d\uff0c\u6b63\u5728\u5199\u5165\u6b63\u6587...&lt;\/p&gt;\",\n      status: \"draft\",\n      categories: categoryId &gt; 0 ? [categoryId] : [],\n    };\n \n    if (log) log(\"\u7b2c1\u6b65\uff1a\u521b\u5efa\u5360\u4f4d\u8349\u7a3f...\");\n    const r1 = await gmRequest({\n      method: \"POST\",\n      url: WP_POSTS,\n      headers: {\n        \"Content-Type\": \"application\/json\",\n        \"X-WP-Nonce\": nonce,\n      },\n      data: JSON.stringify(firstPayload),\n      timeout: 60000,\n    });\n \n    if (r1.status &lt; 200 || r1.status &gt;= 300) {\n      throw new Error(`\u521b\u5efa\u8349\u7a3f\u5931\u8d25(${r1.status}): ${r1.responseText}`);\n    }\n \n    const created = JSON.parse(r1.responseText || \"{}\");\n    const postId = created.id;\n    if (log) log(`\u8349\u7a3f\u521b\u5efa\u6210\u529f\uff0cID=${postId}`);\n \n    \/\/ \u2705 \u7b2c\u4e8c\u6b65\uff1a\u5199\u5165\u5b8c\u6574\u6b63\u6587\n    if (log) log(\"\u7b2c2\u6b65\uff1a\u5199\u5165\u5b8c\u6574\u6b63\u6587...\");\n    let updated = await updatePostContent(postId, finalContent, nonce, log);\n \n    \/\/ \u2705 \u7b2c\u4e09\u6b65\uff1a\u5207\u6362 publish\uff08\u53ef\u9009\uff09\n    if (status === \"publish\") {\n      if (log) log(\"\u7b2c3\u6b65\uff1a\u5207\u6362\u4e3a publish...\");\n      updated = await updatePostStatus(postId, \"publish\", nonce, log);\n    }\n \n    return updated;\n  }\n \n  \/* ---------------- 5) UI \u5f39\u7a97 + \u65e5\u5fd7\u6846 ---------------- *\/\n \n  function openRepostUI() {\n    let postData = null;\n    let categories = [];\n \n    const mask = document.createElement(\"div\");\n    mask.style.cssText = `\n      position:fixed; inset:0; background:rgba(0,0,0,.45);\n      z-index:999999; display:flex; align-items:center; justify-content:center;\n      font-family: system-ui, -apple-system, Segoe UI, Roboto, PingFang SC, sans-serif;\n    `;\n \n    const modal = document.createElement(\"div\");\n    modal.style.cssText = `\n      width:520px; max-width:90vw; background:#fff; border-radius:14px;\n      box-shadow:0 12px 40px rgba(0,0,0,.26); padding:18px 18px 14px;\n    `;\n \n    modal.innerHTML = `\n      &lt;div style=\"font-size:18px;font-weight:700;margin-bottom:6px;\"&gt;\n        \u8f6c\u8f7d\u5230 WordPress\uff08\u53ea\u4e3b\u697c\uff09\n      &lt;\/div&gt;\n      &lt;div id=\"dw-title\" style=\"font-size:13px;color:#666;margin-bottom:8px;max-height:48px;overflow:hidden;\"&gt;&lt;\/div&gt;\n \n      &lt;label style=\"display:block;font-size:14px;margin:6px 0 4px;\"&gt;\u9009\u62e9\u5206\u7c7b&lt;\/label&gt;\n      &lt;select id=\"dw-cat\" style=\"width:100%;padding:8px;border:1px solid #ddd;border-radius:8px;font-size:14px;\"&gt;\n        &lt;option value=\"0\"&gt;\u4e0d\u8bbe\u7f6e\u5206\u7c7b&lt;\/option&gt;\n      &lt;\/select&gt;\n \n      &lt;div style=\"display:flex;gap:12px;margin-top:10px;flex-wrap:wrap;\"&gt;\n        &lt;label style=\"display:flex;align-items:center;gap:6px;font-size:14px;\"&gt;\n          &lt;input id=\"dw-img\" type=\"checkbox\" ${DEFAULT_DOWNLOAD_IMAGES ? \"checked\" : \"\"} \/&gt;\n          \u56fe\u7247\u5165\u5e93\uff08\u4e0b\u8f7d\u5230\u5a92\u4f53\u5e93\uff09\n        &lt;\/label&gt;\n \n        &lt;label style=\"display:flex;align-items:center;gap:6px;font-size:14px;\"&gt;\n          &lt;input id=\"dw-pub\" type=\"checkbox\" ${DEFAULT_STATUS === \"publish\" ? \"checked\" : \"\"} \/&gt;\n          \u76f4\u63a5\u53d1\u5e03\uff08\u5426\u5219\u8349\u7a3f\uff09\n        &lt;\/label&gt;\n      &lt;\/div&gt;\n \n      &lt;div id=\"dw-status\" style=\"margin-top:8px;font-size:13px;color:#888;\"&gt;&lt;\/div&gt;\n \n      &lt;div style=\"margin-top:10px;\"&gt;\n        &lt;div style=\"font-size:13px;color:#666;margin-bottom:6px;\"&gt;\u8fd0\u884c\u65e5\u5fd7&lt;\/div&gt;\n        &lt;div id=\"dw-log\" style=\"\n          height:140px;\n          overflow:auto;\n          background:#0b1020;\n          color:#d1d5db;\n          font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;\n          font-size:12px;\n          line-height:1.6;\n          padding:8px 10px;\n          border-radius:8px;\n          border:1px solid #111827;\n          white-space:pre-wrap;\n        \"&gt;&lt;\/div&gt;\n      &lt;\/div&gt;\n \n      &lt;div style=\"display:flex;justify-content:flex-end;gap:8px;margin-top:14px;\"&gt;\n        &lt;button id=\"dw-cancel\" style=\"padding:8px 12px;border-radius:8px;border:1px solid #ddd;background:#fff;cursor:pointer;\"&gt;\n          \u53d6\u6d88\n        &lt;\/button&gt;\n        &lt;button id=\"dw-send\" style=\"padding:8px 14px;border-radius:8px;border:none;background:#111;color:#fff;cursor:pointer;\"&gt;\n          \u53d1\u9001\n        &lt;\/button&gt;\n      &lt;\/div&gt;\n    `;\n \n    mask.appendChild(modal);\n    document.body.appendChild(mask);\n \n    const q = (sel) =&gt; modal.querySelector(sel);\n    const statusEl = q(\"#dw-status\");\n    const sendBtn = q(\"#dw-send\");\n    const logEl = q(\"#dw-log\");\n \n    function log(msg) {\n      const t = new Date().toLocaleTimeString(\"zh-CN\", { hour12:false });\n      logEl.textContent += `[${t}] ${msg}\\n`;\n      logEl.scrollTop = logEl.scrollHeight;\n    }\n \n    q(\"#dw-cancel\").onclick = () =&gt; mask.remove();\n \n    (async () =&gt; {\n      try {\n        log(\"\u5f00\u59cb\u63d0\u53d6\u4e3b\u697c\u5185\u5bb9...\");\n        postData = extractLinuxDoOP();\n        q(\"#dw-title\").textContent = \"\u6807\u9898\uff1a\" + postData.title;\n        log(\"\u63d0\u53d6\u6210\u529f\");\n \n        log(\"\u62c9\u53d6 WordPress \u5206\u7c7b...\");\n        categories = await fetchCategories();\n        const catSel = q(\"#dw-cat\");\n        categories.forEach((c) =&gt; {\n          const opt = document.createElement(\"option\");\n          opt.value = c.id;\n          opt.textContent = c.name;\n          catSel.appendChild(opt);\n        });\n        log(`\u5206\u7c7b\u6570\u91cf\uff1a${categories.length}`);\n \n        statusEl.textContent = \"\u51c6\u5907\u5c31\u7eea\uff0c\u9009\u62e9\u5206\u7c7b\/\u9009\u9879\u540e\u70b9\u51fb\u53d1\u9001\u3002\";\n        log(\"\u51c6\u5907\u5c31\u7eea\");\n      } catch (e) {\n        const em = toErrorMessage(e);\n        statusEl.textContent = \"\u274c \u63d0\u53d6\u5e16\u5b50\u5931\u8d25\uff1a\" + em;\n        log(\"\u63d0\u53d6\u5e16\u5b50\u5931\u8d25\uff1a\" + em);\n        sendBtn.disabled = true;\n      }\n    })();\n \n    sendBtn.onclick = async () =&gt; {\n      try {\n        sendBtn.disabled = true;\n \n        const categoryId = parseInt(q(\"#dw-cat\").value, 10) || 0;\n        const downloadImages = q(\"#dw-img\").checked;\n        const status = q(\"#dw-pub\").checked ? \"publish\" : \"draft\";\n \n        statusEl.textContent = \"\u68c0\u67e5 WordPress \u767b\u5f55\u6001...\";\n        log(\"\u68c0\u67e5 WordPress \u767b\u5f55\u6001...\");\n        const nonce = await getRestNonce();\n        log(\"Nonce \u83b7\u53d6\u6210\u529f\");\n \n        if (downloadImages) {\n          statusEl.textContent = \"\u6b63\u5728\u4e0b\u8f7d\u5e76\u5c06\u56fe\u7247\u4e0a\u4f20\u5230\u5a92\u4f53\u5e93...\";\n          log(\"\u5f00\u59cb\u56fe\u7247\u5165\u5e93\u4e0e\u66ff\u6362\u5916\u94fe...\");\n          postData = await downloadAndReplaceImages(postData, nonce, log);\n          log(\"\u56fe\u7247\u5165\u5e93\u6d41\u7a0b\u7ed3\u675f\");\n        } else {\n          log(\"\u56fe\u7247\u5165\u5e93\u672a\u5f00\u542f\uff0c\u8df3\u8fc7\");\n        }\n \n        statusEl.textContent = \"\u6b63\u5728\u53d1\u5e03\u5230 WordPress...\";\n        log(`\u5f00\u59cb\u53d1\u5e03\uff08status=${status}, categoryId=${categoryId || 0})`);\n \n        const res = await sendPostToWordPress(postData, { categoryId, status, nonce, log });\n \n        const postId = res.id || res.ID;\n        const link = res.link || (res.guid &amp;&amp; res.guid.rendered) || \"#\";\n \n        statusEl.innerHTML = `\u2705 \u53d1\u5e03\u6210\u529f\uff01\u6587\u7ae0ID: ${postId}&lt;br&gt;&lt;a href=\"${link}\" target=\"_blank\"&gt;\u6253\u5f00\u6587\u7ae0&lt;\/a&gt;`;\n        log(`\u53d1\u5e03\u6210\u529f\uff1aID=${postId}`);\n        log(`\u6587\u7ae0\u94fe\u63a5\uff1a${link}`);\n      } catch (e) {\n        const em = toErrorMessage(e);\n        statusEl.textContent = \"\u274c \u53d1\u5e03\u5931\u8d25\uff1a\" + em;\n        log(\"\u53d1\u5e03\u5931\u8d25\uff1a\" + em);\n      } finally {\n        sendBtn.disabled = false;\n      }\n    };\n  }\n \n  \/* ---------------- 6) \u53f3\u4e0b\u89d2\u6309\u94ae ---------------- *\/\n \n  function initButton() {\n    const btn = document.createElement(\"button\");\n    btn.textContent = \"\u8f6c\u8f7d\u5230 WP\";\n    btn.style.cssText = `\n      position:fixed; right:20px; bottom:20px; z-index:99999;\n      padding:8px 14px; border:none; border-radius:9px;\n      background:#111; color:#fff; cursor:pointer; font-size:14px;\n      box-shadow:0 6px 20px rgba(0,0,0,.25);\n    `;\n    btn.addEventListener(\"click\", openRepostUI);\n    document.body.appendChild(btn);\n  }\n \n  initButton();\n})();\n\n\n<\/code><\/pre>\n<p dir=\"auto\" style=\"margin: 0px 0px 14px; line-height: 1.8; font-size: 16px;\">\u6211\u81ea\u5df1\u7684\u535a\u5ba2\u662f <strong>[<a href=\"https:\/\/blog.qinnian.xyz\" rel=\"noopener nofollow ugc\" data-clicks=\"2\" aria-label=\"https:\/\/blog.qinnian.xyz \u94fe\u63a5\u5df2\u70b9\u51fb 2 \u6b21\">https:\/\/blog.qinnian.xyz<\/a><\/strong><p style=\"margin: 0px 0px 14px; line-height: 1.8; font-size: 16px;\">\uff0c\u5e73\u65f6\u4f1a\u628a\u770b\u5230\u7684\u597d\u5185\u5bb9\u505a\u6574\u7406\/\u7b14\u8bb0\uff0c\u4e5f\u4f1a\u540c\u6b65\u4e00\u4e9b\u5de5\u5177\u548c\u6298\u817e\u8bb0\u5f55\u3002]<\/p><p style=\"margin: 0px 0px 14px; line-height: 1.8; font-size: 16px;\">\u5982\u679c\u6709\u4f6c\u53cb\u4e5f\u5728\u5199\u535a\u5ba2\u3001\u613f\u610f\u4e92\u76f8\u4ea4\u6d41\u7684\u8bdd\uff0c\u6b22\u8fce\u6765\u901b\u901b\uff5e<\/p><strong>\u60f3\u4e92\u6302\u53cb\u60c5\u94fe\u63a5\u7684\u670b\u53cb\u76f4\u63a5\u56de\u5e16\/\u79c1\u4fe1\u6211\u7ad9\u70b9\u5730\u5740<\/strong><\/p><div style=\"margin-top:18px;\">\n  <hr style=\"border:0;height:1px;background:#e2e8f0;margin:16px 0;\">\n\n  <div style=\"\n    padding:12px 14px;\n    background:#f8fafc;\n    border:1px dashed #d0d7de;\n    border-radius:12px;\n    font-size:14px;\n    color:#334155;\n    line-height:1.8;\n  \">\n    <div style=\"margin:0 0 8px 0;font-weight:700;color:#0f172a;font-size:15px;\">\n      \ud83d\udccc \u8f6c\u8f7d\u4fe1\u606f\n    <\/div>\n\n    <div style=\"margin:0 0 6px 0;\">\n      <span style=\"color:#64748b;display:inline;font-weight:600;\">\u6765\u6e90\uff1a<\/span>\n      <a href=\"https:\/\/linux.do\/t\/topic\/1293707\" target=\"_blank\" rel=\"nofollow noopener\"\n         style=\"display:inline;color:#2563eb;text-decoration:underline;word-break:break-all;\">\n        https:\/\/linux.do\/t\/topic\/1293707\n      <\/a>\n    <\/div>\n\n    \n    <div style=\"margin:0 0 6px 0;\">\n      <span style=\"color:#64748b;display:inline;font-weight:600;\">\u539f\u4f5c\u8005\uff1a<\/span>\n      <span style=\"display:inline;font-weight:600;\">qinnian<\/span>\n    <\/div>\n\n    <div style=\"margin:0;\">\n      <span style=\"color:#64748b;display:inline;font-weight:600;\">\u8f6c\u8f7d\u65f6\u95f4\uff1a<\/span>\n      <span style=\"display:inline;\">2025\/12\/10 16:18:19<\/span>\n    <\/div>\n  <\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>\u672c\u6587\u4e3a\u8f6c\u8f7d\u5185\u5bb9\uff0c\u4fdd\u7559\u539f\u5e16\u89c2\u70b9\u4e0e\u7ed3\u6784\uff1b\u5982\u6709\u4fb5\u6743\u8bf7\u8054\u7cfb\u6211\u5904\u7406\u3002 \u6700\u8fd1\u901b linux.do \u7ecf\u5e38\u770b\u5230\u597d\u5e16\uff0c\u60f3\u987a\u624b\u4fdd\u5b58 &hellip; <a href=\"https:\/\/blog.jj.mr\/index.php\/2025\/12\/10\/%e3%80%90%e8%bd%ac%e8%bd%bd%e3%80%91%e5%88%86%e4%ba%ab%e4%b8%80%e4%b8%aa%e8%87%aa%e7%94%a8%e5%b0%8f%e8%84%9a%e6%9c%ac%ef%bc%9alinux-do-%e4%b8%bb%e6%a5%bc%e4%b8%80%e9%94%ae%e6%94%b6%e8%97%8f%e5%88%b0-w\/\" class=\"more-link\">\u7ee7\u7eed\u9605\u8bfb<span class=\"screen-reader-text\">\u3010\u8f6c\u8f7d\u3011\u5206\u4eab\u4e00\u4e2a\u81ea\u7528\u5c0f\u811a\u672c\uff1alinux.do \u4e3b\u697c\u4e00\u952e\u6536\u85cf\u5230 WordPress<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-10","post","type-post","status-publish","format-standard","hentry","category-l"],"_links":{"self":[{"href":"https:\/\/blog.jj.mr\/index.php\/wp-json\/wp\/v2\/posts\/10","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.jj.mr\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.jj.mr\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jj.mr\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jj.mr\/index.php\/wp-json\/wp\/v2\/comments?post=10"}],"version-history":[{"count":2,"href":"https:\/\/blog.jj.mr\/index.php\/wp-json\/wp\/v2\/posts\/10\/revisions"}],"predecessor-version":[{"id":232,"href":"https:\/\/blog.jj.mr\/index.php\/wp-json\/wp\/v2\/posts\/10\/revisions\/232"}],"wp:attachment":[{"href":"https:\/\/blog.jj.mr\/index.php\/wp-json\/wp\/v2\/media?parent=10"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jj.mr\/index.php\/wp-json\/wp\/v2\/categories?post=10"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jj.mr\/index.php\/wp-json\/wp\/v2\/tags?post=10"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}