PixivPrivateBookmarkButton

pixiv.netで、非公開状態でブックマークするボタンを追加します

// ==UserScript==
// @name            PixivPrivateBookmarkButton
// @namespace       sgthr7/monkey-script
// @version         0.0.1
// @author          SGThr7
// @description     pixiv.netで、非公開状態でブックマークするボタンを追加します
// @description:en  Add private bookmark button to pixiv.net
// @license         MIT
// @match           https://www.pixiv.net/*
// @require         https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js
// @grant           GM_addStyle
// ==/UserScript==

(t=>{if(typeof GM_addStyle=="function"){GM_addStyle(t);return}const o=document.createElement("style");o.textContent=t,document.head.append(o)})(" .ppbb-root{display:inline;-webkit-user-select:none;user-select:none}.ppbb-main{padding-right:13px}.ppbb-absolute{position:absolute;bottom:0;right:32px}.private-bookmark-button[data-v-c5b4a471]{color:inherit;font-size:large;font-family:inherit}.container[data-v-c5b4a471]{position:relative}.heart[data-v-c5b4a471]{font-size:200%}.heart-fill[data-v-c5b4a471]{color:inherit}.heart-outline[data-v-c5b4a471]{position:absolute;right:0;bottom:0;color:#000}.bookmarked[data-v-c5b4a471]{color:#ff4060}.lock[data-v-c5b4a471]{font-size:100%;position:absolute;right:-5px;bottom:1px} ");

