2025年10月18日星期六

页面增强任务脚本

1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/Bg6shY若失效,可用地址

1.购买服务器

阿里云:

服务器购买地址

https://t.aliyun.com/U/Bg6shY

若失效,可用地址

https://www.aliyun.com/daily-act/ecs/activity_selection?source=5176.29345612&userCode=49hts92d

腾讯云:

https://curl.qcloud.com/wJpWmSfU

若失效,可用地址

https://cloud.tencent.com/act/cps/redirect?redirect=2446&cps_key=ad201ee2ef3b771157f72ee5464b1fea&from=console

华为云

https://activity.huaweicloud.com/cps.html?fromacct=64b5cf7cc11b4840bb4ed2ea0b2f4468&utm_source=V1g3MDY4NTY=&utm_medium=cps&utm_campaign=201905

2.部署教程

2024年最新青龙面板跑脚本教程(一)持续更新中

3.代码如下

(function () {  'use strict';
  var __defProp = Object.defineProperty;  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerabletrueconfigurabletruewritabletrue, value }) : obj[key] = value;  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);  function handleError(error, fallback) {    console.error("Booth Helper Error:", error);    if (fallback) {      try {        fallback();      } catch (e) {        console.error("Fallback handler failed:", e);      }    }  }  class Simulate {    /**     * 模拟用户输入文本     * @param element 目标输入元素     * @param text 要输入的文本     */    static input(element, text) {      var _a;      const nativeInputValueSetter = (_a = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype"value")) == null ? void 0 : _a.set;      if (nativeInputValueSetter) {        nativeInputValueSetter.call(element, text);      }      const ev2 = new Event("input", { bubblestrue });      element.dispatchEvent(ev2);    }    /**     * 模拟键盘按下事件     * @param element 目标元素     * @param keyCode 键码     */    static keyDown(element, keyCode) {      const keyboardEvent = new KeyboardEvent("keydown", {        bubblestrue,        cancelabletrue,        key"Enter",        code"Enter",        keyCode,        which: keyCode,        shiftKeyfalse,        ctrlKeyfalse,        metaKeyfalse      });      element.dispatchEvent(keyboardEvent);    }    /**     * 模拟按下回车键     * @param element 目标元素     */    static pressEnter(element) {      this.keyDown(element, 13);    }  }  const Config = {    throttleDelay100,    animationDelay1e3  };  class Utils {    // 优化的节流函数,使用Map缓存    static throttle(func, limit) {      const key = func.toString();      if (!this.throttleCache.has(key)) {        let inThrottle;        const throttled = function(...args) {          if (!inThrottle) {            func.apply(this, args);            inThrottle = true;            setTimeout(() => inThrottle = false, limit);          }        };        this.throttleCache.set(key, throttled);      }      return this.throttleCache.get(key);    }    // 等待指定时间    static sleep(ms) {      return new Promise((resolve) => setTimeout(resolve, ms));    }    // 等待DOM加载完成    static async waitForDOMReady() {      if (document.readyState === "loading") {        await new Promise((resolve) => document.addEventListener("DOMContentLoaded", resolve));      }    }    // 优化的按钮状态更新    static updateButtonState(button, success = true, originalHtml) {      if (!button) return;      const newHtml = success ? '<i class="icon-check"></i><span class="cmd-label">已完成</span>' : originalHtml;      button.innerHTML = newHtml;      button.classList.toggle("calm", !success);      button.classList.toggle("primary", success);      if (success) {        setTimeout(() => {          button.innerHTML = originalHtml;          button.classList.add("calm");          button.classList.remove("primary");        }, Config.animationDelay);      }    }  }  __publicField(Utils"throttleCache"/* @__PURE__ */ new Map());  class Feature {    constructor(context) {      __publicField(this"context");      __publicField(this"path");      this.context = context;      this.path = window.location.pathname;    }    /**     * 判断当前页面是否应该执行此功能     */    shouldExecute() {      return false;    }    /**     * 执行页面功能     */    async execute() {    }    /**     * 清理资源     */    cleanup() {    }  }  class ItemEditFeature extends Feature {    shouldExecute() {      return /^\/items\/\d+\/edit(_pre)?$/.test(this.path);    }    async execute() {      super.execute();      this.addNumbers();      this.addTagButtons();    }    // 变体序号功能    addNumbers() {      const allUlElements = document.querySelectorAll("ul.grid.gap-16");      if (allUlElements.length === 0) {        const observer = new MutationObserver((_, obs) => {          if (document.querySelectorAll("ul.grid.gap-16").length > 0) {            obs.disconnect();            this.addNumbers();          }        });        observer.observe(document.body, {          childListtrue,          subtreetrue        });        this.context.observers.set("variation-numbers-wait", observer);        return;      }      allUlElements.forEach((variationList) => {        const hasVariationItems = variationList.querySelector("li .variation-box-head") !== null;        if (!hasVariationItems) {          return;        }        const children = Array.from(variationList.children).filter((child) => child.tagName.toLowerCase() === "li");        children.forEach((li, index) => {          const existingNumberSpan = li.querySelector(".variation-number");          if (existingNumberSpan) {            existingNumberSpan.remove();          }          const titleContainer = li.querySelector(".variation-box-head .flex.items-center.gap-4");          if (!titleContainer) {            return;          }          const numberSpan = document.createElement("span");          numberSpan.className = "variation-number typography-14 inline-block font-semibold";          numberSpan.style.cssText = "margin-right: 8px; color: #666;";          numberSpan.textContent = `#${index + 1}`;          titleContainer.insertBefore(numberSpan, titleContainer.firstChild);        });      });      allUlElements.forEach((ul) => {        if (ul.querySelector("li .variation-box-head")) {          const observer = new MutationObserver(() => {            this.processUlNumbers(ul);          });          observer.observe(ul, {            childListtrue,            // 监听子元素的添加和删除            subtreefalse            // 不监听深层子元素的变化          });          const observerId = `ul-${Date.now()}`;          this.context.observers.set(observerId, observer);        }      });      const bodyObserver = new MutationObserver((mutations) => {        let newUlAdded = false;        for (const mutation of mutations) {          for (const node of Array.from(mutation.addedNodes)) {            if (node instanceof HTMLElement) {              if (node.tagName === "UL" && node.classList.contains("grid") && node.classList.contains("gap-16") || node.querySelector("ul.grid.gap-16")) {                newUlAdded = true;                break;              }            }          }          if (newUlAdded) break;        }        if (newUlAdded) {          Array.from(this.context.observers.entries()).filter(([key]) => key.startsWith("ul-")).forEach(([key, observer]) => {            if (observer instanceof MutationObserver) {              observer.disconnect();              this.context.observers.delete(key);            }          });          this.addNumbers();        }      });      bodyObserver.observe(document.body, {        childListtrue,        subtreetrue      });      this.context.observers.set("body-observer", bodyObserver);    }    /**     * 处理单个UL元素内的序号     * @param ul 要处理的UL元素     */    processUlNumbers(ul) {      const children = Array.from(ul.children).filter((child) => child.tagName.toLowerCase() === "li");      children.forEach((li, index) => {        const existingNumberSpan = li.querySelector(".variation-number");        if (existingNumberSpan) {          existingNumberSpan.remove();        }        const titleContainer = li.querySelector(".variation-box-head .flex.items-center.gap-4");        if (!titleContainer) {          return;        }        const numberSpan = document.createElement("span");        numberSpan.className = "variation-number typography-14 inline-block font-semibold";        numberSpan.style.cssText = "margin-right: 8px; color: #666;";        numberSpan.textContent = `#${index + 1}`;        titleContainer.insertBefore(numberSpan, titleContainer.firstChild);      });    }    // 标签功能    addTagButtons() {      const observer = new MutationObserver((_, obs) => {        const inputContainer = document.querySelector("#item_tag .item-search-input__container");        if (inputContainer) {          const buttonContainer = document.createElement("div");          buttonContainer.className = "flex gap-2";          buttonContainer.style.alignItems = "center";          buttonContainer.style.position = "absolute";          buttonContainer.style.right = "8px";          buttonContainer.style.top = "50%";          buttonContainer.style.transform = "translateY(-50%)";          const copyBtn = document.createElement("a");          copyBtn.className = "btn calm small";          copyBtn.innerHTML = "复制标签";          copyBtn.onclick = () => this.copyTags();          const pasteBtn = document.createElement("a");          pasteBtn.className = "btn calm small";          pasteBtn.innerHTML = "粘贴标签";          pasteBtn.onclick = () => this.pasteTags();          const clearBtn = document.createElement("a");          clearBtn.className = "btn calm small";          clearBtn.innerHTML = "清空标签";          clearBtn.onclick = () => this.clearTags();          buttonContainer.appendChild(copyBtn);          buttonContainer.appendChild(pasteBtn);          buttonContainer.appendChild(clearBtn);          inputContainer.appendChild(buttonContainer);          obs.disconnect();        }      });      observer.observe(document.body, {        childListtrue,        subtreetrue      });      this.context.observers.set("tag-buttons", observer);    }    copyTags() {      try {        const tags = Array.from(document.querySelectorAll("#item_tag .bg-secondary500 .font-bold")).map((tag) => {          var _a;          return (_a = tag.textContent) == null ? void 0 : _a.trim();        }).filter(Boolean);        if (tags.length === 0) {          alert("没有找到标签");          return;        }        navigator.clipboard.writeText(JSON.stringify(tags)).then(() => {          const copyBtn = document.querySelector("#item_tag .btn:first-child");          if (copyBtn instanceof HTMLElement) {            Utils.updateButtonState(copyBtn, true, copyBtn.innerHTML);          }        });      } catch (error) {        handleError(error);      }    }    createProgressTip(container) {      const tipContainer = document.createElement("div");      tipContainer.style.cssText = "margin-bottom: 12px; background: #f5f7fa; border-radius: 4px; padding: 12px; position: relative;";      const textElement = document.createElement("div");      textElement.style.cssText = "color: #666; font-size: 14px; margin-bottom: 8px;";      const progressBarContainer = document.createElement("div");      progressBarContainer.style.cssText = "background: #e4e7ed; height: 6px; border-radius: 3px; overflow: hidden;";      const progressBar = document.createElement("div");      progressBar.style.cssText = `            width: 0%;            height: 100%;            background: #409EFF;            transition: width 0.3s ease;            border-radius: 3px;        `;      progressBarContainer.appendChild(progressBar);      tipContainer.appendChild(textElement);      tipContainer.appendChild(progressBarContainer);      const inputContainer = container.querySelector(".item-search-input__container");      if (inputContainer == null ? void 0 : inputContainer.parentElement) {        inputContainer.parentElement.insertBefore(tipContainer, inputContainer);      } else {        container.insertBefore(tipContainer, container.firstChild);      }      return {        container: tipContainer,        progressBar,        textElement,        updateProgress(current, total, message) => {          const percentage = current / total * 100;          progressBar.style.width = `${percentage}%`;          textElement.textContent = message || `处理中... (${current}/${total})`;        },        complete(message) => {          progressBar.style.width = "100%";          progressBar.style.background = "#67C23A";          textElement.textContent = message;          setTimeout(() => tipContainer.remove(), 2e3);        },        remove() => tipContainer.remove()      };    }    async pasteTags() {      try {        const text = await navigator.clipboard.readText();        const newTags = JSON.parse(text);        if (!Array.isArray(newTags) || newTags.length === 0) {          throw new Error("无效的标签数据");        }        const input = document.querySelector(".js-item-tags-array");        if (!input) throw new Error("找不到标签输入框");        const container = document.querySelector("#item_tag");        if (!container) throw new Error("找不到标签容器");        const existingTags = Array.from(document.querySelectorAll("#item_tag .bg-secondary500 .font-bold")).map((tag) => {          var _a;          return (_a = tag.textContent) == null ? void 0 : _a.trim();        }).filter(Boolean);        const tagsToAdd = newTags.filter((tag) => !existingTags.includes(tag));        if (tagsToAdd.length === 0) {          alert("所有标签都已存在,无需添加");          return;        }        const progress = this.createProgressTip(container);        try {          for (let i = 0; i < tagsToAdd.length; i++) {            progress.updateProgress(i + 1, tagsToAdd.length);            input.focus();            Simulate.input(input, tagsToAdd[i]);            await Utils.sleep(10);            Simulate.pressEnter(input);            await Utils.sleep(10);          }          progress.complete(`处理完成!已添加 ${tagsToAdd.length} 个新标签,跳过 ${newTags.length - tagsToAdd.length} 个已存在的标签。`);          const pasteBtn = document.querySelector("#item_tag .btn:nth-child(2)");          if (pasteBtn instanceof HTMLElement) {            Utils.updateButtonState(pasteBtn, true, pasteBtn.innerHTML);          }        } catch (error) {          progress.remove();          throw error;        }      } catch (error) {        handleError(error, () => {          alert("粘贴标签失败:" + (error instanceof Error ? error.message : String(error)));        });      }    }    async clearTags() {      try {        if (!confirm("确定要清空所有标签吗?")) return;        const container = document.querySelector("#item_tag");        if (!container) throw new Error("找不到标签容器");        const deleteButtons = Array.from(document.querySelectorAll('#item_tag .bg-secondary500 a.flex pixiv-icon[name="32/BoothClose"]'));        if (deleteButtons.length === 0) {          alert("没有找到需要清空的标签");          return;        }        const progress = this.createProgressTip(container);        try {          for (let i = deleteButtons.length - 1; i >= 0; i--) {            progress.updateProgress(deleteButtons.length - i, deleteButtons.length);            const button = deleteButtons[i];            const clickableAnchor = button.closest("a");            if (clickableAnchor) {              clickableAnchor.click();              await Utils.sleep(1);            }          }          progress.complete(`处理完成!已清空 ${deleteButtons.length} 个标签。`);          const clearBtn = document.querySelector("#item_tag .btn:nth-child(3)");          if (clearBtn instanceof HTMLElement) {            Utils.updateButtonState(clearBtn, true, clearBtn.innerHTML);          }        } catch (error) {          progress.remove();          throw error;        }      } catch (error) {        handleError(error);      }    }    cleanup() {      ["variation-numbers-wait""body-observer""tag-buttons"].forEach((observerName) => {        const observer = this.context.observers.get(observerName);        if (observer instanceof MutationObserver) {          observer.disconnect();          this.context.observers.delete(observerName);        }      });      const buttons = document.querySelectorAll(".btn.calm.small");      buttons.forEach((button) => {        if (["复制标签""粘贴标签""清空标签"].includes(button.innerHTML)) {          button.remove();        }      });    }  }  class ItemManageFeature extends Feature {    constructor(context) {      super(context);      __publicField(this"itemObserver");      this.itemObserver = new IntersectionObserver(        (entries) => {          entries.forEach((entry) => {            if (entry.isIntersecting) {              const item = entry.target;              this.processItem(item);              this.itemObserver.unobserve(item);            }          });        },        { threshold0.1 }        // 当元素10%可见时触发      );    }    shouldExecute() {      return this.path === "/items" || this.path === "/items/";    }    async execute() {      await super.execute();      this.setupItemsObserver();    }    // 处理单个商品卡片    processItem(item) {      try {        this.addButtonToItem(item);        this.addVariationNumbersToItem(item);        this.addTotalStats(item);        item.setAttribute("data-processed""true");      } catch (error) {        handleError(error);      }    }    // 为单个商品添加变体序号    addVariationNumbersToItem(item) {      const variationList = item.querySelector(".dashboard-items-variation");      if (!variationList) return;      const variations = variationList.querySelectorAll(".row");      variations.forEach((variation, index) => {        const labelArea = variation.querySelector(".dashboard-items-variation-label");        if (!labelArea) return;        let numberSpan = variation.querySelector(".variation-number");        if (!numberSpan) {          numberSpan = document.createElement("span");          numberSpan.className = "variation-number";          numberSpan.style.cssText = "margin-right: 8px; color: #666;";          labelArea.insertBefore(numberSpan, labelArea.firstChild);        }        numberSpan.textContent = `#${index + 1}`;      });      const observer = new MutationObserver(Utils.throttle((_mutations, _observer) => {        const needsUpdate = Array.from(variations).some((variation, index) => {          const numberSpan = variation.querySelector(".variation-number");          return !numberSpan || numberSpan.textContent !== `#${index + 1}`;        });        if (needsUpdate) {          requestAnimationFrame(() => this.addVariationNumbersToItem(item));        }      }, Config.throttleDelay));      observer.observe(variationList, {        childListtrue,        subtreefalse      });      item.variationObserver = observer;    }    setupItemsObserver() {      const pageObserver = new MutationObserver(Utils.throttle((_mutations, _observer) => {        _mutations.forEach((mutation) => {          mutation.addedNodes.forEach((node) => {            if (node.nodeType === 1) {              const items = node.matches(".item-wrapper") ? [node] : Array.from(node.querySelectorAll(".item-wrapper"));              items.forEach((item) => {                if (!item.hasAttribute("data-processed")) {                  this.itemObserver.observe(item);                }              });            }          });        });      }, Config.throttleDelay));      pageObserver.observe(document.body, {        childListtrue,        subtreetrue      });      this.context.observers.set("page", pageObserver);      document.querySelectorAll(".item-wrapper").forEach((item) => {        if (!item.hasAttribute("data-processed")) {          this.itemObserver.observe(item);        }      });    }    addButtonToItem(item) {      if (item.querySelector(".tag-copy-btn") || item.querySelector(".item-delete-btn")) return;      const itemId = item.getAttribute("data-id");      if (!itemId) return;      const deleteBtn = document.createElement("a");      deleteBtn.className = "btn danger small item-delete-btn";      deleteBtn.style.cssText = "position: absolute; top: 20px; right: 20px; z-index: 10;";      deleteBtn.innerHTML = "删除";      deleteBtn.onclick = async (e) => {        var _a, _b, _c;        e.preventDefault();        if (!confirm("确定要删除这个商品吗?此操作不可恢复。")) return;        const itemName = ((_b = (_a = item.querySelector(".nav")) == null ? void 0 : _a.textContent) == null ? void 0 : _b.trim()) || "未知商品";        if (!confirm(`再次确认删除商品:${itemName}ID: ${itemId}`)) return;        try {          const csrfToken = (_c = document.querySelector('meta[name="csrf-token"]')) == null ? void 0 : _c.getAttribute("content");          if (!csrfToken) {            throw new Error("无法获取CSRF token");          }          const response = await fetch(`https://manage.booth.pm/items/${itemId}`, {            method"DELETE",            headers: {              "accept""application/json, text/javascript, */*; q=0.01",              "accept-language""zh-CN,zh;q=0.9,en;q=0.8",              "x-requested-with""XMLHttpRequest",              "x-csrf-token": csrfToken            },            referrerwindow.location.href,            referrerPolicy"strict-origin-when-cross-origin",            mode"cors",            credentials"include"          });          if (response.ok) {            item.remove();          } else {            const errorText = await response.text();            console.log("删除失败响应:", errorText);            throw new Error(`删除失败: ${response.status}${errorText}`);          }        } catch (error) {          handleError(error, () => {            alert("删除商品失败,请刷新页面重试");          });        }      };      if (getComputedStyle(item).position === "static") {        item.style.position = "relative";      }      item.appendChild(deleteBtn);      const tagList = item.querySelector(".dashboard-items-tags");      const footerActions = item.querySelector(".dashboard-item-footer-actions");      if (tagList && footerActions) {        const copyBtn = document.createElement("a");        copyBtn.className = "btn calm small tag-copy-btn mr-8";        copyBtn.innerHTML = "复制标签";        copyBtn.onclick = (e) => {          e.preventDefault();          this.copyItemManageTags(tagList);        };        footerActions.insertBefore(copyBtn, footerActions.firstChild);      }    }    copyItemManageTags(tagList) {      try {        const tags = Array.from(tagList.querySelectorAll(".tag-text")).map((tag) => tag.textContent).filter(Boolean);        if (tags.length === 0) {          alert("没有找到标签");          return;        }        navigator.clipboard.writeText(JSON.stringify(tags)).then(() => {          var _a;          const copyBtn = (_a = tagList.closest(".item-wrapper")) == null ? void 0 : _a.querySelector(".tag-copy-btn");          if (copyBtn instanceof HTMLElement) {            Utils.updateButtonState(copyBtn, true, copyBtn.innerHTML);          }        });      } catch (error) {        handleError(error);      }    }    // 新增方法:添加总销量和总收益统计    addTotalStats(item) {      const variations = item.querySelectorAll(".dashboard-items-variation .row");      if (!variations.lengthreturn;      variations.forEach((variation) => {        const labelArea = variation.querySelector(".dashboard-items-variation-label");        if (!labelArea || labelArea.querySelector(".variation-checkbox")) return;        const checkbox = document.createElement("input");        checkbox.type = "checkbox";        checkbox.className = "variation-checkbox";        checkbox.checked = true;        checkbox.style.cssText = `                margin: 0 4px;                cursor: pointer;                display: none;            `;        checkbox.onchange = () => this.updateStats(item);        labelArea.insertBefore(checkbox, labelArea.firstChild);      });      const itemLabel = item.querySelector(".cell.item-label");      if (!itemLabel) return;      let statsElement = item.querySelector(".total-stats");      if (!statsElement) {        statsElement = document.createElement("div");        statsElement.className = "total-stats";        statsElement.style.cssText = `                position: absolute;                bottom: 8px;                right: 8px;                padding: 2px 6px;                background: rgba(255, 255, 255, 0.9);                border: 1px solid #ddd;                border-radius: 4px;                font-size: 12px;                color: #666;                z-index: 2;                display: flex;                align-items: center;                gap: 8px;            `;        const toggleContainer = document.createElement("div");        toggleContainer.className = "stats-toggle-container";        toggleContainer.style.cssText = `                display: inline-flex;                align-items: center;                gap: 4px;            `;        const toggle = document.createElement("input");        toggle.type = "checkbox";        toggle.className = "stats-toggle";        toggle.style.cssText = `                margin: 0;                cursor: pointer;                vertical-align: middle;            `;        const label = document.createElement("label");        label.textContent = "过滤模式";        label.style.cssText = `                cursor: pointer;                font-size: 12px;                color: #666;                user-select: none;                vertical-align: middle;            `;        toggleContainer.appendChild(toggle);        toggleContainer.appendChild(label);        const statsInfo = document.createElement("div");        statsInfo.className = "stats-info";        statsElement.appendChild(toggleContainer);        statsElement.appendChild(statsInfo);        if (itemLabel) {          itemLabel.style.position = "relative";          itemLabel.appendChild(statsElement);        }        toggle.onchange = () => {          const checkboxes = item.querySelectorAll(".variation-checkbox");          checkboxes.forEach((checkbox) => {            checkbox.style.display = toggle.checked ? "inline-block" : "none";            if (!toggle.checked) {              checkbox.checked = true;            }          });          this.updateStats(item);        };      }      this.updateStats(item);    }    // 更新统计信息    updateStats(item) {      let totalSales = 0;      let totalRevenue = 0;      item.querySelectorAll(".dashboard-items-variation .row").forEach((variation) => {        var _a, _b;        const checkbox = variation.querySelector(".variation-checkbox");        if (!checkbox || !checkbox.checkedreturn;        const salesCount = (_a = variation.querySelector(".sales_quantity .count")) == null ? void 0 : _a.textContent;        if (salesCount) {          totalSales += parseInt(salesCount, 10) || 0;        }        const revenue = (_b = variation.querySelector(".sales_subtotal")) == null ? void 0 : _b.textContent;        if (revenue) {          const revenueNum = parseInt(revenue.replace(/[^\d]/g""), 10) || 0;          totalRevenue += revenueNum;        }      });      const statsInfo = item.querySelector(".total-stats .stats-info");      if (statsInfo) {        statsInfo.innerHTML = `                总销量: <strong>${totalSales}</strong> |                 总收益: <strong>${totalRevenue.toLocaleString()}</strong> JPY            `;      }    }    cleanup() {      const observer = this.context.observers.get("page");      if (observer instanceof MutationObserver) {        observer.disconnect();        this.context.observers.delete("page");      }      if (this.itemObserver) {        this.itemObserver.disconnect();      }      document.querySelectorAll(".item-wrapper").forEach((item) => {        const variationObserver = item.variationObserver;        if (variationObserver instanceof MutationObserver) {          variationObserver.disconnect();          delete item.variationObserver;        }      });      document.querySelectorAll(".tag-copy-btn, .variation-number, .variation-checkbox, .total-stats, .stats-toggle-container").forEach((el) => el.remove());    }  }  var _GM_notification = /* @__PURE__ */ (() => typeof GM_notification != "undefined" ? GM_notification : void 0)();  var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();  var _GM_setClipboard = /* @__PURE__ */ (() => typeof GM_setClipboard != "undefined" ? GM_setClipboard : void 0)();  var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();  class SessionFeature extends Feature {    shouldExecute() {      return true;    }    async execute() {      await super.execute();      _GM_registerMenuCommand("获取Booth Session"() => this.getSession());    }    extractCookieInfo(headers) {      var _a, _b;      const cookieHeader = headers.split("\n").find((line) => line.toLowerCase().startsWith("set-cookie:") && line.includes("_plaza_session_nktz7u="));      if (!cookieHeader) return null;      const value = cookieHeader.split(";")[0].split("=").slice(1).join("=").trim();      const expires = (_b = (_a = cookieHeader.match(/expires=([^;]+)/i)) == null ? void 0 : _a[1]) == null ? void 0 : _b.trim();      return {        value,        expires: expires ? new Date(expires).toISOString() : null      };    }    getSession() {      _GM_xmlhttpRequest({        method"GET",        url"https://manage.booth.pm/orders",        headers: {          "Accept""text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",          "Accept-Language""ja,en-US;q=0.9,en;q=0.8"        },        onload(response) => {          const cookieInfo = this.extractCookieInfo(response.responseHeaders);          if (cookieInfo) {            const cookieData = {              _plaza_session_nktz7u: cookieInfo.value,              updated_at: (/* @__PURE__ */ new Date()).toISOString(),              expires_at: cookieInfo.expires            };            _GM_setClipboard(JSON.stringify(cookieData, null2), "Booth Session");            _GM_notification({              text: cookieInfo.expires ? `Session已复制过期时间: ${new Date(cookieInfo.expires).toLocaleString()}` : "Session已复制到剪贴板",              title"获取成功",              timeout3e3            });          } else {            _GM_notification({              text"未找到有效的 Session",              title"获取失败",              timeout3e3            });          }        },        onerror() => {          _GM_notification({            text"请求出错,请检查网络连接",            title"错误",            timeout3e3          });        }      });    }  }  class BoothEnhancer {    constructor() {      __publicField(this"context", {        observers/* @__PURE__ */ new Map(),        cachedElements/* @__PURE__ */ new Map()      });      __publicField(this"features", [        // new OrderAnalysisFeature(this.context),        new ItemEditFeature(this.context),        new ItemManageFeature(this.context),        new SessionFeature(this.context)      ]);    }    async init() {      try {        await Utils.waitForDOMReady();        for (const feature of this.features) {          try {            if (feature.shouldExecute()) {              await feature.execute();            }          } catch (error) {            handleError(error);          }        }      } catch (error) {        handleError(error, () => {          console.error("Booth Enhancer 启动失败");        });      }    }    destroy() {      try {        this.features.forEach((feature) => feature.cleanup());        this.context.observers.clear();        this.context.cachedElements.clear();      } catch (error) {        handleError(error);      }    }  }  new BoothEnhancer().init();
})();
解析

