Greasy Fork 支持简体中文。

Zhubai Toolbox 🧰

Tools for Zhubai creators.

目前為 2023-04-14 提交的版本,檢視 最新版本

// ==UserScript==
// @name                 Zhubai Toolbox 🧰
// @name:zh-CN           竹白工具箱 🧰
// @namespace            https://github.com/utags/zhubai-toolbox
// @homepage             https://github.com/utags/zhubai-toolbox#readme
// @supportURL           https://github.com/utags/zhubai-toolbox/issues
// @version              0.0.2
// @description          Tools for Zhubai creators.
// @description:zh-CN    为竹白创作者的工具箱,包括订阅者信息导出,Markdown 编辑器等功能。更多功能欢迎交流。
// @icon                 https://zhubai.love/favicon.png
// @author               Pipecraft
// @license              MIT
// @match                https://zhubai.love/*
// @connect              zhubai.love
// @grant                GM_addElement
// ==/UserScript==
//
;(() => {
  "use strict"
  var doc = document
  var createElement = (tagName, attributes) =>
    setAttributes(doc.createElement(tagName), attributes)
  var addEventListener = (element, type, listener, options) => {
    if (!element) {
      return
    }
    if (typeof type === "object") {
      for (const type1 in type) {
        if (Object.hasOwn(type, type1)) {
          element.addEventListener(type1, type[type1])
        }
      }
    } else if (typeof type === "string" && typeof listener === "function") {
      element.addEventListener(type, listener, options)
    }
  }
  var setAttribute = (element, name, value) =>
    element ? element.setAttribute(name, value) : void 0
  var setAttributes = (element, attributes) => {
    if (element && attributes) {
      for (const name in attributes) {
        if (Object.hasOwn(attributes, name)) {
          const value = attributes[name]
          if (name === "textContent") {
            element[name] = value
          } else if (name === "style") {
            setStyle(element, value, true)
          } else if (/on\w+/.test(name)) {
            const type = name.slice(2)
            addEventListener(element, type, value)
          } else {
            setAttribute(element, name, value)
          }
        }
      }
    }
    return element
  }
  var setStyle = (element, values, overwrite) => {
    if (!element) {
      return
    }
    const style = element.style
    if (typeof values === "string") {
      style.cssText = overwrite ? values : style.cssText + ";" + values
      return
    }
    if (overwrite) {
      style.cssText = ""
    }
    for (const key in values) {
      if (Object.hasOwn(values, key)) {
        style[key] = values[key].replace("!important", "")
      }
    }
  }
  if (typeof Object.hasOwn !== "function") {
    Object.hasOwn = (instance, prop) =>
      Object.prototype.hasOwnProperty.call(instance, prop)
  }
  var addElement = (parentNode, tagName, attributes) => {
    if (typeof parentNode === "string" || typeof tagName === "string") {
      const element = GM_addElement(parentNode, tagName, attributes)
      setAttributes(element, attributes)
      return element
    }
    setAttributes(tagName, attributes)
    parentNode.append(tagName)
    return tagName
  }
  async function fetchZhubaiSubscriptions(
    page,
    subscriberEmailSet,
    subscribers
  ) {
    page = page || 1
    const url = `https://zhubai.love/api/dashboard/subscriptions?limit=20&page=${page}`
    const response = await fetch(url, {})
    console.log("Fetched page", page)
    if (response.status !== 200) {
      console.warn(response)
      return
    }
    const data = await response.json()
    for (const subscriber of data.data) {
      subscribers.push(subscriber)
      if (subscriber.subscriber_email) {
        subscriberEmailSet.add(subscriber.subscriber_email)
      }
    }
    const limit = data.pagination.limit
    const total = data.pagination.total_count
    return { limit, total }
  }
  async function main() {
    const modal = addElement(document.body, "div", {
      style:
        "width: 100%; height: 100%; position: fixed; top: 72px; left: 30px; padding: 10px; background-color: #fff;",
    })
    const message = addElement(modal, "p", {
      style: "font-weight: 600; font-size: 16px; color: #060e4b;",
      textContent: "\u{1F680} \u6B63\u5728\u5BFC\u51FA\u6570\u636E ...",
    })
    addElement(modal, "p", {
      style: "font-weight: 600; font-size: 16px; color: #060e4b;",
      textContent: "\u{1F4EE} \u90AE\u7BB1\u8BA2\u9605\u5217\u8868",
    })
    const textarea = addElement(modal, "textarea", {
      style: "width: 90%; height: 40%; padding: 5px;",
    })
    addElement(modal, "p", {
      style: "font-weight: 600; font-size: 16px; color: #060e4b;",
      textContent:
        "\u{1F4D6} \u8BE6\u7EC6\u8BA2\u9605\u7528\u6237\u6570\u636E\uFF0C\u5305\u542B\u90AE\u7BB1\u8BA2\u9605\u548C\u5FAE\u4FE1\u8BA2\u9605",
    })
    const textarea2 = addElement(modal, "textarea", {
      style: "width: 90%; height: 40%; padding: 5px;",
    })
    const subscriberEmailSet = /* @__PURE__ */ new Set()
    const subscribers = []
    let page = 1
    try {
      while (true) {
        const result = await fetchZhubaiSubscriptions(
          page,
          subscriberEmailSet,
          subscribers
        )
        const total = result.total
        const limit = result.limit
        message.textContent = `\u{1F697} \u6B63\u5728\u83B7\u53D6\u6570\u636E: ${page} / ${Math.round(
          total / 20
        )}`
        if (subscribers.length > 0) {
          textarea.value = JSON.stringify([...subscriberEmailSet], null, 2)
          textarea2.value = JSON.stringify(subscribers, null, 2)
        }
        if (limit * page < total) {
          page++
        } else {
          break
        }
      }
      message.textContent = `\u{1F389} \u6570\u636E\u5BFC\u51FA\u5B8C\u6BD5\u3002\u8BF7\u590D\u5236\u4E0B\u9762\u7684\u6570\u636E\uFF0C\u505A\u597D\u5907\u4EFD\u3002`
    } catch (error) {
      console.error(error)
      message.innerHTML = `\u6570\u636E\u5BFC\u51FA\u5931\u8D25\uFF0C\u6709\u95EE\u9898\u8BF7\u5728 <a href="https://github.com/utags/zhubai-toolbox/issues" target="_blank">GitHub</a> \u6216 <a href="https://greasyfork.org/scripts/463934" target="_blank">Greasy Fork</a> \u53CD\u9988\u3002`
    }
  }
  var intervalId = setInterval(() => {
    const button = document.querySelector("th:nth-of-type(6) button")
    if (button && button.textContent === "\u5BFC\u5165/\u5BFC\u51FA") {
      const newButton = createElement("button", {
        textContent: "\u5BFC\u5165/\u5BFC\u51FA",
        class: "Button_button__2Ce79 Button_defaultButton__1bbUl",
      })
      button.after(newButton)
      button.remove()
      newButton.addEventListener("click", (event) => {
        main()
        event.preventDefault()
      })
      clearInterval(intervalId)
    }
  }, 1e3)
})()