dzmm-helper

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         dzmm-helper
// @namespace    oninashi
// @version      1.1.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        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 _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 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 = _unsafeWindow.fetch.bind(_unsafeWindow);
  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;
  };
  _unsafeWindow.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 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) => {
    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");
      }
      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();
      if ($img.dataset.event === "set") return;
      $img.dataset.event = "set";
      if (!isListMode) {
        $img.draggable = true;
      }
      fnPromptHandle($img, isListMode);
      fnBadgeHandle($img);
      storePublic.isPublic($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 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 fnAddNavLinks = () => {
    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();
  };
  const mountLitePage = () => {
    console.log("lite page mounted");
    gob.enablePageObserve(() => {
      fnInitLitePage();
    });
  };
  mountLitePage();
})();