脚本主要作用

  • 面向 Booth 管理端/商品页,自动增强编辑与管理体验:

    • 变体序号:在商品编辑页与商品列表卡片中,为每个变体(variation)标上 #1/#2/... 序号,并在 DOM 变化时保持同步。

    • 标签工具:在商品编辑页提供 "复制标签 / 粘贴标签 / 清空标签",支持批量添加、进度条反馈、防重。

    • 管理列表增强:在商品管理页为每个商品卡片添加 "复制标签" 与 "删除商品(带二次确认与 CSRF)",并统计 总销量/总收入(可切换"过滤模式"按勾选变体累加)。

    • 一键获取 Booth Session:通过菜单命令请求后端页面响应头,解析并复制 _plaza_session_nktz7u 到剪贴板,配合通知提示。

总体结构与流程

  • 入口:new BoothEnhancer().init()

    • 等待 DOM 就绪 → 依次执行可用的 Feature(功能模块)。

  • 公共工具:

    • Utils:节流、sleep、DOM 就绪、按钮状态动画("已完成"→恢复原样)。

    • Simulate:模拟输入与回车(给标签输入框用)。

    • Feature:功能基类(shouldExecute()/execute()/cleanup())。

    • 错误处理统一走 handleError

关键方法

1) ItemEditFeature(商品编辑页增强)

