joplin-publisher
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseJoplin Publisher Skill
Joplin 内容发布技能
Purpose
用途
Import markdown documents and mermaid diagrams into Joplin using the Joplin CLI.
使用Joplin CLI将Markdown文档和Mermaid图表导入Joplin。
When to Use
适用场景
- Exporting research to Joplin notebooks
- Creating documentation in Joplin
- Generating diagrams for Joplin knowledge base
- Syncing analysis results to Joplin
- 将研究内容导出到Joplin笔记本
- 在Joplin中创建文档
- 为Joplin知识库生成图表
- 将分析结果同步到Joplin
Overview
概述
Joplin uses a database-backed system. Content is imported via the Joplin CLI or API. This skill focuses on CLI-based imports.
Joplin采用基于数据库的系统。内容可通过Joplin CLI或API导入。本技能专注于基于CLI的导入方式。
Prerequisites
前置条件
Install Joplin CLI
安装Joplin CLI
bash
undefinedbash
undefinedUsing npm
使用npm安装
npm install -g joplin
npm install -g joplin
Verify installation
验证安装
joplin version
undefinedjoplin version
undefinedConfigure Joplin CLI
配置Joplin CLI
bash
undefinedbash
undefinedSet sync target (if needed)
设置同步目标(如有需要)
joplin config sync.target 2 # Filesystem
joplin config sync.2.path /path/to/sync/folder
joplin config sync.target 2 # 文件系统
joplin config sync.2.path /path/to/sync/folder
Or connect to Joplin Server/Cloud
或连接到Joplin Server/Cloud
joplin config sync.target 9
joplin config sync.9.path https://your-joplin-server.com
joplin config sync.9.username your-username
undefinedjoplin config sync.target 9
joplin config sync.9.path https://your-joplin-server.com
joplin config sync.9.username your-username
undefinedJoplin CLI Commands
Joplin CLI 命令
List Notebooks
列出笔记本
bash
joplin ls / # List top-level notebooks
joplin ls /Notebook # List notes in notebookbash
joplin ls / # 列出顶级笔记本
joplin ls /Notebook # 列出笔记本中的笔记Create Notebook
创建笔记本
bash
joplin mkbook "Notebook Name"
joplin mkbook "Parent/Child" # Nested notebookbash
joplin mkbook "Notebook Name"
joplin mkbook "Parent/Child" # 嵌套笔记本Import Markdown
导入Markdown
bash
undefinedbash
undefinedImport single file to notebook
将单个文件导入笔记本
joplin import /path/to/file.md --notebook "Notebook Name"
joplin import /path/to/file.md --notebook "Notebook Name"
Import directory
导入目录
joplin import /path/to/folder --notebook "Notebook Name"
joplin import /path/to/folder --notebook "Notebook Name"
Import with format specification
指定格式导入
joplin import /path/to/file.md --format md --notebook "Notebook Name"
undefinedjoplin import /path/to/file.md --format md --notebook "Notebook Name"
undefinedCreate Note Directly
直接创建笔记
bash
undefinedbash
undefinedCreate note from stdin
从标准输入创建笔记
echo "# Title
Content" | joplin mknote "Note Title" --notebook "Notebook Name"
echo "# Title
Content" | joplin mknote "Note Title" --notebook "Notebook Name"
Create from file content
从文件内容创建笔记
cat file.md | joplin mknote "Note Title" --notebook "Notebook Name"
undefinedcat file.md | joplin mknote "Note Title" --notebook "Notebook Name"
undefinedPublishing Workflow
发布工作流
Step 1: Validate Notebook Exists
步骤1:验证笔记本是否存在
python
import subprocess
def notebook_exists(notebook: str) -> bool:
"""Check if a Joplin notebook exists."""
result = subprocess.run(
["joplin", "ls", "/"],
capture_output=True,
text=True
)
notebooks = result.stdout.strip().split('
')
return notebook in notebooks
def create_notebook_if_missing(notebook: str):
"""Create notebook if it doesn't exist."""
if not notebook_exists(notebook):
subprocess.run(
["joplin", "mkbook", notebook],
check=True
)python
import subprocess
def notebook_exists(notebook: str) -> bool:
"""检查Joplin笔记本是否存在。"""
result = subprocess.run(
["joplin", "ls", "/"],
capture_output=True,
text=True
)
notebooks = result.stdout.strip().split('\n')
return notebook in notebooks
def create_notebook_if_missing(notebook: str):
"""如果笔记本不存在则创建。"""
if not notebook_exists(notebook):
subprocess.run(
["joplin", "mkbook", notebook],
check=True
)Step 2: Prepare Content
步骤2:准备内容
python
def prepare_markdown(
title: str,
content: str,
tags: list = None
) -> str:
"""
Prepare markdown content for Joplin import.
Joplin supports YAML frontmatter for metadata.
"""
lines = [f"# {title}", ""]
if tags:
lines.extend([
"---",
f"tags: {', '.join(tags)}",
"---",
""
])
lines.append(content)
return '
'.join(lines)python
def prepare_markdown(
title: str,
content: str,
tags: list = None
) -> str:
"""
准备用于Joplin导入的Markdown内容。
Joplin支持使用YAML前置元数据。
"""
lines = [f"# {title}", ""]
if tags:
lines.extend([
"---",
f"tags: {', '.join(tags)}",
"---",
""
])
lines.append(content)
return '\n'.join(lines)Step 3: Write Temporary File
步骤3:写入临时文件
python
import tempfile
from pathlib import Path
def write_temp_markdown(content: str, filename: str) -> Path:
"""Write content to a temporary markdown file."""
temp_dir = Path(tempfile.mkdtemp())
file_path = temp_dir / f"{filename}.md"
file_path.write_text(content, encoding='utf-8')
return file_pathpython
import tempfile
from pathlib import Path
def write_temp_markdown(content: str, filename: str) -> Path:
"""将内容写入临时Markdown文件。"""
temp_dir = Path(tempfile.mkdtemp())
file_path = temp_dir / f"{filename}.md"
file_path.write_text(content, encoding='utf-8')
return file_pathStep 4: Import to Joplin
步骤4:导入到Joplin
python
def import_to_joplin(
file_path: Path,
notebook: str
) -> bool:
"""Import markdown file to Joplin notebook."""
result = subprocess.run(
[
"joplin", "import",
str(file_path),
"--notebook", notebook
],
capture_output=True,
text=True
)
if result.returncode != 0:
raise JoplinImportError(f"Import failed: {result.stderr}")
return Truepython
def import_to_joplin(
file_path: Path,
notebook: str
) -> bool:
"""将Markdown文件导入Joplin笔记本。"""
result = subprocess.run(
[
"joplin", "import",
str(file_path),
"--notebook", notebook
],
capture_output=True,
text=True
)
if result.returncode != 0:
raise JoplinImportError(f"导入失败: {result.stderr}")
return TrueComplete Publishing Function
完整发布函数
python
def publish_to_joplin(
notebook: str,
title: str,
content: str,
tags: list = None
) -> bool:
"""
Publish markdown content to a Joplin notebook.
Args:
notebook: Target notebook name
title: Note title
content: Markdown content (can include mermaid)
tags: Optional list of tags
Returns:
True if successful
"""
# Ensure notebook exists
create_notebook_if_missing(notebook)
# Prepare content
full_content = prepare_markdown(title, content, tags)
# Write to temp file
temp_file = write_temp_markdown(full_content, title)
try:
# Import to Joplin
import_to_joplin(temp_file, notebook)
return True
finally:
# Cleanup
temp_file.unlink()
temp_file.parent.rmdir()python
def publish_to_joplin(
notebook: str,
title: str,
content: str,
tags: list = None
) -> bool:
"""
将Markdown内容发布到Joplin笔记本。
参数:
notebook: 目标笔记本名称
title: 笔记标题
content: Markdown内容(可包含Mermaid代码)
tags: 可选标签列表
返回:
成功则返回True
"""
# 确保笔记本存在
create_notebook_if_missing(notebook)
# 准备内容
full_content = prepare_markdown(title, content, tags)
# 写入临时文件
temp_file = write_temp_markdown(full_content, title)
try:
# 导入到Joplin
import_to_joplin(temp_file, notebook)
return True
finally:
# 清理临时文件
temp_file.unlink()
temp_file.parent.rmdir()Document Formats
文档格式
Basic Note
基础笔记
markdown
undefinedmarkdown
undefinedNote Title
笔记标题
Content goes here.
内容写在这里。
Section
章节
More content.
undefined更多内容。
undefinedNote with Tags
带标签的笔记
markdown
undefinedmarkdown
undefinedNote Title
笔记标题
Content here.
undefined内容在这里。
undefinedNote with Mermaid
带Mermaid图表的笔记
Joplin supports mermaid diagrams natively in markdown:
markdown
undefinedJoplin原生支持在Markdown中使用Mermaid图表:
markdown
undefinedSystem Architecture
系统架构
mermaid
flowchart TD
A[Client] --> B[Server]
B --> C[(Database)]mermaid
flowchart TD
A[客户端] --> B[服务器]
B --> C[(数据库)]Description
说明
The system consists of...
undefined该系统由...组成
undefinedNotebook Organization
笔记本组织方式
Flat Structure
扁平结构
Notebooks/
├── Research
├── Projects
├── Meetings
└── ArchiveNotebooks/
├── 研究
├── 项目
├── 会议
└── 归档Nested Structure
嵌套结构
Notebooks/
├── Work/
│ ├── Project Alpha
│ └── Project Beta
├── Personal/
│ ├── Notes
│ └── Ideas
└── Archive/Create nested notebooks:
bash
joplin mkbook "Work"
joplin mkbook "Work/Project Alpha"Notebooks/
├── 工作/
│ ├── Alpha项目
│ └── Beta项目
├── 个人/
│ ├── 笔记
│ └── 想法
└── 归档/创建嵌套笔记本:
bash
joplin mkbook "Work"
joplin mkbook "Work/Project Alpha"Usage Examples
使用示例
Publish Research Note
发布研究笔记
python
publish_to_joplin(
notebook="Research",
title="API Design Patterns",
content="""python
publish_to_joplin(
notebook="Research",
title="API设计模式",
content="""Overview
概述
Key findings from API design research.
API设计研究的关键发现。
REST Best Practices
REST最佳实践
- Use nouns for resources
- Use HTTP methods correctly
- Version your API
- 对资源使用名词
- 正确使用HTTP方法
- 为API添加版本
GraphQL Considerations
GraphQL注意事项
- Schema-first design
- Query optimization """, tags=["api", "research", "design"] )
undefined- 优先采用Schema-first设计
- 查询优化 """, tags=["api", "research", "design"] )
undefinedPublish Diagram
发布图表
python
publish_to_joplin(
notebook="Architecture",
title="System Overview Diagram",
content="""python
publish_to_joplin(
notebook="Architecture",
title="系统概览图",
content="""Architecture Diagram
架构图
mermaid
flowchart TB
subgraph Frontend
A[Web App]
B[Mobile App]
end
subgraph Backend
C[API Server]
D[Worker]
end
subgraph Data
E[(PostgreSQL)]
F[(Redis)]
end
A --> C
B --> C
C --> E
C --> F
D --> Emermaid
flowchart TB
subgraph 前端
A[Web应用]
B[移动应用]
end
subgraph 后端
C[API服务器]
D[工作节点]
end
subgraph 数据层
E[(PostgreSQL)]
F[(Redis)]
end
A --> C
B --> C
C --> E
C --> F
D --> EComponents
组件说明
| Component | Technology | Purpose |
|---|---|---|
| Web App | React | User interface |
| API Server | FastAPI | REST API |
| Worker | Celery | Background jobs |
| """, |
tags=["architecture", "diagram"])
undefined| 组件 | 技术栈 | 用途 |
|---|---|---|
| Web应用 | React | 用户界面 |
| API服务器 | FastAPI | REST API |
| 工作节点 | Celery | 后台任务 |
| """, |
tags=["architecture", "diagram"])
undefinedPublish Meeting Notes
发布会议笔记
python
publish_to_joplin(
notebook="Meetings/2024",
title="Project Sync - Jan 15",
content="""python
publish_to_joplin(
notebook="Meetings/2024",
title="项目同步会 - 1月15日",
content="""Attendees
参会人员
- Alice
- Bob
- Charlie
- 爱丽丝
- 鲍勃
- 查理
Agenda
议程
- Sprint review
- Blockers
- Next steps
- 迭代回顾
- 阻塞问题
- 下一步计划
Notes
会议记录
Sprint Review
迭代回顾
- Feature X completed
- Bug Y in progress
- 功能X已完成
- 漏洞Y处理中
Blockers
阻塞问题
- Waiting on API access
- 等待API访问权限
Action Items
行动项
- Alice: Follow up on API access
- Bob: Complete bug fix
- Charlie: Update documentation """, tags=["meeting", "project-alpha"] )
undefined- 爱丽丝:跟进API访问权限
- 鲍勃:完成漏洞修复
- 查理:更新文档 """, tags=["meeting", "project-alpha"] )
undefinedBatch Import
批量导入
For importing multiple documents:
python
def batch_import(
notebook: str,
documents: list[dict]
) -> dict:
"""
Import multiple documents to Joplin.
Args:
notebook: Target notebook
documents: List of {title, content, tags} dicts
Returns:
{success: int, failed: int, errors: list}
"""
results = {"success": 0, "failed": 0, "errors": []}
for doc in documents:
try:
publish_to_joplin(
notebook=notebook,
title=doc["title"],
content=doc["content"],
tags=doc.get("tags", [])
)
results["success"] += 1
except Exception as e:
results["failed"] += 1
results["errors"].append({
"title": doc["title"],
"error": str(e)
})
return results如需导入多个文档:
python
def batch_import(
notebook: str,
documents: list[dict]
) -> dict:
"""
将多个文档导入Joplin。
参数:
notebook: 目标笔记本
documents: 包含{title, content, tags}的字典列表
返回:
{success: 成功数量, failed: 失败数量, errors: 错误列表}
"""
results = {"success": 0, "failed": 0, "errors": []}
for doc in documents:
try:
publish_to_joplin(
notebook=notebook,
title=doc["title"],
content=doc["content"],
tags=doc.get("tags", [])
)
results["success"] += 1
except Exception as e:
results["failed"] += 1
results["errors"].append({
"title": doc["title"],
"error": str(e)
})
return resultsError Handling
错误处理
python
class JoplinError(Exception):
"""Base exception for Joplin operations."""
pass
class JoplinNotInstalledError(JoplinError):
"""Joplin CLI not found."""
pass
class JoplinImportError(JoplinError):
"""Failed to import content."""
pass
class NotebookNotFoundError(JoplinError):
"""Notebook does not exist."""
pass
def check_joplin_installed():
"""Verify Joplin CLI is available."""
result = subprocess.run(
["joplin", "version"],
capture_output=True
)
if result.returncode != 0:
raise JoplinNotInstalledError(
"Joplin CLI not found. Install with: npm install -g joplin"
)python
class JoplinError(Exception):
"""Joplin操作的基础异常类。"""
pass
class JoplinNotInstalledError(JoplinError):
"""未找到Joplin CLI。"""
pass
class JoplinImportError(JoplinError):
"""内容导入失败。"""
pass
class NotebookNotFoundError(JoplinError):
"""笔记本不存在。"""
pass
def check_joplin_installed():
"""验证Joplin CLI是否可用。"""
result = subprocess.run(
["joplin", "version"],
capture_output=True
)
if result.returncode != 0:
raise JoplinNotInstalledError(
"未找到Joplin CLI。请使用以下命令安装:npm install -g joplin"
)Joplin API Alternative
Joplin API 替代方案
For more control, use the Joplin Data API:
python
import requests
class JoplinAPI:
def __init__(self, token: str, port: int = 41184):
self.base_url = f"http://localhost:{port}"
self.token = token
def create_note(
self,
title: str,
body: str,
parent_id: str = None
) -> dict:
"""Create a note via Joplin API."""
response = requests.post(
f"{self.base_url}/notes",
params={"token": self.token},
json={
"title": title,
"body": body,
"parent_id": parent_id
}
)
response.raise_for_status()
return response.json()Enable the API in Joplin Desktop: Options → Web Clipper → Enable
如需更多控制,可使用Joplin数据API:
python
import requests
class JoplinAPI:
def __init__(self, token: str, port: int = 41184):
self.base_url = f"http://localhost:{port}"
self.token = token
def create_note(
self,
title: str,
body: str,
parent_id: str = None
) -> dict:
"""通过Joplin API创建笔记。"""
response = requests.post(
f"{self.base_url}/notes",
params={"token": self.token},
json={
"title": title,
"body": body,
"parent_id": parent_id
}
)
response.raise_for_status()
return response.json()在Joplin桌面端启用API:选项 → 网页剪辑器 → 启用
Checklist
检查清单
Before publishing:
- Joplin CLI is installed and configured
- Target notebook exists or will be created
- Content is valid markdown
- Mermaid diagrams use correct syntax
- Tags are properly formatted
- Sync is configured (if using cloud/server)
发布前请确认:
- Joplin CLI已安装并配置完成
- 目标笔记本已存在或会自动创建
- 内容为合法的Markdown格式
- Mermaid图表语法正确
- 标签格式正确
- 已配置同步(如使用云端/服务器)