Add editor version metadata

This commit is contained in:
xin61
2026-07-06 21:37:34 +08:00
parent 7da060f827
commit c14e3cb3d8
6 changed files with 68 additions and 1 deletions
+14
View File
@@ -1,7 +1,21 @@
# 双语 EPUB 审校编辑器
当前版本:`0.2.0`
这个工具用于把生成后的中日双语 EPUB 打开成浏览器审校界面。用户可以直接修改中文译文,也可以标记“哪里翻得不好”,并把所有记录沉淀为可交给 Codex 的反馈文件。
## 版本规则
维护版本号使用 `version = "0.1.0"` 这种语义化格式:
| 层级 | 触发条件 |
| --- | --- |
| PATCH | 修复 bug 或兼容性小修 |
| MINOR | 新增向后兼容能力、API 字段或可选配置 |
| MAJOR | 破坏兼容的 API、配置或行为变更 |
本次从 `0.1.0` 升到 `0.2.0`,因为新增了独立上传、会话管理、下载接口与可选 `--host` 配置,且保持原命令行 EPUB 路径用法兼容。
## 独立安装
这个审校器现在可以脱离 Codex 使用,只需要 Python 和浏览器。把 `tools/epub_review_editor` 目录复制到其他电脑或服务器后,在该目录里安装依赖:
+24
View File
@@ -27,6 +27,16 @@ import xml.etree.ElementTree as ET
from flask import Flask, jsonify, request, send_from_directory
try:
from version import VERSION_RULES, version
except ImportError:
VERSION_RULES = {
"PATCH": "修复 bug 或兼容性小修",
"MINOR": "新增向后兼容能力、API 字段或可选配置",
"MAJOR": "破坏兼容的 API、配置或行为变更",
}
version = "0.2.0"
P_RE = re.compile(r"(<p\b[^>]*>)(.*?)(</p>)", re.S | re.I)
TAG_RE = re.compile(r"<[^>]+>")
@@ -306,6 +316,7 @@ def summarize_session(session_root: Path) -> dict[str, Any]:
updated_at = state.get("updated_at") or manifest.get("updated_at") or ""
return {
"id": session_public_id(session_root),
"version": version,
"source_name": source_name,
"source_epub": source_epub,
"session_root": str(session_root),
@@ -942,6 +953,7 @@ def create_app(review_root: Path, initial_epub_path: Path | None = None, reset:
)
review_root.mkdir(parents=True, exist_ok=True)
app.config["REVIEW_ROOT"] = review_root
app.config["APP_VERSION"] = version
app.config["SESSION_ROOT"] = None
app.config["EPUB_PATH"] = None
app.config["LOCK"] = threading.Lock()
@@ -962,6 +974,8 @@ def create_app(review_root: Path, initial_epub_path: Path | None = None, reset:
return jsonify(
{
"has_session": False,
"version": version,
"version_rules": VERSION_RULES,
"error": "尚未打开 EPUB。请先上传中日双语 EPUB,或从已有会话中选择一个。",
"review_root": str(review_root),
}
@@ -983,6 +997,8 @@ def create_app(review_root: Path, initial_epub_path: Path | None = None, reset:
return jsonify(
{
"has_session": False,
"version": version,
"version_rules": VERSION_RULES,
"review_root": str(review_root),
"sessions": list_review_sessions(review_root),
}
@@ -993,6 +1009,8 @@ def create_app(review_root: Path, initial_epub_path: Path | None = None, reset:
return jsonify(
{
"has_session": True,
"version": version,
"version_rules": VERSION_RULES,
"id": session_public_id(session_root),
"source_name": manifest.get("source_name") or epub_path.name,
"source_epub": str(epub_path),
@@ -1005,12 +1023,18 @@ def create_app(review_root: Path, initial_epub_path: Path | None = None, reset:
}
)
@app.route("/api/version")
def api_version():
return jsonify({"version": version, "version_rules": VERSION_RULES})
@app.route("/api/sessions")
def api_sessions():
session_root, _epub_path = active_session()
return jsonify(
{
"review_root": str(review_root),
"version": version,
"version_rules": VERSION_RULES,
"active_session_id": session_public_id(session_root) if session_root else "",
"sessions": list_review_sessions(review_root),
}
+8
View File
@@ -16,6 +16,7 @@ const $ = (id) => document.getElementById(id);
const dom = {
startScreen: $("startScreen"),
reviewLayout: $("reviewLayout"),
appVersion: $("appVersion"),
sessionMeta: $("sessionMeta"),
readingModeBtn: $("readingModeBtn"),
polishModeBtn: $("polishModeBtn"),
@@ -165,6 +166,11 @@ function setShellMode(active) {
}
}
function setVersionBadge(value) {
if (!value) return;
dom.appVersion.textContent = `v${value}`;
}
function formatDateTime(value) {
if (!value) return "";
const date = new Date(value);
@@ -205,6 +211,7 @@ function renderSessions(sessions = [], activeId = "") {
async function refreshSessions() {
const data = await api("/api/sessions");
setVersionBadge(data.version);
renderSessions(data.sessions || [], data.active_session_id || "");
}
@@ -297,6 +304,7 @@ function scopeVisibleRows() {
async function loadSession() {
const session = await api("/api/session");
setVersionBadge(session.version);
if (!session.has_session) {
await showStartScreen(session);
return session;
+1 -1
View File
@@ -9,7 +9,7 @@
<body>
<header class="topbar">
<div class="brandBlock">
<h1>双语 EPUB 审校编辑器</h1>
<h1>双语 EPUB 审校编辑器 <span id="appVersion" class="versionBadge">v0.2.0</span></h1>
<p id="sessionMeta">正在载入……</p>
</div>
<div class="modeTabs" role="tablist" aria-label="审校模式">
+14
View File
@@ -58,6 +58,20 @@ h1 {
font-weight: 700;
}
.versionBadge {
display: inline-flex;
align-items: center;
min-height: 20px;
margin-left: 6px;
padding: 0 6px;
border-radius: 6px;
background: #e8edf2;
color: var(--muted);
font-size: 12px;
font-weight: 600;
vertical-align: middle;
}
#sessionMeta {
margin: 2px 0 0;
color: var(--muted);
+7
View File
@@ -0,0 +1,7 @@
version = "0.2.0"
VERSION_RULES = {
"PATCH": "修复 bug 或兼容性小修",
"MINOR": "新增向后兼容能力、API 字段或可选配置",
"MAJOR": "破坏兼容的 API、配置或行为变更",
}