dzmm-helper

自用辅助脚本,只适用于电脑浏览器

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

Advertisement:

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

Advertisement:

// ==UserScript==
// @name         dzmm-helper
// @namespace    oninashi
// @version      1.2.0
// @author       oninashi
// @description  自用辅助脚本,只适用于电脑浏览器
// @license      MIT
// @icon         https://www.dzmm.ai/favicon.ico
// @match        https://www.dzmm.ai/*
// @match        https://www.dzmm.io/*
// @match        https://www.duskpine.top/*
// @match        https://www.aiaptx.com/*
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        unsafeWindow
// ==/UserScript==

(function() {
  "use strict";

  const d = new Set(); const importCSS = async (e) => { d.has(e) || (d.add(e), ((t) => { typeof GM_addStyle == "function" ? GM_addStyle(t) : (document.head || document.documentElement).appendChild(document.createElement("style")).append(t); })(e)); };

  var _GM_getValue = (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  var _GM_setValue = (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  var _unsafeWindow = (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  const lsObj = {
    setItem: (key, value) => {
      localStorage.setItem(key, JSON.stringify(value));
    },
    getItem: (key, def = "") => {
      const item = localStorage.getItem(key);
      if (item) {
        return JSON.parse(item);
      }
      return def;
    },
  };
  const _locHref = () => location.href;
  const $n = (selector) => {
    return document.querySelector(selector);
  };
  const $na = (selector) => {
    return document.querySelectorAll(selector);
  };
  const gob = {
    $body: document.body,
    pageObserver: null,
    get locHref() {
      return _locHref();
    },
    get bolWidthChanged() {
      return $n("div.width-adjusted") !== null;
    },
    get $$header() {
      return $na("header");
    },
    _checkImgUrl: (url) => url.startsWith("/api/draw/image/"),
    _getUUID: (url) => {
      const parts = decodeURIComponent(url).split("/");
      return parts[parts.length - 1].split("?")[0];
    },
    _getImgUrl: (url) => {
      const uuid = gob._getUUID(url);
      const rslUrl = `${location.origin}/draw/${uuid}`;
      return rslUrl;
    },
    _markImg: ($img, classNames, delay = 1e3) => {
      setTimeout(() => {
        $img.classList.add(...classNames, "dzmm-image");
        if ($img.classList.contains("opacity-0")) {
          gob._markImg($img, classNames, delay);
          return;
        }
      }, delay);
    },
    _getImages: () => {
      const $$imgs = $na("div.group img");
      const $$Images = [];
      $$imgs.forEach(($img) => {
        const src = $img.getAttribute("src");
        if (src && gob._checkImgUrl(src)) {
          $img.dataset.uuid = gob._getUUID(src);
          $$Images.push($img);
        }
      });
      return $$Images;
    },
    _isHistoryPage() {
      return this.locHref.includes("draw/generate/history");
    },
    _isHistoryGallery() {
      return this.locHref.includes("draw/generate/history?sub=gallery");
    },
    _isGeneratePage() {
      return this.locHref.endsWith("draw/generate/create");
    },
    _isDrawPage() {
      return /\/draw\/[a-f0-9-]{36}$/.test(this.locHref);
    },
    _isCharEdt() {
      return this.locHref.includes("/studio/character-creation");
    },
    _cleanClickEvents($el) {
      $el.onclick = (e) => {
        e.stopPropagation();
      };
      $el.oncontextmenu = (e) => {
        e.stopPropagation();
      };
    },
    _delayRun(fn, delay = 1e3) {
      setTimeout(() => {
        fn();
      }, delay);
    },
    disablePageObserve() {
      if (this.pageObserver) {
        this.pageObserver.disconnect();
        this.pageObserver = null;
      }
    },
    enablePageObserve(callback) {
      if (this.pageObserver) {
        return;
      }
      this.pageObserver = new MutationObserver((mr, mo) => callback(mr, mo));
      this.pageObserver.observe(this.$body, {
        childList: true,
        subtree: true,
      });
    },
  };
  const LS_PUBLIC = "dzmm_listPublic";
  const storePublic = {
    galleries: {},
    load() {
      const galleries = lsObj.getItem(LS_PUBLIC, {});
      if (Object.keys(galleries).length > 0) {
        this.galleries = galleries;
      }
    },
    save() {
      lsObj.setItem(LS_PUBLIC, this.galleries);
    },
    parseGalleries(res) {
      const data = JSON.parse(res);
      if (data.result?.data?.json) {
        const galleries = data.result.data.json;
        if (Array.isArray(galleries)) {
          galleries.forEach((gallery) => {
            const { id, title, images } = gallery;
            this.galleries[id] = { id, title, images };
          });
          this.save();
        }
      }
    },
    isPublic($img) {
      const uuid = $img.getAttribute("data-uuid");
      if (!uuid) return;
      Object.values(this.galleries).forEach((gallery) => {
        gallery.images.forEach((image) => {
          if (image.endsWith(uuid)) {
            gob._markImg($img, ["public"]);
          }
        });
      });
    },
  };
  storePublic.load();
  const gmWindow = _unsafeWindow ?? window;
  const reFetchHandler = (requestUrl, response) => {
    const interceptConfigs = [
      {
        pattern: /\/api\/trpc\/user.getGalleries\?input=/,
        handler: async (text) => {
          storePublic.parseGalleries(text);
        },
      },
    ];
    interceptConfigs.forEach(async (config) => {
      if (config.pattern.test(requestUrl)) {
        try {
          const text = await response.clone().text();
          await config.handler(text);
        }
        catch (err) {
          console.error("拦截处理出错,回退原始 response:", err);
        }
      }
    });
  };
  const originalFetch = gmWindow.fetch.bind(gmWindow);
  const reFetch = async (input, init) => {
    const response = await originalFetch(input, init);
    const requestUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
    reFetchHandler(requestUrl, response);
    return response;
  };
  gmWindow.fetch = reFetch;
  const styleCss = "div.group:has(.dzmm-image){--orange: #f97316;--green: #10b981;border-width:2px}div.group:has(.submitted){border-top-color:var(--green)}div.group:has(.cur-downloaded){border-right-color:var(--green)}div.group:has(.public){border-bottom-color:var(--green)}div.group:has(.downloaded){border-left-color:var(--green)}div.group img.downloaded{opacity:.8;filter:brightness(.9)}div.group:has(.dzmm-art):hover .dzmm-art{flex-wrap:wrap!important}div.group:has(.dzmm-art):hover .dzmm-art>span{min-width:48%}.z-55{z-index:55}.z-60{z-index:60}.z-65{z-index:65}.z-75{z-index:75}";
  importCSS(styleCss);
  const LS_ART = "dzmm_listArt";
  const storeArt = {
    arts: [],
    load() {
      const gmArts = _GM_getValue(LS_ART, []);
      const lsArts = lsObj.getItem(LS_ART, []);
      const arts = [...new Set([...gmArts, ...lsArts])];
      if (arts.length > 0) {
        console.log("Loaded arts:", arts);
        this.arts = arts;
      }
    },
    save() {
      lsObj.setItem(LS_ART, this.arts);
      _GM_setValue(LS_ART, this.arts);
    },
    add(artName) {
      if (!this.arts.includes(artName)) {
        this.arts.push(artName);
        this.save();
      }
    },
    remove(artName) {
      const idx = this.arts.indexOf(artName);
      if (idx !== -1) {
        this.arts.splice(idx, 1);
        this.save();
      }
    },
    artsCheck(text, cb) {
      const lowerText = text.toLowerCase();
      const found = this.arts.filter((artName) => lowerText.includes(artName.toLowerCase()));
      cb(found);
    },
  };
  storeArt.load();
  const insertPreviewContainer = (clsName) => {
    let $fixedDiv = $n(`.${clsName}`);
    if (!$fixedDiv) {
      $fixedDiv = document.createElement("div");
      $fixedDiv.className = `rounded-lg bg-card fixed bottom-1 z-75 p-1.5 ${clsName} hidden`;
      $fixedDiv.innerHTML = "<div class=\"image-preview h-full\"></div>";
      document.body.appendChild($fixedDiv);
    }
    $fixedDiv.style.maxWidth = "40vw";
    return $fixedDiv;
  };
  const _isListMode = () => {
    return $na(".space-y-3").length > 0;
  };
  const fnShowImgIndex = ($img, act = "show") => {
    if (!$img) {
      return;
    }
    const i = parseInt($img.dataset.index);
    const recordIndex = $img.dataset.recordIndex;
    const clsName = `dzmm-img-index-${i}`;
    const $imgIndex = $n(`.${clsName}`);
    if (act === "show") {
      if ($imgIndex) return;
      const $span = document.createElement("span");
      $span.className = "absolute bottom-1 right-1 text-xs bg-black/50 rounded-full px-1 py-1 transition-opacity";
      $span.classList.add(clsName);
      $span.textContent = String(i + 1) + (recordIndex ? ` (${recordIndex})` : "");
      $img.insertAdjacentElement("afterend", $span);
    }
    else {
      if ($imgIndex) {
        $imgIndex.classList.add("opacity-0");
        setTimeout(() => {
          $imgIndex.remove();
        }, 500);
      }
    }
  };
  const fnFindBadge = ($el) => {
    const $elParent = $el.parentElement;
    if (!$elParent) return null;
    const $greenBg = $elParent.querySelector(".text-green-700");
    if ($greenBg) {
      return $greenBg;
    }
    else {
      return fnFindBadge($elParent);
    }
  };
  const fnBadgeHandle = ($img) => {
    const $greenBg = fnFindBadge($img);
    if ($greenBg) {
      $greenBg.classList.add("dark:text-orange-400", "text-orange-700");
      $greenBg.classList.remove("dark:text-green-400", "text-green-700");
      gob._cleanClickEvents($greenBg);
    }
    const detUrl = gob._getImgUrl($img.src);
    if ($greenBg && detUrl) {
      const tmpHtml = $greenBg.innerHTML;
      const tmpCls = $greenBg.className;
      $greenBg.className = "";
      $greenBg.innerHTML = `<a href="${detUrl}" target="_blank" class="${tmpCls}">${tmpHtml}</a>`;
    }
  };
  const fnPromptHandle = ($img, isList = false) => {
    let textPrompt = "";
    if (isList) {
      const $itemCenter = $img.closest(".items-stretch");
      const $promptWrap = $itemCenter?.querySelector(".self-stretch");
      if ($promptWrap) {
        const $prompt = $promptWrap.querySelector(".text-sm.line-clamp-2");
        $prompt?.classList.remove("line-clamp-2");
        $prompt?.classList.add("dzmm-prompt");
        const actBar = $promptWrap.querySelector("div.mt-1.justify-between");
        if (actBar) {
          actBar.classList.remove("justify-between", "items-end");
          actBar.classList.add("items-center");
        }
        $promptWrap.classList.add("cursor-default");
        $promptWrap.onclick = (e) => {
          if (e.target.tagName === "BUTTON") return;
          e.stopPropagation();
          e.preventDefault();
        };
      }
    }
    else {
      const $divGroup = $img.closest("div.group");
      const $promptWrap = $divGroup?.querySelector("div.px-3");
      if ($promptWrap && $img.dataset.index) {
        gob._cleanClickEvents($promptWrap);
        const $prompt = $promptWrap.querySelector("p.text-sm");
        $prompt?.classList.add("dzmm-prompt");
        textPrompt = $prompt?.textContent?.trim() || "";
        storeArt.artsCheck(textPrompt, (found) => {
          if (found.length > 0) {
            let $artFound;
            if ($promptWrap.querySelector(".text-xs")) {
              $artFound = $promptWrap.querySelector(".flex-nowrap");
              $artFound?.classList.add("dzmm-art");
            }
            else {
              $prompt?.insertAdjacentHTML("afterend", "<p class=\"dzmm-art flex gap-1\" data-art=\"found\"></p>");
              $artFound = $promptWrap.querySelector(".dzmm-art");
            }
            found.forEach((art) => {
              $artFound?.insertAdjacentHTML("beforeend", `<span class="text-xs px-2 py-0.5 rounded-full dark:bg-pink-900/40 dark:text-pink-200" data-art="${art}">${art}</span>`);
            });
          }
        });
      }
      if ($divGroup) {
        $divGroup.style.aspectRatio = "0.75/1.2";
      }
    }
  };
  const bindImagePreviewEvents = (getImages, $fixedDiv, clsName) => {
    const imgs = getImages();
    if (imgs.length === 0) return;
    const fistImg = imgs[0];
    const lstImgUrl = $fixedDiv.dataset.url || "";
    if (fistImg.src === lstImgUrl && fistImg.dataset.event === "set") {
      return;
    }
    $fixedDiv.dataset.url = fistImg.src;
    let t;
    const fnRemovePreview = () => {
      t = setTimeout(() => {
        $fixedDiv.classList.add("hidden");
      }, 50);
    };
    const isListMode = _isListMode();
    imgs.forEach(($img, i) => {
      $img.dataset.index = i.toString();
      storePublic.isPublic($img);
      if ($img.dataset.event === "set") return;
      $img.dataset.event = "set";
      if (!isListMode) {
        $img.draggable = true;
      }
      fnPromptHandle($img, isListMode);
      fnBadgeHandle($img);
      $img.addEventListener("mouseenter", (e) => {
        clearTimeout(t);
        fnShowImgIndex($img);
        const $preview = $n(`.${clsName} .image-preview`);
        $preview.innerHTML = `<img src="${$img.src}" class="h-full" />`;
        $fixedDiv?.appendChild($preview);
        $fixedDiv.classList.remove("hidden");
        const isLeft = isListMode || e.clientX < window.innerWidth / 2;
        if (isLeft) {
          $fixedDiv.classList.add("right-1");
          $fixedDiv.classList.remove("left-1");
        }
        else {
          $fixedDiv.classList.add("left-1");
          $fixedDiv.classList.remove("right-1");
        }
        const aspectRatio = $img.naturalWidth / $img.naturalHeight;
        if (aspectRatio >= 1) {
          $fixedDiv.classList.remove("top-1");
          $preview.querySelector("img")?.classList.remove("h-full");
        }
        else {
          $fixedDiv.classList.add("top-1");
          $preview.querySelector("img")?.classList.add("h-full");
        }
      });
      $img.addEventListener("mouseout", () => {
        fnRemovePreview();
        setTimeout(() => {
          fnShowImgIndex($img, "hide");
        }, 1500);
      });
    });
    if ($fixedDiv.dataset.event === "set") return;
    $fixedDiv.addEventListener("mousemove", () => {
      clearTimeout(t);
    });
    $fixedDiv.addEventListener("mouseleave", () => {
      fnRemovePreview();
    });
    $fixedDiv.dataset.event = "set";
  };
  const fnAddElementToNav = (newElement) => {
    const $nav = $n("nav.h-full div.hidden");
    if (!$n(".dzmm-nav-divider")) {
      const $span = document.createElement("span");
      $span.classList.add("px-1", "py-2", "text-muted-foreground");
      $span.classList.add("dzmm-nav-divider");
      $span.textContent = "|";
      $nav?.insertAdjacentElement("beforeend", $span);
    }
    newElement.classList.add("px-3", "py-2", "text-muted-foreground", "hover:text-foreground");
    if ($nav) {
      $nav?.insertAdjacentElement("beforeend", newElement);
      $nav.classList.add("dzmm-nav-added");
    }
  };
  const fnAddGalleryLink = () => {
    const clsName = "dzmm-gallery-link";
    if ($n(`.${clsName}`)) return;
    const $画廊链接 = document.createElement("a");
    $画廊链接.classList.add(clsName);
    $画廊链接.href = "/draw";
    $画廊链接.textContent = "画廊";
    fnAddElementToNav($画廊链接);
  };
  const fnAddGenerateLink = (target = "nav") => {
    const clsName = "dzmm-generate-link" + target;
    if ($n(`.${clsName}`)) return;
    const $创作链接 = document.createElement("a");
    $创作链接.classList.add(clsName);
    $创作链接.href = "/draw/generate/create";
    $创作链接.textContent = "创作";
    fnAddElementToNav($创作链接);
  };
  const fnAddHistoryLink = () => {
    const clsName = "dzmm-history-link";
    if ($n(`.${clsName}`)) return;
    const $历史链接 = document.createElement("a");
    $历史链接.classList.add(clsName);
    $历史链接.href = "/draw/generate/history";
    $历史链接.textContent = "我的作品";
    fnAddElementToNav($历史链接);
  };
  const fnAddImagePreview = () => {
    if (!gob._isHistoryPage() && !gob._isGeneratePage()) {
      return;
    }
    if (gob._isHistoryGallery()) {
      return;
    }
    const clsName = "dzmm-fixed-preview";
    const $fixedDiv = insertPreviewContainer(clsName);
    bindImagePreviewEvents(gob._getImages, $fixedDiv, clsName);
  };
  const fnAddStoreArt = () => {
    if (!gob._isHistoryPage() && !gob._isGeneratePage() && !gob._isDrawPage()) {
      return;
    }
    const clsName = "dzmm-store-art-btn";
    if ($n(`.${clsName}`)) return;
    let $subNav = $n("div.relative.items-center.overflow-x-auto");
    if (!$subNav) {
      const $h3 = $n("div.items-center > h3.font-medium");
      if (!$h3) return;
      $subNav = document.createElement("div");
      $subNav.classList.add("flex-1", "flex", "gap-1", "ml-1");
      $h3.insertAdjacentElement("afterend", $subNav);
    }
    if (!$subNav) return;
    const $btn = document.createElement("button");
    $btn.classList.add(clsName);
    $btn.classList.add("dzmm-store-art-btn", "px-2", "py-1.5", "text-sm", "text-muted-foreground", "hover:text-foreground", "rounded-md", "border", "border-input", "hover:bg-accent");
    $btn.textContent = "保存画师";
    const $input = document.createElement("input");
    $input.type = "text";
    $input.placeholder = "输入画师名称并回车";
    $input.classList.add("dzmm-art-input", "px-2", "py-1.5", "text-sm", "rounded-full", "bg-muted", "hidden");
    $subNav.insertAdjacentElement("beforeend", $input);
    $subNav.insertAdjacentElement("beforeend", $btn);
    const fnSubmitArt = () => {
      const artName = $input.value.trim().replace(/\s+/g, "_").toLocaleLowerCase();
      if (!artName) {
        $input.placeholder = "画师名称不能为空";
        return;
      }
      storeArt.add(artName);
      const btnText = $btn.textContent || "保存画师";
      $btn.textContent = "已保存: " + artName;
      gob._delayRun(() => {
        $btn.textContent = btnText;
      }, 2e3);
      $input.value = "";
    };
    let t;
    const _ToggleInput = (to) => {
      const flagFocus = $input.dataset.focus === "true";
      if (to === "show") {
        clearTimeout(t);
        $input.classList.remove("hidden");
        $input.focus();
        $input.dataset.focus = "true";
      }
      else {
        $input.blur();
        if (flagFocus) return;
        t = setTimeout(() => {
          $input.classList.add("hidden");
        }, 500);
      }
    };
    const $parent = $subNav.parentElement;
    $parent?.addEventListener("mouseenter", () => {
      _ToggleInput("show");
    });
    $parent?.addEventListener("mouseleave", () => {
      _ToggleInput("hide");
    });
    $btn.addEventListener("click", () => {
      fnSubmitArt();
    });
    $input.addEventListener("keydown", (e) => {
      if (e.key === "Enter") {
        fnSubmitArt();
      }
    });
  };
  const fnAddPromptExt = () => {
    const $h3提示词 = Array.from($na("h3")).find((el) => {
      return el.textContent?.includes("绘画提示词");
    });
    if (!$h3提示词) return;
    const $h3Parent = $h3提示词.parentElement;
    const $p = $h3Parent?.nextElementSibling;
    const fnChangePrompt = ($p2) => {
      $p2.classList.add("dzmm-sys-prompt");
      $p2.classList.add("hidden");
      const $$a = $p2.querySelectorAll("a");
      let promptText = "";
      if ($$a.length > 0) {
        $$a.forEach(($a) => {
          const linkText = $a.textContent?.trim() || "";
          promptText += linkText + ", ";
        });
      }
      else {
        promptText = $p2.textContent?.trim() || "";
      }
      let $newPromptP = $n(".dzmm-new-prompt");
      if ($newPromptP) {
        $newPromptP.textContent = promptText;
      }
      else {
        $newPromptP = document.createElement("p");
        $newPromptP.textContent = promptText;
        $newPromptP.classList.add("dzmm-new-prompt", "rounded-md", "bg-muted/60", "p-3", "leading-relaxed", "text-foreground/80");
        $h3Parent?.insertAdjacentElement("afterend", $newPromptP);
      }
    };
    if ($p && $p.tagName === "DIV") {
      fnChangePrompt($p);
      const observer = new MutationObserver(() => {
        fnChangePrompt($p);
      });
      observer.observe($p, { childList: true, subtree: true });
    }
  };
  const fnAddNavLinks = () => {
    fnAddGalleryLink();
    fnAddGenerateLink();
    fnAddHistoryLink();
    gob._delayRun(() => {
      if (gob.$$header.length >= 2) {
        Array.from(gob.$$header).forEach(($header) => {
          if (!$header.querySelector(".dzmm-nav-added")) {
            $header.remove();
          }
        });
      }
    });
  };
  const fnSetContainer = () => {
    if (gob.bolWidthChanged) {
      return;
    }
    setTimeout(() => {
      const $container = $n(".min-h-screen div.container");
      if (!$container) {
        return;
      }
      $container.className = "w-full space-y-2 flex-1 container max-w-6xl mx-auto p-4";
      const $grid = $container.querySelector(".grid.md\\:grid-cols-3");
      if (!$grid) {
        return;
      }
      $grid?.classList.add("lg:grid-cols-6", "width-adjusted");
    }, 1e3);
  };
  const fnInitLitePage = () => {
    fnAddNavLinks();
    fnSetContainer();
    fnAddImagePreview();
    fnAddStoreArt();
    fnAddPromptExt();
  };
  const mountLitePage = () => {
    console.log("lite page mounted");
    gob.enablePageObserve(() => {
      fnInitLitePage();
    });
  };
  mountLitePage();
})();