Add editor version metadata
This commit is contained in:
@@ -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` 目录复制到其他电脑或服务器后,在该目录里安装依赖:
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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="审校模式">
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
version = "0.2.0"
|
||||
|
||||
VERSION_RULES = {
|
||||
"PATCH": "修复 bug 或兼容性小修",
|
||||
"MINOR": "新增向后兼容能力、API 字段或可选配置",
|
||||
"MAJOR": "破坏兼容的 API、配置或行为变更",
|
||||
}
|
||||
Reference in New Issue
Block a user