Greasy Fork is available in English.

即刻收藏导出

导出即刻收藏

// ==UserScript==
// @name         即刻收藏导出
// @namespace    https://xhs.mundane.ink
// @version      0.3
// @description  导出即刻收藏
// @match        https://web.okjike.com/me/*
// @match        https://web.okjike.com/u/*/collection
// @license      MIT
// @run-at       document-start
// @grant        unsafeWindow
// @icon         https://web.okjike.com/favicon-32x32.png
// ==/UserScript==

(function () {
  "use strict";
  console.log("即刻脚本生效了");

  const collectionList = [];
  const btnScroll = document.createElement("button");
  btnScroll.innerHTML = "自动滚动";
  btnScroll.style.position = "fixed";
  btnScroll.style.top = "160px";
  btnScroll.style.right = "20px";
  btnScroll.style.backgroundColor = "#056b00";
  btnScroll.style.color = "#fff";
  btnScroll.style.padding = "8px";
  btnScroll.style.borderRadius = "6px";
  btnScroll.style.zIndex = "1000";

  const btnCount = document.createElement("button");
  btnCount.innerHTML = "捕获数量:" + collectionList.length;
  btnCount.style.position = "fixed";
  btnCount.style.top = "210px";
  btnCount.style.right = "20px";
  btnCount.style.backgroundColor = "#056b00";
  btnCount.style.color = "#fff";
  btnCount.style.padding = "8px";
  btnCount.style.borderRadius = "6px";
  btnCount.style.zIndex = "1000";

  const btnExport = document.createElement("button");
  btnExport.innerHTML = "导出收藏";
  btnExport.style.position = "fixed";
  btnExport.style.top = "260px";
  btnExport.style.right = "20px";
  btnExport.style.backgroundColor = "#056b00";
  btnExport.style.color = "#fff";
  btnExport.style.padding = "8px";
  btnExport.style.borderRadius = "6px";
  btnExport.style.zIndex = "1000";

  document.body.appendChild(btnExport);
  document.body.appendChild(btnScroll);
  document.body.appendChild(btnCount);

  let isScrolling = false;
  let timerId;

  function simulateScroll() {
    // window.scrollBy(0, 200);
    window.scrollBy({ top: 200, left: 0, behavior: "smooth" });
  }

  function startScroll() {
    if (isScrolling) {
      return;
    }
    isScrolling = true;
    btnScroll.innerHTML = "停止滚动";
    btnScroll.style.backgroundColor = "#ff2442";
    timerId = setInterval(simulateScroll, 200);
  }

  function cancelScroll() {
    if (!isScrolling) {
      return;
    }
    isScrolling = false;
    btnScroll.style.backgroundColor = "#056b00";
    btnScroll.innerHTML = "自动滚动";
    if (timerId) {
      clearInterval(timerId);
    }
  }

  // 给按钮添加点击事件
  btnScroll.addEventListener("click", function () {
    if (isScrolling) {
      cancelScroll();
    } else {
      startScroll();
    }
  });

  btnExport.addEventListener("click", function () {
    const header = "链接,内容\n";
    // 导出csv文件
    const csvContent =
      "data:text/csv;charset=utf-8,\uFEFF" +
      header +
      collectionList
        .map((item) => {
          return `${item.url},${item.content}`;
        })
        .join("\n");
    const encodedUri = encodeURI(csvContent);
    const link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "即刻收藏.csv");
    document.body.appendChild(link);
    link.click();
    link.remove();
  });

  function csvEscapeStr(str) {
    return `"${str
      .replace(/"/g, '""')
      .replace(/#/g, "")
      .replace(/\n/g, "\\n")
      .replace(/\r/g, "\\r")}"`;
  }

  // 拦截 fetch 请求
  const originFetch = fetch;
  window.unsafeWindow.fetch = (url, options) => {
    return originFetch(url, options).then(async (response) => {
      if (url === "https://web-api.okjike.com/api/graphql") {
        const responseClone = response.clone();
        let res = await responseClone.json();
        intercept(res);
        const responseNew = new Response(JSON.stringify(res), response);
        return responseNew;
      } else {
        return response;
      }
    });
  };

  function intercept(res) {
    if (
      res.data &&
      res.data.viewer &&
      res.data.viewer.collections &&
      res.data.viewer.collections.nodes
    ) {
      const nodes = res.data.viewer.collections.nodes;

      const collections = nodes.map((node) => {
        return {
          url: csvEscapeStr(`https://web.okjike.com/originalPost/${node.id}`),
          content: csvEscapeStr(node.content),
        };
      });
      collectionList.push(...collections);

      btnCount.innerHTML = "捕获数量:" + collectionList.length;
    }
  }
})();