(function (vue) {
  'use strict';

  const _withScopeId = (n) => (vue.pushScopeId("data-v-c5b4a471"), n = n(), vue.popScopeId(), n);
  const _hoisted_1 = { class: "container" };
  const _hoisted_2 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "heart heart-outline" }, "♡", -1));
  const _hoisted_3 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", { class: "lock" }, "🔒️", -1));
  const _sfc_main = /* @__PURE__ */ vue.defineComponent({
    __name: "PrivateBookmarkButton",
    props: {
      artworkId: {
        type: String,
        required: true,
        validator: (val) => {
          const validatorRegex = /^\d+$/;
          return validatorRegex.test(val);
        }
      },
      relatedBookmarkButtonContainer: {
        type: Element,
        required: false
      }
    },
    setup(__props) {
      const props = __props;
      const getBookmarkButton = () => {
        var _a;
        return (_a = props.relatedBookmarkButtonContainer) == null ? void 0 : _a.querySelector(":is(button, a:has(> svg))");
      };
      const isBookmarked = vue.ref(parseIsBookmarked());
      function parseIsBookmarked() {
        var _a;
        const styleElementClass = "sc-j89e3c-1";
        const styleElement = (_a = props.relatedBookmarkButtonContainer) == null ? void 0 : _a.querySelector(`.${styleElementClass}`);
        const bookmarkedClassName = "bXjFLc";
        return (styleElement == null ? void 0 : styleElement.classList.contains(bookmarkedClassName)) ?? false;
      }
      if (props.relatedBookmarkButtonContainer != null) {
        const observer = new MutationObserver(() => {
          isBookmarked.value = parseIsBookmarked();
        });
        observer.observe(props.relatedBookmarkButtonContainer, { subtree: true, childList: true, attributes: true, attributeFilter: ["class"] });
      }
      const bookmarkPageUrl = vue.computed(() => new URL(`https://www.pixiv.net/bookmark_add.php?type=illust&illust_id=${props.artworkId}`));
      function privateBookmark() {
        var _a;
        (_a = getBookmarkButton()) == null ? void 0 : _a.click();
        if (isBookmarked.value) {
          return;
        }
        const bookmarkPageWindow = window.open(bookmarkPageUrl.value, "_blank", "popup,width=1,height=1,top=0,left=0");
        const bookmarkPageAction = () => {
          if (bookmarkPageWindow == null) {
            throw new Error("Failed to get bookmark page window");
          }
          const bookmarkPageDocument = bookmarkPageWindow.document;
          if (bookmarkPageDocument == null) {
            throw new Error("Failed to get bookmark page document");
          }
          const form = bookmarkPageDocument.querySelector("section.bookmark-detail-unit>form");
          if (form == null) {
            throw new Error("Failed to find bookmark form");
          }
          const restrictRadio = form.elements.namedItem("restrict");
          if (restrictRadio == null || !isRadioNodeList(restrictRadio)) {
            throw new Error("Failed to get restrict radio button");
          }
          restrictRadio.value = "1";
          const finishedEventName = "pagehide";
          const onBookmarkedAction = () => {
            bookmarkPageWindow.removeEventListener(finishedEventName, onBookmarkedAction);
            bookmarkPageWindow.close();
          };
          bookmarkPageWindow.addEventListener(finishedEventName, onBookmarkedAction);
          form.requestSubmit();
        };
        bookmarkPageWindow == null ? void 0 : bookmarkPageWindow.addEventListener("load", bookmarkPageAction);
      }
      function isRadioNodeList(target) {
        return target instanceof RadioNodeList || target.toString() === RadioNodeList.prototype.toString();
      }
      return (_ctx, _cache) => {
        return vue.openBlock(), vue.createElementBlock("button", {
          type: "button",
          class: "ppbb-button fgVkZi",
          onClick: privateBookmark
        }, [
          vue.createElementVNode("div", _hoisted_1, [
            vue.createElementVNode("span", {
              class: vue.normalizeClass(["heart heart-fill", { bookmarked: isBookmarked.value }])
            }, "♥", 2),
            _hoisted_2,
            vue.createTextVNode("️"),
            _hoisted_3
          ])
        ]);
      };
    }
  });
  const _export_sfc = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
      target[key] = val;
    }
    return target;
  };
  const PrivateBookmarkButton = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-c5b4a471"]]);
  function isElement(node) {
    return node.nodeType === Node.ELEMENT_NODE;
  }
  const globalObserver = new MutationObserver((records, _observer) => {
    records.forEach((record) => {
      if (record.addedNodes.length <= 0) {
        return;
      }
      if (Array.from(record.addedNodes).some((node) => isElement(node) && Array.from(node.classList).some((className) => className.startsWith("ppbb")))) {
        return;
      }
      Array.from(record.addedNodes).filter(isElement).filter(
        (el) => el.querySelectorAll("button.sc-kgq5hw-0").length === 1 && el.querySelector("div.ppbb-root") == null
      ).forEach(applyThumbnailArtwork);
      if (record.addedNodes.length === 1) {
        const maybeContainersOwner = record.addedNodes[0];
        if (isElement(maybeContainersOwner)) {
          const artworkContainersList = maybeContainersOwner.querySelectorAll(":is(ul, div.sc-1nhgff6-4) > :is(div, li):has(button.sc-kgq5hw-0)");
          artworkContainersList.forEach((artworkContainers) => {
            Array.from(artworkContainers.children).filter((el) => el.querySelector("div.ppbb-root") == null).forEach(applyThumbnailArtwork);
          });
        }
      }
    });
  });
  const globalObserverOption = {
    childList: true,
    subtree: true
  };
  function init() {
    const initialArtworkContainers = document.querySelectorAll("div:has(a[data-gtm-value]):has(div:nth-child(2) button.sc-kgq5hw-0)");
    initialArtworkContainers.forEach((el) => {
      if (el.querySelectorAll("button.sc-kgq5hw-0").length === 1 && el.querySelector("div.ppbb-root") == null) {
        applyThumbnailArtwork(el);
      }
    });
    window.addEventListener("load", onLoad);
    globalObserver.observe(document, globalObserverOption);
    const titleObserver = new MutationObserver((records, _observer) => {
      initMainArtwork();
    });
    const title = document.head.querySelector("title");
    if (title != null) {
      titleObserver.observe(title, {
        childList: true,
        subtree: true
      });
    }
  }
  function onLoad() {
    initMainArtwork();
  }
  init();
  function initMainArtwork() {
    var _a;
    const buttonContainer = document.querySelector("div.sc-181ts2x-3");
    if (buttonContainer == null) {
      return;
    }
    const url = new URL(window.location.href);
    const artworkPageRegex = /^\/(?:en\/)?artworks\/(\d+)$/;
    const regexResult = url.pathname.match(artworkPageRegex);
    if (regexResult == null || regexResult.length <= 1) {
      return;
    }
    const artworkId = regexResult[1];
    const ppbbRoot = document.createElement("div");
    ppbbRoot.classList.add("ppbb-root", "ppbb-main");
    (_a = buttonContainer.parentNode) == null ? void 0 : _a.insertBefore(ppbbRoot, buttonContainer.nextElementSibling);
    const app = vue.createApp(PrivateBookmarkButton, {
      artworkId,
      relatedBookmarkButtonContainer: buttonContainer
    });
    app.mount(ppbbRoot);
  }
  function applyThumbnailArtwork(target) {
    var _a;
    const artworkLink = target.querySelector("a[data-gtm-value]");
    if (artworkLink == null) {
      return;
    }
    const artworkId = artworkLink.getAttribute("data-gtm-value");
    if (artworkId == null) {
      return;
    }
    const button = target.querySelector("button");
    if (button == null) {
      return;
    }
    const buttonContainer = (_a = button.parentElement) == null ? void 0 : _a.parentElement;
    if (buttonContainer == null) {
      return;
    }
    const ppbbRoot = document.createElement("div");
    ppbbRoot.classList.add("ppbb-root", "ppbb-absolute");
    buttonContainer.appendChild(ppbbRoot);
    const app = vue.createApp(PrivateBookmarkButton, {
      artworkId,
      relatedBookmarkButtonContainer: button.parentElement
    });
    app.mount(ppbbRoot);
  }

})(Vue);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址