作用页面/items/:id/edit 与 /items/:id/edit_pre

  • shouldExecute():匹配编辑页路径。

  • execute():调用两大功能 —— 变体序号 与 标签按钮

A. 变体序号

  • addNumbers()

    • 在 ul.grid.gap-16 列表中的每个 li(存在 .variation-box-head)前插入 #序号

    • 给每个目标 ul 绑 MutationObserver,子项增删时调用 processUlNumbers(ul) 重新编号;

    • 还在 body 上放一个观察器,若新增了符合条件的 ul,会重置并重新绑定。

  • processUlNumbers(ul)

    • 遍历 ul.children,重绘 #1/#2/...,避免重复插入。

B. 标签工具

  • addTagButtons()

    • 等待 #item_tag .item-search-input__container 出现后,右侧加入三个按钮:"复制标签 / 粘贴标签 / 清空标签"。

  • copyTags()

    • 读取 #item_tag 中现有标签(.bg-secondary500 .font-bold),复制为 JSON 数组到剪贴板,并给按钮做"完成"动画。

  • pasteTags()

    • 从剪贴板解析 JSON 数组 → 过滤掉已存在的 → 对剩余的依次:填入输入框 → 回车,带进度条 UI(createProgressTip()),结束后动画反馈。

  • clearTags()

    • 依次点击每个标签的删除图标(倒序),带进度条 UI,并在完成后动画反馈。

  • createProgressTip(container)

    • 在标签区域上方插入一个浅色提示条 + 进度条,提供 updateProgress/complete/remove 接口。

  • cleanup():断开各 observer,移除注入的按钮与样式元素。

