木木困玉光

Eagle外链增强


Tags: #软件
Created:
Updated:

前言

花费半天时间,将之前的一个小开发想法落地,作为本月博文分享给大家下

本篇博文仅适用于Eagle用户,非Eagle用户可以直接退出了
但好像更适用于Eagle+开发用户?😑,得,估计Eagle用户看也懵

先了解下前因后果

Eagle软件本身支持文件外链,例如:eagle://item/LT119HK340IHU
通过外链可以直接快速从其他使用Eagle打开指定文件

例如,我有张莲花山的图

image-20240726195824579

复制链接,外链是eagle://item/LT119HK30UGE3,如果在Obsidian或者其他地方点击这个超链接
那么就能迅速打开Eagle跳转到这张图片

Egale外链示例

这种外链在引用文件的时候非常非常便捷,尤其是Eagle2.0之后增加更多的格式支持后,可以说就是个万能的资源管理器

我通常使用Eagle作为Obsidian的外部资源拓展,例如视频笔记,例如书签管理

但是其中有个痛点,外链是没办法跨资源库的
Eagle可以创建多个资源库,例如我网站书签放一个资源库,音乐放一个资源库,图片放一个….

我在A资源库复制了文件外链,Eagle处于其他资源库(B、C、D等)的时候,这个文件外链是没办法达成上面效果(直达文件),外链只能打开Eagle而已,失去了直达的效果

这种只能自己手动先切换Eagle资源库成这个文件所在的资源库,再点击链接才有效
可以说是很难受,这个就是外链使用过程中遇到的痛点😕

毕竟多个资源库是不可避免的,于是就想到替代协议,想法落地,就有了本篇

思路

Eagle的外链eagle://item/LT119HK30UGE3是自定义协议,那么就是通过注册表注册的
打开注册表,在HKEY_CLASSES_ROOT下搜索Eagle,果然有

定位:\HKEY_CLASSES_ROOT\eagle\shell\open\command

image-20240726201338625

可以发现就是将%1也就是外链eagle://item/LT119HK30UGE3传递给Eagle.exe进行打开而已

那么我的思路就是我直接开发个脚本,替换掉注册表中的Eagle.exe
这样每次点击外链,则运行的是我开发的脚本

脚本中实现的逻辑

  1. 接受参数(文件外链)
  2. 去查找这个文件是处于哪个资源库
  3. 使用 API 切换成对应资源库
  4. 模拟系统命令,向Eagle软件发送外链,实现直达文件

想法如上,开始落地

参考资料

  1. # Eagle - 图片收集及管理必备工具:Eagle 软件,这里安利一波,五星好评😘😘
  2. # Eagle API 官方文档:Eagle 官方的 API 文档,好的软件必备👍👍
  3. # Eagle 媒体资源包:图标资源,用于打包时候使用

代码讲解

接受参数

使用sys.argv接受外链参数即可

url = sys.argv[1]

查找文件

原先使用Eagle的 API查找,但发现效率不如直接使用 os 模块的路径判断,所以改用 os

Eagle一个资源库的所有文件是在其资源库下的images文件夹中,每个文件有个对应id的文件夹

image-20240726202509878

直接使用os.path.exist()进行判断文件是否在这个资源库即可
举例:

外链是eagle://item/LT119HK30UGE3,提取文件id(LT119HK30UGE3
那么使用os.path.exist()判断该资源库下是否有这个文件夹,就可以知道是处于哪个资源库中了

我个人是所有资源库放在D盘,直接提取所有资源库的名称,进行遍历所有资源库即可

示例代码

# 读取所有资源库名称
library_list = [i for i in os.listdir("D:/Software") if i.endswith(".library")]

for library in library_list:
    path = f"D:/Software/{library}/images/{item}.info"
    if os.path.exists(path):
        pass

切换对应资源库

使用Eagle的API就能将Eagle软件切换到对应资源库,API文档具体看参考资料

def switch_library(library_name):
    # 数据字典
    data = {
        "libraryPath": f"D:/Software/{library_name}",
    }

    # 请求选项
    url = "http://localhost:41595/api/library/switch"
    headers = {
        "Content-Type": "application/json",
        "Accept": "application/json",
    }

    # 将数据字典转换为JSON格式的字符串
    json_data = json.dumps(data)

    # 发送POST请求
    response = requests.post(url, headers=headers, data=json_data)

    # 检查请求是否成功
    if response.ok:
        # 解析JSON响应
        result = response.json()
        print(result)
    else:
        print(f"Request failed with status code: {response.status_code}")

    # 处理可能发生的异常
    try:
        # 可以尝试再次解析JSON响应
        result = response.json()
        print(result)
    except json.JSONDecodeError as error:
        print(f"Error decoding JSON: {error}")

