这次将介绍 Zotero 与 Excalidraw 的无缝连接,不需要借助 Quicker,而是通过自定义 Excalidraw 的脚本,直接拖拽 Zotero 的文本或者图片就可以实现 Zotero 到 Excalidraw 的笔记了,拖拽过来的包含注释和选择的内容

PS:本文使用的的是 Zotero 7,按理说 Zotero 6 也可以正常使用。

修改📌注释的文件路径

修改 [[#Zotero to Excalidraw 脚本]] 中的两个文件路径:

  • 第一个为 Zotero 的图形存储路径:Zotero 的标注图片一般在你定义的数据库的文件夹的cache->library下面:
  • 第二个就是你自定义拖拽过来的图片存放的存储路径了,注意要在 Obsidian 的笔记库中。

保存为 md 文件保存到指定文件夹

修改完路径后将下面代码保存为 md 文件,修改放入 Excalidraw 指定的 Scripts 的文件夹中,在 Excalidraw 的画板中的工具面板中就会出现一个齿轮按钮,需要时点击运行就可以了。

可以添加相同名称的SVG来给脚本一个图标

Zotero to Excalidraw 脚本

该脚本的中心思想就是通过拖拽的文本,定位到图片名,从而复制该图片到 OB 的笔记库中,并对拖拽的文本进行处理,去除多余的空格以及全角转半角,拆分为 zotero_txt、zotero_author、zotero_link、zotero_comment、zotero_image 这 5 个文本,自定义组合:

如果你是拖拽替他文本,该脚本可以帮你格式化处理一下的

文档原链接:自定义 Excalidraw 脚本:实现 Zotero 与 Excalidraw 的拖拽联动

function processText(text) {
    // 替换英文之间的多个空格为一个空格
    text = text.replace(/([a-zA-Z])([\u4e00-\u9fa5])/g, '$1 $2');
    // 删除中文之间的空格
    text = text.replace(/([\u4e00-\u9fa5])\s+([\u4e00-\u9fa5])/g, '$1$2');
    text = text.replace(/([\u4e00-\u9fa5])\s+/g, '$1');
    text = text.replace(/\s+([\u4e00-\u9fa5])/g, '$1');
    // 将全角字符转换为半角字符
    text = text.replace(/[\uFF01-\uFF5E]/g, function (match) { return String.fromCharCode(match.charCodeAt(0) - 65248); });

    // // 在中英文之间添加空格
    // text = text.replace(/([\u4e00-\u9fa5])([a-zA-Z])/g, '$1 $2');
    // text = text.replace(/([a-zA-Z])([\u4e00-\u9fa5])/g, '$1 $2');

    return text;
}

function match_zotero_txt(text) {
    const regex = /“(.*)” \(/;
    const matches = text.match(regex);
    return matches ? matches[1] : "";
}

function match_zotero_author(text) {
    const regex = /\(\[(.*\d+)]\(/;
    const matches = text.match(regex);
    return matches ? matches[1] : "";
}

function match_zotero_link(text) {
    const regex = /\[pdf\]\((.*)\)\)/;
    const matches = text.match(regex);
    return matches ? matches[1] : "";
}

function match_zotero_comment(text) {
    const regex = /\)\)([^ ].*)/;
    const matches = text.match(regex);
    return matches ? matches[1] : "";
}

function match_zotero_image(text) {
    const regex = /annotation=(\w*)/;
    const matches = text.match(regex);
    return matches ? matches[1] : "";
}

const path = require('path');
const fs = require("fs");

let api = ea.getExcalidrawAPI();
let el = ea.targetView.containerEl.querySelectorAll(".excalidraw-wrapper")[0];

el.ondrop = async function (event) {
    console.log("ondrop");
    event.preventDefault();
    let insert_txt = event.dataTransfer.getData("Text");

    // 清空原本投入的文本
    event.stopPropagation();
    ea.clear();
    // 格式化文本(去空格、全角转半角)  

    insert_txt = processText(insert_txt)

    if (insert_txt.includes("zotero://")) {
        console.log("Zotero");

        zotero_txt = match_zotero_txt(insert_txt);
        zotero_author = match_zotero_author(insert_txt);
        if (zotero_author) {
            zotero_author = `(${zotero_author})`;
        };
        zotero_comment = match_zotero_comment(insert_txt);
        if (zotero_comment) {
            zotero_comment = `\n\n📝:${zotero_comment}`;
        };
        zotero_link = match_zotero_link(insert_txt);

        if (zotero_txt) {
            console.log("ZoteroText");
            let id = await ea.addText(0, 0, `📖:${zotero_txt}${zotero_author}${zotero_comment}`, { width: 600, box: true, wrapAt: 50, textAlign: "left", textVerticalAlign: "middle", box: "box" });
            let el = ea.getElement(id);
            el.link = zotero_link;
            await ea.addElementsToView(true, false, false);
            if (ea.targetView.draginfoDiv) {
                document.body.removeChild(ea.targetView.draginfoDiv);
                delete ea.targetView.draginfoDiv;
            };
        } else {
            console.log("ZoteroImage");
            zotero_image = match_zotero_image(insert_txt);
            zotero_image_name = `${zotero_image}.png`;

            // 📌修改到Zotero的library文件夹
            zotero_image_path = `D:\\Zotero\\cache\\library\\${zotero_image}.png`;
            // 📌定义附件保存的地址,修改到你定义的笔记文件夹
            let Obsidian_image_Path = `D:\\PandaNotes\\Y-图形文件存储\\ZoteroImages\\${zotero_image}.png`

            // 复制zotero的图片到Obsidian的笔记库
            fs.copyFileSync(zotero_image_path, Obsidian_image_Path);

            await new Promise((resolve) => setTimeout(resolve, 300)); // 暂停0.3秒,等待复制文件的过程

            let id = await ea.addImage(0, 0, zotero_image_name);
            let el = ea.getElement(id);
            el.link = zotero_link;
            await ea.addElementsToView(true, false, false);
            if (ea.targetView.draginfoDiv) {
                document.body.removeChild(ea.targetView.draginfoDiv);
                delete ea.targetView.draginfoDiv;
            };
        };

    } else {
        let id = await ea.addText(0, 0, `${insert_txt} `, { width: 400, box: true, wrapAt: 50, textAlign: "left", textVerticalAlign: "middle", box: "box" });
        let el = ea.getElement(id);
        await ea.addElementsToView(true, false, false);
        if (ea.targetView.draginfoDiv) {
            document.body.removeChild(ea.targetView.draginfoDiv);
            delete ea.targetView.draginfoDiv;
        };

    };
};