撰于 阅读 22

obsidian 写 typecho 博客,上传图片到 lsky pro 图床

1. 先安装插件 Python Scripter

2 .

3. 脚本放入文件夹

C:\Users\Administrator\Documents\Obsidian Vault\.obsidian\scripts\python
import xmlrpc.client
import os
import sys
import io 
import re
import requests
import hashlib
from config import *

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

# 用于存储已上传图片的字典
uploaded_images = {}

def get_lsky_token():
    response = requests.post(f"{LSKY_API_URL}/tokens", json={
        "email": LSKY_EMAIL,
        "password": LSKY_PASSWORD
    })
    if response.status_code == 200:
        data = response.json()
        if data['status']:
            return data['data']['token']
    print(f"获取Lsky Pro token失败: {response.text}")
    return None

def get_file_md5(file_path):
    hash_md5 = hashlib.md5()
    with open(file_path, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()

def upload_image_to_lsky(image_path, token):
    if not os.path.isfile(image_path):
        print(f"图片文件不存在或不是文件: {image_path}")
        return None

    file_md5 = get_file_md5(image_path)
    if file_md5 in uploaded_images:
        print(f"图片已上传过: {uploaded_images[file_md5]}")
        return uploaded_images[file_md5]

    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "application/json"
    }
    print(f"尝试上传图片: {image_path}")
    try:
        with open(image_path, 'rb') as image_file:
            files = {'file': image_file}
            response = requests.post(f"{LSKY_API_URL}/upload", headers=headers, files=files)
        
        if response.status_code == 200:
            data = response.json()
            if data['status']:
                url = data['data']['links']['url']
                uploaded_images[file_md5] = url
                print(f"图片上传成功: {url}")
                return url
        print(f"上传图片失败: {response.text}")
    except Exception as e:
        print(f"上传图片时发生错误: {str(e)}")
    return None

def replace_image_links(content, vault_path, token):
    def replace_link(match):
        image_path = match.group(1)
        if image_path.startswith('http://') or image_path.startswith('https://'):
            return match.group(0)  # 如果是网络图片,不处理
        
        full_image_path = os.path.normpath(os.path.join(vault_path, image_path))
        print(f"处理图片路径: {full_image_path}")
        if os.path.isfile(full_image_path):
            new_url = upload_image_to_lsky(full_image_path, token)
            if new_url:
                return f"![]({new_url})"
        else:
            print(f"图片文件不存在或不是文件: {full_image_path}")
        return match.group(0)
    
    # 替换Obsidian双方括号图片链接
    content = re.sub(r'!\[\[(.*?)\]\]', replace_link, content)
    # 替换标准Markdown图片链接(保留以防万一)
    content = re.sub(r'!\[.*?\]\((.*?)\)', replace_link, content)
    return content

def get_post_id_by_title(client, username, password, title):
    recent_posts = client.metaWeblog.getRecentPosts("", username, password, 100)
    for post in recent_posts:
        if post['title'] == title:
            return post['postid']
    return None

# 打印所有命令行参数,用于调试
print("命令行参数:", sys.argv)

# 获取Lsky Pro token
lsky_token = get_lsky_token()
if not lsky_token:
    raise Exception("无法获取Lsky Pro token")

# 创建XML-RPC客户端
client = xmlrpc.client.ServerProxy(TYPECHO_API_URL)

# 获取当前编辑的文件内容
if len(sys.argv) > 2:
    vault_path = sys.argv[1]  # Obsidian保管库路径
    file_name = sys.argv[2]   # 文件名
    file_path = os.path.join(vault_path, file_name)
    print(f"尝试打开文件: {file_path}")
    
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            content = file.read()
        title = os.path.splitext(file_name)[0]
        
        print(f"文件内容读取成功,标题: {title}")
        print(f"Vault路径: {vault_path}")
        
        # 替换图片链接
        content = replace_image_links(content, vault_path, lsky_token)
    except IOError as e:
        print(f"无法打开文件: {e}")
        raise
else:
    raise Exception("无法获取当前文件信息")

# 创建博客文章结构
post = {
    "title": title,
    "description": content,
    "categories": ["Obsidian"],  # 可以根据需要修改分类
    "mt_keywords": "obsidian, markdown",  # 可以根据需要修改标签
}

try:
    # 检查文章是否已存在
    existing_post_id = get_post_id_by_title(client, TYPECHO_USERNAME, TYPECHO_PASSWORD, title)
    
    if existing_post_id:
        # 更新现有文章
        success = client.metaWeblog.editPost(existing_post_id, TYPECHO_USERNAME, TYPECHO_PASSWORD, post, True)
        if success:
            print(f"文章已成功更新,ID: {existing_post_id}")
        else:
            print("文章更新失败")
    else:
        # 发布新文章
        post_id = client.metaWeblog.newPost("", TYPECHO_USERNAME, TYPECHO_PASSWORD, post, True)
        print(f"新文章已成功发布,ID: {post_id}")
except xmlrpc.client.Fault as err:
    print(f"发布/更新失败: {err.faultString}")
except Exception as e:
    print(f"发生错误: {str(e)}")

4. Config. Py 文件内容

# Lsky Pro API 配置
LSKY_API_URL = "https://域名/api/v1"
LSKY_EMAIL = ""
LSKY_PASSWORD = ""

# Typecho 配置
TYPECHO_API_URL = "https://域名/index.php/action/xmlrpc"
TYPECHO_USERNAME = ""
TYPECHO_PASSWORD = ""