直达

模拟Eagle注册表中的写法,也就是将外链发送给Eagle即可
这里使用subprocess模块运行系统命令

# 定义Eagle执行文件的路径
eagle_exe = "D:/Software/Eagle/Eagle.exe"

# 定义要打开的Eagle链接
eagle_link = "eagle://item/LT119HK340IHU"

# 构建命令
command = f'"{eagle_exe}" --allow-file-access-from-files "{eagle_link}"'

# 使用subprocess.run执行命令
subprocess.run(command, shell=True)

完整代码

将上面的所有功能拼凑起来,实现完整的代码逻辑
注:目前仅适用于个人使用,仅供参考,不要直接运行,是无效果的

import json
import os
import subprocess
import sys

import requests
from win10toast import ToastNotifier

def switch_library(library_name):
    """切换资源库
    @param str library_name: 资源库名称
    """    
    data = {
        "libraryPath": f"D:/Software/{library_name}",
    }
    url = "http://localhost:41595/api/library/switch"
    headers = {
        "Content-Type": "application/json",
        "Accept": "application/json",
    }

    # 转换为JSON格式的字符串
    json_data = json.dumps(data)
    response = requests.post(url, headers=headers, data=json_data)

    # 检查请求
    if response.ok:
        result = response.json()
        print(result)
    else:
        print(f"Request failed with status code: {response.status_code}")

    try:
        # 尝试再次解析JSON响应
        result = response.json()
        print(result)
    except json.JSONDecodeError as error:
        print(f"Error decoding JSON: {error}")


def send_notification(title, message):
    """弹窗提示
    @param str title: 弹窗标题
    @param str message: 弹窗备注
    """    
    toaster = ToastNotifier()
    toaster.show_toast(title, message, duration=3)

def main():
    """主函数"""

    if len(sys.argv) > 1:

        
        eagle_exe = "D:/Software/Eagle/Eagle.exe"  # 定义Eagle执行文件的路径
        eagle_link = sys.argv[1]  # 定义要打开的Eagle链接
        command = f'"{eagle_exe}" --allow-file-access-from-files "{eagle_link}"' # 构建命令

        item = eagle_link.replace("eagle://item/", "")
        result_lib = None  # 待切换成的资源库

        # 读取所有资源库名称
        library_list = [i for i in os.listdir("D:/Software") if i.endswith(".library")]

        for library in library_list:
            path = f"D:/Software/{library}/images/{item}.info"
            if os.path.exists(path):
                result_lib = library
                break

        if result_lib:
            switch_library(result_lib)
            subprocess.run(command, shell=True)

            sys.exit(0)
        else:
            send_notification("Eagle 增强插件", "未找到文件")
            # print("未找到文件")


if __name__ == "__main__":
    main()

打包

注册表中是不能使用脚本的,只能是可执行文件.exe,所以我们需要将脚本打包成exe
emmm…,也许也可以?将脚本作为参数传递,再将%1作为参数传递给脚本
像这样"c:\Users\Lin-BLACKBOOK\AppData\Local\Programs\Python\Python310\python.exe" "D:\develop\Python\demo.py" "%1",也许可以,没尝试过

我这里是先打包,再使用

使用pyinstaller打包成单文件Eagle_enhance.exe
想要文件更小,可以使用pipenv创建个虚拟环境,能使文件小N多

pyinstaller -F -w -i "D:\systemLibrary\Desktop\Eagle\4.ico" Eagle_enhance.pyw

为了防止不小心删除,可以将打包后的Eagle_enhance.exe跟Eagle放一起

image-20240726204839703

使用方法

  1. 运行中输入regedit,打开注册表
  2. 定位:\HKEY_CLASSES_ROOT\eagle\shell\open\command
  3. 将项改成打包好的程序位置+空格+%1
    image-20240726204934424
  4. 点击外链,愉快玩耍~

后话

目前仅仅是一个适用个人的版本,会编程的直接改改就能用了
博客看的人还是少,博客+Eagle可能遇到的更加少,所以没有想浪费时间开发通用版的念头,虽然实际可能用不了多少时间

看看吧,如果有需要的朋友也可以留言,可以开发个适用全部人的通用版本程序,直接一键运行完成部署

吐槽个无语的,其实难度不大,开发应该非常快可以完成的,但中途陷入了无限死循环,搞的有点懵,算了,无力吐槽,有这时间刷视频不香吗

:D 获取中...