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 = ""