MemTrace

trace browsing history and preserve tables (HTML passthrough)

当前为 2024-06-28 提交的版本,查看 最新版本

// ==UserScript==
// @name         MemTrace
// @namespace    Violentmonkey Scripts
// @version      0.1
// @description  trace browsing history and preserve tables (HTML passthrough)
// @author       fankaidev
// @match        *://*/*
// @exclude      *://cubox.pro/*
// @exclude      *://localhost:*/*
// @exclude      *://127.0.0.1:*/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @require      https://cdnjs.cloudflare.com/ajax/libs/turndown/7.1.1/turndown.min.js
// @require      https://unpkg.com/[email protected]/dist/turndown-plugin-gfm.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/purify.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/crypto-js.js
// @require      https://cdn.jsdelivr.net/npm/@mozilla/[email protected]/Readability.min.js
// @license MIT
// ==/UserScript==

(function () {
  "use strict";
  function md5(input) {
    return CryptoJS.MD5(input).toString();
  }
  let hrefHistory = [];

  // Function to get or initialize global state
  function getGlobalState(key, defaultValue) {
    return GM_getValue(key, defaultValue);
  }

  // Function to update global state
  function updateGlobalState(key, value) {
    GM_setValue(key, value);
  }

  // Function to get the endpoint
  function getEndpoint() {
    let endpoint = getGlobalState('endpoint', null);
    if (!endpoint) {
      endpoint = prompt("Please enter the endpoint URL:", "https://api.example.com/endpoint");
      if (endpoint) {
        updateGlobalState('endpoint', endpoint);
      } else {
        console.error("MemTrace: No endpoint provided. Script will not function correctly.");
      }
    }
    return endpoint;
  }

  // Function to change the endpoint
  function changeEndpoint() {
    let newEndpoint = prompt("Enter new endpoint URL:", getGlobalState('endpoint', ''));
    if (newEndpoint) {
      updateGlobalState('endpoint', newEndpoint);
      console.log("MemTrace: Endpoint updated to", newEndpoint);
    }
  }

  // Register menu command to change endpoint
  GM_registerMenuCommand("Change MemTrace Endpoint", changeEndpoint);

  function process() {
    const url = window.location.href.split("#")[0];
    if (hrefHistory.includes(url)) {
      return;
    }
    console.log("MemTrace: processing url", url);
    hrefHistory.push(url);
    const article = new Readability(document.cloneNode(true)).parse().content;
    console.log("article", article)

    const turndownService = new TurndownService({
      keepReplacement: function (content, node) {
        return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML;
      }
    });

    // Add a rule to keep tables
    turndownService.addRule('tables', {
      filter: ['table'],
      replacement: function (content, node) {
        return node.outerHTML;
      }
    });

    // Uncomment the following line if you want to use the GFM table plugin instead
    // turndownService.use(turndownPluginGfm.tables);

    let markdown = turndownService.turndown(article);
    if (markdown.length < 100) {
      console.log("MemTrace: fail to parse page");
      return;
    }
    let data = {
      title: document.title,
      source: "chrome",
      id: md5(url),
      markdown: markdown,
      url: url,
    };
    console.log("MemTrace: saving page", data);
    GM_xmlhttpRequest({
      method: "POST",
      url: getEndpoint(),
      data: JSON.stringify(data),
      headers: {
        "Content-Type": "application/json",
      },
      onload: function (response) {
        if (response.status === 200) {
          console.log("MemTrace: saved page");
        } else {
          console.error("Failed to save to MemTrace", response.responseText);
        }
      },
      onerror: function (error) {
        console.error("Request failed:", error);
      },
    });
  }
  window.addEventListener("load", function () {
    if (window.self === window.top) {
      setTimeout(() => {
        process();
      }, 5000);
    }
  });
})();