2) ItemManageFeature(商品管理页增强)

作用页面/items 列表页

  • shouldExecute():限定在 /items

  • execute():启动整页观察 → 懒加载处理每个商品卡片。

A. 卡片处理(核心)

  • setupItemsObserver()

    • 用 MutationObserver(节流)监听页面新增的 .item-wrapper,交给 IntersectionObserver 懒处理。

  • processItem(item)

    • 依次调用:addButtonToItemaddVariationNumbersToItemaddTotalStats,完成后标记 data-processed="true"

B. 变体序号(列表卡片内)

  • addVariationNumbersToItem(item)

    • 在 .dashboard-items-variation .row 的标签区前插入 #序号

    • 对变体列表绑 MutationObserver(节流),发现编号不一致时 requestAnimationFrame 触发重绘。

C. 操作按钮

  • addButtonToItem(item)

    • 在卡片右上角添加 删除 按钮:二次确认 → 取页面 meta[name="csrf-token"] → 调 DELETE https://manage.booth.pm/items/:id;成功则移除卡片;失败提示。

    • 在卡片底部动作区域添加 复制标签 按钮:调用 copyItemManageTags(tagList)

  • copyItemManageTags(tagList)

    • 读取 .dashboard-items-tags .tag-text → JSON 数组 → 复制剪贴板 → 动画反馈。

D. 总销量 / 总收益

  • addTotalStats(item)

    • 开启后显示变体勾选框,可按勾选变体汇总;

    • 关闭则全部计算。

    • 给每个变体行插入一个 隐藏复选框(默认勾选);

    • 在卡片标题区加一个悬浮小面板显示总销量/总收益,并有"过滤模式"开关:

  • updateStats(item)

    • 销量:.sales_quantity .count

    • 收入:.sales_subtotal(提取数字,累计后 toLocaleString() 显示为 JPY)

    • 遍历勾选的变体,汇总:

  • cleanup():断开页面观察、逐卡片解绑变体观察,移除注入的按钮、序号、复选框、统计面板。

3) SessionFeature(获取 Session)

作用页面:全站(shouldExecute() => true

  • execute():注册脚本菜单命令 "获取Booth Session"

  • getSession()

    • 以 GM_xmlhttpRequest 访问 https://manage.booth.pm/orders

    • extractCookieInfo(headers) 从响应头 Set-Cookie 抓 _plaza_session_nktz7u 的值与 expires

    • 复制 { _plaza_session_nktz7u, updated_at, expires_at } JSON 到剪贴板(GM_setClipboard),并用 GM_notification 提示成功/失败。



注意

本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。


历史脚本txt文件获取>>
服务器搭建,人工服务咨询>>

没有评论:

发表评论

页面增强任务脚本

1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/Bg6shY若失效,可用地址 1.购买服务器 阿里云: 服务器购买地址 https : //t.aliyun.com/U/Bg6shY 若失效,可用地址 https ://www.aliyun....