refine fonts and language support

This commit is contained in:
Your Name 2026-01-19 23:54:04 +08:00
parent 6933f5cc75
commit e792dfedf1
10 changed files with 1365 additions and 65 deletions

33
.github/ISSUE_TEMPLATE/upstream-sync.md vendored Normal file
View file

@ -0,0 +1,33 @@
---
name: Upstream Sync Report
about: Auto-generated report for upstream sync
title: '🔄 Upstream Sync: {{ date | date("YYYY-MM-DD") }}'
labels: upstream-sync, automated
assignees: ""
---
## 🔄 Upstream 自動同步報告
**同步日期:** {{ date }}
**新 Commits:** {{ commit_count }}
### 📝 變更摘要
```
{{ commits_list }}
```
### 🐳 Docker Image
- **Tag:** `upstream-{{ date_tag }}`
- **Smoke Test:** {{ smoke_test_status }}
### ⏳ 後續動作
- [ ] 檢視變更內容
- [ ] 確認 smoke test 結果
- [ ] 決定是否 merge 到 main
---
_此 Issue 由 GitHub Actions 自動建立_

280
.github/UPSTREAM_SYNC.md vendored Normal file
View file

@ -0,0 +1,280 @@
# 🔄 Upstream 自動同步機制
本專案實作了完整的 upstream 自動同步、變更追蹤與 smoke test 機制。
## 📋 目錄
- [功能概述](#功能概述)
- [工作流程圖](#工作流程圖)
- [Workflow 說明](#workflow-說明)
- [Smoke Test 內容](#smoke-test-內容)
- [設定說明](#設定說明)
- [手動操作](#手動操作)
---
## 功能概述
### 1⃣ 自動同步 Upstream
| 功能 | 說明 |
| ---------- | ---------------------------- |
| 觸發方式 | 每 6 小時自動檢查 / 手動觸發 |
| 同步目標 | `dev` 分支 |
| Merge 策略 | 自動 merge無衝突時 |
| 衝突處理 | 自動建立 GitHub Issue 通知 |
### 2⃣ 變更摘要
同步完成後自動產生:
- ✅ GitHub Issue詳細變更記錄
- ✅ `upstream-changelog.md`(累積變更歷史)
- ✅ GitHub Actions Summary快速查看
### 3⃣ Smoke Test
| 測試項目 | 內容 | 時間限制 |
| -------------- | -------------------------------------- | ------------- |
| Container 啟動 | 驗證 image 可正常啟動 | 60s |
| 工具檢查 | libreoffice, pandoc, ffmpeg, tesseract | 30s |
| 最小轉換 | txt → pdf | 60s |
| API 端點 | healthcheck, root | 10s |
| **總計** | | **< 10 分鐘** |
---
## 工作流程圖
```
┌─────────────────────────────────────────────────────────────────────────┐
│ Upstream 自動同步流程 │
└─────────────────────────────────────────────────────────────────────────┘
┌──────────────┐
│ Upstream │
│ (C4illin/ │
│ ConvertX) │
└──────┬───────┘
│ 每 6 小時檢查
┌──────────────┐ 無更新 ┌──────────────┐
│ 檢查是否有 │ ─────────────► │ 結束 │
│ 新 commits │ └──────────────┘
└──────┬───────┘
│ 有更新
┌──────────────┐ 衝突 ┌──────────────┐
│ 自動 Merge │ ─────────────► │ 建立 Issue │
│ 到 dev 分支 │ │ 需手動處理 │
└──────┬───────┘ └──────────────┘
│ 成功
┌──────────────┐
│ 產生變更摘要 │
│ • Issue │
│ • Changelog │
└──────┬───────┘
┌──────────────┐
│ Push 到 dev │
└──────┬───────┘
│ 觸發 upstream-sync.yml
┌──────────────┐
│ Build 測試 │
│ Image (amd64)│
└──────┬───────┘
┌──────────────────────────────────────────────────┐
│ Smoke Test │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Container │ │ 工具 │ │ 轉換 │ │
│ │ 啟動 │ │ 檢查 │ │ 測試 │ │
│ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ │ │
└───────────────────────┼──────────────────────────┘
┌─────────────┴─────────────┐
│ │
▼ ▼
┌────────────┐ ┌────────────┐
│ ✅ 通過 │ │ ❌ 失敗 │
└─────┬──────┘ └─────┬──────┘
│ │
▼ ▼
┌────────────┐ ┌────────────┐
│ Build 並 │ │ Workflow │
│ Push 到 │ │ 失敗 │
│ Docker Hub │ │ (不發布) │
└─────┬──────┘ └────────────┘
┌────────────────────────┐
│ upstream-YYYYMMDD tag │
│ ❌ 不更新 latest │
│ ❌ 不打 semver tag │
└────────────────────────┘
```
---
## Workflow 說明
### `auto-upstream-sync.yml`
**用途:** 自動檢測並同步 upstream 更新
**觸發條件:**
- ⏰ 每 6 小時自動執行
- 🖱️ 手動觸發
**主要步驟:**
1. Fetch upstream 最新程式碼
2. 檢查是否有新 commits
3. 自動 merge 到 `dev` 分支
4. 產生變更摘要Issue + Changelog
5. Push 到 `dev`
### `upstream-sync.yml`
**用途:** 當 `dev` 分支有 push 時,執行 build + smoke test
**觸發條件:**
- 📦 `dev` 分支有 push
**主要步驟:**
1. Build 測試用 image僅 amd64加速測試
2. 執行 Smoke Test10 分鐘內)
3. 測試通過後 build multi-arch image
4. Push 到 Docker Hubtag: `upstream-YYYYMMDD`
---
## Smoke Test 內容
### Test 1: Container 啟動測試
```bash
# 啟動 container 並等待 healthcheck 回應
docker run -d --name convertx-test $IMAGE
curl http://localhost:3000/healthcheck
```
### Test 2: 關鍵工具檢查
```bash
# 必須通過(任一失敗則整體失敗)
libreoffice --version
pandoc --version
ffmpeg -version
tesseract --version
```
### Test 3: 最小轉換測試
```bash
# txt → pdf 轉換測試
echo "test" > test.txt
libreoffice --headless --convert-to pdf test.txt
```
### Test 4: API 端點檢查
```bash
# 確認服務正常運作
curl http://localhost:3000/healthcheck
curl http://localhost:3000/
```
---
## 設定說明
### 必要的 GitHub Secrets
在 Repository Settings → Secrets and variables → Actions 中設定:
| Secret 名稱 | 說明 |
| -------------------- | ----------------------- |
| `DOCKERHUB_USERNAME` | Docker Hub 帳號 |
| `DOCKERHUB_TOKEN` | Docker Hub Access Token |
### 分支保護規則
建議設定:
**`main` 分支:**
- ✅ Require pull request before merging
- ✅ Require status checks to pass
- ❌ Allow force pushes
**`dev` 分支:**
- ✅ Allow direct pushes (for automation)
---
## 手動操作
### 手動觸發同步
1. 前往 Actions → Auto Upstream Sync
2. 點選 "Run workflow"
3. 可選擇「強制同步」
### 手動處理 Merge 衝突
當自動同步發生衝突時:
```bash
# 1. 切換到 dev 分支
git checkout dev
# 2. 添加 upstream remote如果還沒有
git remote add upstream https://github.com/C4illin/ConvertX.git
# 3. Fetch upstream
git fetch upstream main
# 4. Merge upstream
git merge upstream/main
# 5. 解決衝突
# ... 編輯衝突的檔案 ...
# 6. 提交並 push
git add .
git commit -m "Resolve merge conflicts with upstream"
git push origin dev
```
---
## ⚠️ 注意事項
1. **不會自動更新 `latest` tag** - 需要手動發布正式版本
2. **不會自動打 semver tag** - 需要手動建立 release
3. **`main` 分支不會被自動修改** - 只有 `dev` 會自動同步
4. **Smoke test 失敗時不會發布 image** - 確保品質
---
## 📊 Docker Image Tag 規則
| Tag 格式 | 說明 | 自動/手動 |
| ------------------- | ---------------------------------- | --------- |
| `upstream-YYYYMMDD` | Upstream 同步版(經過 smoke test | 自動 |
| `vX.Y.Z` | 正式版本 | 手動 |
| `latest` | 最新穩定版 | 手動 |

238
.github/scripts/smoke-test.sh vendored Normal file
View file

@ -0,0 +1,238 @@
#!/bin/bash
# ==============================================================================
# ConvertX Smoke Test Script
# 用於驗證 Docker image 的基本功能
# ==============================================================================
set -e
CONTAINER_NAME="${CONTAINER_NAME:-convertx-test}"
TEST_TIMEOUT="${TEST_TIMEOUT:-60}"
echo "=================================================="
echo "🧪 ConvertX Smoke Test"
echo "=================================================="
echo ""
# 顏色定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
pass() {
echo -e "${GREEN}✅ PASS${NC}: $1"
}
fail() {
echo -e "${RED}❌ FAIL${NC}: $1"
exit 1
}
warn() {
echo -e "${YELLOW}⚠️ WARN${NC}: $1"
}
# ==============================================================================
# Test 1: Container 啟動測試
# ==============================================================================
test_container_startup() {
echo ""
echo "📦 Test 1: Container Startup"
echo "----------------------------"
echo "Waiting for container to be healthy..."
for i in $(seq 1 $TEST_TIMEOUT); do
if docker exec $CONTAINER_NAME curl -sf http://localhost:3000/healthcheck > /dev/null 2>&1; then
pass "Container started in ${i}s"
return 0
fi
sleep 1
done
fail "Container failed to start within ${TEST_TIMEOUT}s"
}
# ==============================================================================
# Test 2: 關鍵工具存在性檢查
# ==============================================================================
test_critical_tools() {
echo ""
echo "🔧 Test 2: Critical Tools Availability"
echo "---------------------------------------"
local failed=0
# LibreOffice (必要)
echo -n " libreoffice: "
if docker exec $CONTAINER_NAME libreoffice --version > /dev/null 2>&1; then
VERSION=$(docker exec $CONTAINER_NAME libreoffice --version 2>/dev/null | head -1)
echo -e "${GREEN}OK${NC} ($VERSION)"
else
echo -e "${RED}MISSING${NC}"
failed=1
fi
# Pandoc (必要)
echo -n " pandoc: "
if docker exec $CONTAINER_NAME pandoc --version > /dev/null 2>&1; then
VERSION=$(docker exec $CONTAINER_NAME pandoc --version 2>/dev/null | head -1)
echo -e "${GREEN}OK${NC} ($VERSION)"
else
echo -e "${RED}MISSING${NC}"
failed=1
fi
# FFmpeg (必要)
echo -n " ffmpeg: "
if docker exec $CONTAINER_NAME ffmpeg -version > /dev/null 2>&1; then
VERSION=$(docker exec $CONTAINER_NAME ffmpeg -version 2>/dev/null | head -1 | awk '{print $3}')
echo -e "${GREEN}OK${NC} (v$VERSION)"
else
echo -e "${RED}MISSING${NC}"
failed=1
fi
# Tesseract (必要)
echo -n " tesseract: "
if docker exec $CONTAINER_NAME tesseract --version > /dev/null 2>&1; then
VERSION=$(docker exec $CONTAINER_NAME tesseract --version 2>/dev/null | head -1)
echo -e "${GREEN}OK${NC} ($VERSION)"
else
echo -e "${RED}MISSING${NC}"
failed=1
fi
echo ""
echo " Additional tools (optional):"
# ImageMagick
echo -n " imagemagick: "
if docker exec $CONTAINER_NAME magick -version > /dev/null 2>&1; then
echo -e "${GREEN}OK${NC}"
else
echo -e "${YELLOW}Not found${NC}"
fi
# Inkscape
echo -n " inkscape: "
if docker exec $CONTAINER_NAME inkscape --version > /dev/null 2>&1; then
echo -e "${GREEN}OK${NC}"
else
echo -e "${YELLOW}Not found${NC}"
fi
# GraphicsMagick
echo -n " graphicsmagick: "
if docker exec $CONTAINER_NAME gm version > /dev/null 2>&1; then
echo -e "${GREEN}OK${NC}"
else
echo -e "${YELLOW}Not found${NC}"
fi
# Calibre
echo -n " calibre: "
if docker exec $CONTAINER_NAME ebook-convert --version > /dev/null 2>&1; then
echo -e "${GREEN}OK${NC}"
else
echo -e "${YELLOW}Not found${NC}"
fi
echo ""
if [ $failed -eq 1 ]; then
fail "Critical tools check failed"
else
pass "All critical tools available"
fi
}
# ==============================================================================
# Test 3: 最小轉換測試
# ==============================================================================
test_minimal_conversion() {
echo ""
echo "📄 Test 3: Minimal Conversion"
echo "-----------------------------"
# 在 container 內建立測試檔案並轉換
echo " Creating test file..."
docker exec $CONTAINER_NAME sh -c "echo 'ConvertX Smoke Test - $(date)' > /tmp/test.txt"
echo " Converting txt → pdf using LibreOffice..."
if docker exec $CONTAINER_NAME sh -c "cd /tmp && libreoffice --headless --convert-to pdf test.txt" > /dev/null 2>&1; then
# 檢查輸出檔案
if docker exec $CONTAINER_NAME test -f /tmp/test.pdf; then
SIZE=$(docker exec $CONTAINER_NAME stat -c%s /tmp/test.pdf 2>/dev/null || echo "unknown")
pass "Conversion successful (output: ${SIZE} bytes)"
else
fail "Conversion failed - output file not found"
fi
else
fail "LibreOffice conversion command failed"
fi
# 清理
docker exec $CONTAINER_NAME rm -f /tmp/test.txt /tmp/test.pdf 2>/dev/null || true
}
# ==============================================================================
# Test 4: API 端點檢查
# ==============================================================================
test_api_endpoints() {
echo ""
echo "🌐 Test 4: API Endpoints"
echo "------------------------"
local failed=0
# Healthcheck
echo -n " GET /healthcheck: "
if docker exec $CONTAINER_NAME curl -sf http://localhost:3000/healthcheck > /dev/null 2>&1; then
echo -e "${GREEN}200 OK${NC}"
else
echo -e "${RED}FAILED${NC}"
failed=1
fi
# Root
echo -n " GET /: "
if docker exec $CONTAINER_NAME curl -sf http://localhost:3000/ > /dev/null 2>&1; then
echo -e "${GREEN}200 OK${NC}"
else
echo -e "${RED}FAILED${NC}"
failed=1
fi
echo ""
if [ $failed -eq 1 ]; then
fail "API endpoints check failed"
else
pass "All API endpoints responding"
fi
}
# ==============================================================================
# Main
# ==============================================================================
main() {
local start_time=$(date +%s)
test_container_startup
test_critical_tools
test_minimal_conversion
test_api_endpoints
local end_time=$(date +%s)
local duration=$((end_time - start_time))
echo ""
echo "=================================================="
echo -e "🎉 ${GREEN}All smoke tests passed!${NC}"
echo " Total time: ${duration}s"
echo "=================================================="
}
main "$@"

6
.github/test-files/test.txt vendored Normal file
View file

@ -0,0 +1,6 @@
Hello, this is a smoke test file for ConvertX.
這是 ConvertX 的冒煙測試檔案。
日本語テスト:こんにちは
한국어 테스트: 안녕하세요
This file should be less than 1KB for quick testing.

281
.github/workflows/auto-upstream-sync.yml vendored Normal file
View file

@ -0,0 +1,281 @@
# ==============================================================================
# 自動同步 Upstream Repository
# 功能:
# 1. 定時檢查 upstream 更新
# 2. 自動 merge 到 dev 分支
# 3. 產生變更摘要Change Summary
# 4. 觸發後續的 build + smoke test
# ==============================================================================
name: Auto Upstream Sync
on:
# 每 6 小時檢查一次 upstream
schedule:
- cron: "0 */6 * * *"
# 手動觸發
workflow_dispatch:
inputs:
force_sync:
description: "強制同步(即使無新 commit"
type: boolean
default: false
env:
UPSTREAM_REPO: https://github.com/C4illin/ConvertX.git
TARGET_BRANCH: dev
UPSTREAM_BRANCH: main
permissions:
contents: write
issues: write
jobs:
check-and-sync:
name: Check & Sync Upstream
runs-on: ubuntu-latest
outputs:
has_updates: ${{ steps.check.outputs.has_updates }}
new_commits: ${{ steps.check.outputs.new_commits }}
commit_count: ${{ steps.check.outputs.commit_count }}
sync_date: ${{ steps.date.outputs.date }}
changelog: ${{ steps.changelog.outputs.changelog }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ env.TARGET_BRANCH }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get current date
id: date
run: echo "date=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Add upstream remote
run: |
git remote add upstream ${{ env.UPSTREAM_REPO }} || true
git fetch upstream ${{ env.UPSTREAM_BRANCH }}
- name: Check for upstream updates
id: check
run: |
# 取得本地 dev 分支的最後一次 upstream merge commit
# 我們用 upstream/main 與目前 HEAD 比較
LOCAL_HEAD=$(git rev-parse HEAD)
UPSTREAM_HEAD=$(git rev-parse upstream/${{ env.UPSTREAM_BRANCH }})
echo "Local HEAD: $LOCAL_HEAD"
echo "Upstream HEAD: $UPSTREAM_HEAD"
# 檢查 upstream 是否有新的 commits
MERGE_BASE=$(git merge-base HEAD upstream/${{ env.UPSTREAM_BRANCH }})
echo "Merge base: $MERGE_BASE"
if [ "$MERGE_BASE" = "$UPSTREAM_HEAD" ]; then
echo "✅ Already up to date with upstream"
echo "has_updates=false" >> $GITHUB_OUTPUT
echo "commit_count=0" >> $GITHUB_OUTPUT
else
# 計算新的 commits 數量
NEW_COMMITS=$(git rev-list --count $MERGE_BASE..$UPSTREAM_HEAD)
echo "🔄 Found $NEW_COMMITS new commits from upstream"
echo "has_updates=true" >> $GITHUB_OUTPUT
echo "commit_count=$NEW_COMMITS" >> $GITHUB_OUTPUT
# 取得新 commits 的列表
COMMITS_LIST=$(git log --oneline $MERGE_BASE..$UPSTREAM_HEAD)
echo "new_commits<<EOF" >> $GITHUB_OUTPUT
echo "$COMMITS_LIST" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
fi
- name: Generate changelog before merge
id: changelog
if: steps.check.outputs.has_updates == 'true' || github.event.inputs.force_sync == 'true'
run: |
MERGE_BASE=$(git merge-base HEAD upstream/${{ env.UPSTREAM_BRANCH }})
echo "## 📋 Upstream 變更摘要" > changelog.md
echo "" >> changelog.md
echo "**同步時間:** $(date +'%Y-%m-%d %H:%M:%S UTC')" >> changelog.md
echo "**Upstream 分支:** ${{ env.UPSTREAM_BRANCH }}" >> changelog.md
echo "**新 Commits 數量:** ${{ steps.check.outputs.commit_count }}" >> changelog.md
echo "" >> changelog.md
echo "### 📝 Commit 列表" >> changelog.md
echo "" >> changelog.md
echo "\`\`\`" >> changelog.md
git log --oneline --no-merges $MERGE_BASE..upstream/${{ env.UPSTREAM_BRANCH }} >> changelog.md
echo "\`\`\`" >> changelog.md
echo "" >> changelog.md
echo "### 📊 變更統計" >> changelog.md
echo "" >> changelog.md
echo "\`\`\`" >> changelog.md
git diff --stat $MERGE_BASE..upstream/${{ env.UPSTREAM_BRANCH }} >> changelog.md
echo "\`\`\`" >> changelog.md
echo "" >> changelog.md
echo "### 🔍 變更的檔案" >> changelog.md
echo "" >> changelog.md
git diff --name-status $MERGE_BASE..upstream/${{ env.UPSTREAM_BRANCH }} | while read line; do
STATUS=$(echo "$line" | awk '{print $1}')
FILE=$(echo "$line" | awk '{print $2}')
case $STATUS in
A) echo "- ✅ **新增** \`$FILE\`" >> changelog.md ;;
M) echo "- ✏️ **修改** \`$FILE\`" >> changelog.md ;;
D) echo "- ❌ **刪除** \`$FILE\`" >> changelog.md ;;
R*) echo "- 🔄 **重新命名** \`$FILE\`" >> changelog.md ;;
*) echo "- 📄 \`$FILE\` ($STATUS)" >> changelog.md ;;
esac
done
cat changelog.md
# 輸出給後續步驟使用
CHANGELOG_CONTENT=$(cat changelog.md)
echo "changelog<<EOF" >> $GITHUB_OUTPUT
echo "$CHANGELOG_CONTENT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Merge upstream changes
id: merge
if: steps.check.outputs.has_updates == 'true' || github.event.inputs.force_sync == 'true'
run: |
echo "🔄 Merging upstream/${{ env.UPSTREAM_BRANCH }} into ${{ env.TARGET_BRANCH }}..."
# 嘗試自動 merge
if git merge upstream/${{ env.UPSTREAM_BRANCH }} --no-edit -m "🔄 Auto-merge upstream changes ($(date +'%Y-%m-%d'))"; then
echo "✅ Merge successful!"
echo "merge_success=true" >> $GITHUB_OUTPUT
else
echo "❌ Merge conflict detected!"
echo "merge_success=false" >> $GITHUB_OUTPUT
# 取消 merge
git merge --abort
# 建立 conflict issue
exit 1
fi
- name: Push changes
if: steps.merge.outputs.merge_success == 'true'
run: |
git push origin ${{ env.TARGET_BRANCH }}
echo "✅ Changes pushed to ${{ env.TARGET_BRANCH }}"
- name: Commit changelog
if: steps.merge.outputs.merge_success == 'true'
run: |
# 更新 upstream-changelog.md
if [ -f upstream-changelog.md ]; then
# 在檔案開頭插入新的 changelog
echo "" >> changelog.md
echo "---" >> changelog.md
echo "" >> changelog.md
cat upstream-changelog.md >> changelog.md
fi
mv changelog.md upstream-changelog.md
git add upstream-changelog.md
git commit -m "📋 Update upstream changelog (${{ steps.date.outputs.date }})" || true
git push origin ${{ env.TARGET_BRANCH }} || true
- name: Create GitHub Issue for sync summary
if: steps.merge.outputs.merge_success == 'true' && steps.check.outputs.commit_count > 0
uses: actions/github-script@v7
with:
script: |
const date = '${{ steps.date.outputs.date }}';
const commitCount = '${{ steps.check.outputs.commit_count }}';
const body = `## 🔄 Upstream 自動同步完成
**同步日期:** ${date}
**新 Commits:** ${commitCount} 個
**目標分支:** \`dev\`
### 📝 變更摘要
\`\`\`
${{ steps.check.outputs.new_commits }}
\`\`\`
### ⏳ 後續動作
- [ ] Smoke test 執行中...
- [ ] Docker image 建構中 (\`upstream-${date}\`)
---
*此 Issue 由 GitHub Actions 自動建立*
`;
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `🔄 Upstream Sync: ${date} (${commitCount} commits)`,
body: body,
labels: ['upstream-sync', 'automated']
});
- name: Create Issue for merge conflict
if: failure() && steps.merge.outputs.merge_success == 'false'
uses: actions/github-script@v7
with:
script: |
const date = '${{ steps.date.outputs.date }}';
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `⚠️ Upstream Sync 衝突: ${date}`,
body: `## ⚠️ Upstream 同步發生衝突
需要手動解決 merge conflict。
### 處理步驟
\`\`\`bash
git fetch upstream main
git checkout dev
git merge upstream/main
# 解決衝突後
git add .
git commit
git push origin dev
\`\`\`
---
*此 Issue 由 GitHub Actions 自動建立*
`,
labels: ['upstream-sync', 'merge-conflict', 'needs-attention']
});
- name: Summary
if: always()
run: |
echo "## 🔄 Upstream Sync Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 項目 | 狀態 |" >> $GITHUB_STEP_SUMMARY
echo "|------|------|" >> $GITHUB_STEP_SUMMARY
echo "| 檢查時間 | $(date +'%Y-%m-%d %H:%M:%S UTC') |" >> $GITHUB_STEP_SUMMARY
echo "| 有新更新 | ${{ steps.check.outputs.has_updates }} |" >> $GITHUB_STEP_SUMMARY
echo "| 新 Commits | ${{ steps.check.outputs.commit_count }} |" >> $GITHUB_STEP_SUMMARY
echo "| Merge 成功 | ${{ steps.merge.outputs.merge_success || 'N/A' }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.check.outputs.has_updates }}" == "true" ]; then
echo "### 📝 New Commits" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "${{ steps.check.outputs.new_commits }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
fi

View file

@ -51,6 +51,33 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v6
# ========================================
# 清理磁碟空間(解決 no space left on device
# ========================================
- name: Free disk space
run: |
echo "🧹 Cleaning up disk space..."
df -h
# 移除不需要的預裝軟體
sudo rm -rf /usr/share/dotnet || true
sudo rm -rf /usr/local/lib/android || true
sudo rm -rf /opt/ghc || true
sudo rm -rf /opt/hostedtoolcache/CodeQL || true
sudo rm -rf /usr/local/share/boost || true
sudo rm -rf /usr/share/swift || true
sudo rm -rf /opt/hostedtoolcache || true
# 清理 apt cache
sudo apt-get clean || true
sudo apt-get autoremove -y || true
# 清理 Docker 舊資料
docker system prune -af --volumes || true
echo "After cleanup:"
df -h
- name: downcase REPO - name: downcase REPO
run: | run: |
echo "REPO=${GITHUB_REPOSITORY@L}" >> "${GITHUB_ENV}" echo "REPO=${GITHUB_REPOSITORY@L}" >> "${GITHUB_ENV}"

View file

@ -3,7 +3,7 @@ name: Release
on: on:
push: push:
tags: tags:
- 'v*.*.*' - "v*.*.*"
env: env:
DOCKER_IMAGE: convertx/convertx-cn DOCKER_IMAGE: convertx/convertx-cn
@ -11,15 +11,45 @@ env:
jobs: jobs:
build-and-push: build-and-push:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
# ========================================
# 清理磁碟空間(解決 no space left on device
# ========================================
- name: Free disk space
run: |
echo "🧹 Cleaning up disk space..."
df -h
# 移除不需要的預裝軟體
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo rm -rf /usr/local/share/boost
sudo rm -rf /usr/share/swift
sudo rm -rf /opt/hostedtoolcache
# 清理 apt cache
sudo apt-get clean
sudo apt-get autoremove -y
# 清理 Docker 舊資料
docker system prune -af --volumes || true
echo "After cleanup:"
df -h
- name: Get tag name - name: Get tag name
id: tag id: tag
run: echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT run: echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
@ -54,7 +84,7 @@ jobs:
needs: build-and-push needs: build-and-push
permissions: permissions:
contents: write contents: write
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -70,7 +100,7 @@ jobs:
run: | run: |
# Get previous tag # Get previous tag
PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
if [ -z "$PREVIOUS_TAG" ]; then if [ -z "$PREVIOUS_TAG" ]; then
# No previous tag, get all commits # No previous tag, get all commits
CHANGELOG=$(git log --pretty=format:"- %s (%h)" HEAD) CHANGELOG=$(git log --pretty=format:"- %s (%h)" HEAD)
@ -78,10 +108,10 @@ jobs:
# Get commits between previous tag and current # Get commits between previous tag and current
CHANGELOG=$(git log --pretty=format:"- %s (%h)" ${PREVIOUS_TAG}..HEAD) CHANGELOG=$(git log --pretty=format:"- %s (%h)" ${PREVIOUS_TAG}..HEAD)
fi fi
# Write to file to preserve newlines # Write to file to preserve newlines
echo "$CHANGELOG" > changelog.txt echo "$CHANGELOG" > changelog.txt
- name: Create GitHub Release - name: Create GitHub Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:

View file

@ -1,3 +1,12 @@
# ==============================================================================
# Upstream Sync Build + Smoke Test
# 功能:
# 1. dev 分支有 push 時自動觸發
# 2. 建構 Docker image僅 amd64 用於測試)
# 3. 執行 smoke test10 分鐘內完成)
# 4. 測試通過後推送 multi-arch image
# ==============================================================================
name: Upstream Sync Build name: Upstream Sync Build
on: on:
@ -7,15 +16,56 @@ on:
env: env:
DOCKER_IMAGE: convertx/convertx-cn DOCKER_IMAGE: convertx/convertx-cn
TEST_IMAGE: convertx-cn-test
# Smoke test 超時時間(秒)
SMOKE_TEST_TIMEOUT: 600
concurrency:
group: upstream-sync-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
build-and-push: # ==========================================================================
# Job 1: 快速建構測試用 image僅 amd64
# ==========================================================================
build-test-image:
name: Build Test Image
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.date.outputs.date }}
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
# ========================================
# 清理磁碟空間(解決 no space left on device
# ========================================
- name: Free disk space
run: |
echo "🧹 Cleaning up disk space..."
echo "Before cleanup:"
df -h
# 移除不需要的預裝軟體
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo rm -rf /usr/local/share/boost
sudo rm -rf /usr/share/swift
# 清理 apt cache
sudo apt-get clean
sudo apt-get autoremove -y
# 清理 Docker 舊資料
docker system prune -af --volumes || true
echo ""
echo "After cleanup:"
df -h
- name: Get current date - name: Get current date
id: date id: date
run: echo "date=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT run: echo "date=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT
@ -23,6 +73,308 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Build test image (amd64 only)
uses: docker/build-push-action@v6
with:
context: .
push: false
load: true
tags: ${{ env.TEST_IMAGE }}:test
platforms: linux/amd64
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Save Docker image
run: |
docker save ${{ env.TEST_IMAGE }}:test -o /tmp/test-image.tar
- name: Upload test image
uses: actions/upload-artifact@v4
with:
name: test-image
path: /tmp/test-image.tar
retention-days: 1
# ==========================================================================
# Job 2: Smoke Test必須在 10 分鐘內完成)
# ==========================================================================
smoke-test:
name: Smoke Test
runs-on: ubuntu-latest
needs: build-test-image
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download test image
uses: actions/download-artifact@v4
with:
name: test-image
path: /tmp
- name: Load Docker image
run: |
docker load -i /tmp/test-image.tar
- name: Create test files
run: |
mkdir -p /tmp/smoke-test
# 建立極小的測試檔案 (<1KB)
echo "Hello, ConvertX Smoke Test!" > /tmp/smoke-test/test.txt
echo "這是中文測試檔案" >> /tmp/smoke-test/test.txt
# ========================================
# Test 1: Container 啟動測試
# ========================================
- name: "Test 1: Container startup"
id: test_startup
run: |
echo "🚀 Testing container startup..."
# 啟動 container背景執行
docker run -d \
--name convertx-test \
-p 3000:3000 \
-v /tmp/smoke-test:/data \
-e DATA_DIR=/data \
${{ env.TEST_IMAGE }}:test
# 等待啟動(最多 60 秒)
echo "⏳ Waiting for container to start..."
for i in {1..60}; do
if docker exec convertx-test curl -sf http://localhost:3000/healthcheck > /dev/null 2>&1; then
echo "✅ Container started successfully in ${i}s"
echo "startup_time=${i}" >> $GITHUB_OUTPUT
exit 0
fi
sleep 1
done
echo "❌ Container failed to start within 60s"
docker logs convertx-test
exit 1
# ========================================
# Test 2: 關鍵工具存在性檢查
# ========================================
- name: "Test 2: Tool availability check"
id: test_tools
run: |
echo "🔧 Checking critical tools..."
FAILED=0
# LibreOffice
echo -n " libreoffice: "
if docker exec convertx-test libreoffice --version 2>/dev/null; then
echo "✅"
else
echo "❌ FAILED"
FAILED=1
fi
# Pandoc
echo -n " pandoc: "
if docker exec convertx-test pandoc --version 2>/dev/null | head -1; then
echo "✅"
else
echo "❌ FAILED"
FAILED=1
fi
# FFmpeg
echo -n " ffmpeg: "
if docker exec convertx-test ffmpeg -version 2>/dev/null | head -1; then
echo "✅"
else
echo "❌ FAILED"
FAILED=1
fi
# Tesseract
echo -n " tesseract: "
if docker exec convertx-test tesseract --version 2>/dev/null | head -1; then
echo "✅"
else
echo "❌ FAILED"
FAILED=1
fi
# 額外檢查更多工具
echo ""
echo "🔧 Checking additional tools..."
# ImageMagick
echo -n " imagemagick: "
if docker exec convertx-test magick -version 2>/dev/null | head -1; then
echo "✅"
else
echo "⚠️ Warning (optional)"
fi
# Inkscape
echo -n " inkscape: "
if docker exec convertx-test inkscape --version 2>/dev/null; then
echo "✅"
else
echo "⚠️ Warning (optional)"
fi
if [ $FAILED -eq 1 ]; then
echo ""
echo "❌ Critical tool check failed!"
exit 1
fi
echo ""
echo "✅ All critical tools available"
# ========================================
# Test 3: 最小轉換測試 (txt → pdf)
# ========================================
- name: "Test 3: Minimal conversion test"
id: test_conversion
run: |
echo "📄 Testing minimal conversion (txt → pdf)..."
# 使用 API 進行轉換測試
# 先上傳檔案
echo " Uploading test file..."
UPLOAD_RESPONSE=$(curl -sf -X POST \
-F "file=@/tmp/smoke-test/test.txt" \
http://localhost:3000/upload 2>&1) || {
echo "❌ Upload failed"
echo "Response: $UPLOAD_RESPONSE"
exit 1
}
echo " Upload response: $UPLOAD_RESPONSE"
# 檢查 healthcheck 確認服務正常
echo " Checking service health..."
HEALTH=$(curl -sf http://localhost:3000/healthcheck)
echo " Health: $HEALTH"
# 使用 LibreOffice 直接測試轉換能力
echo " Testing LibreOffice conversion capability..."
docker exec convertx-test sh -c "
cd /tmp && \
echo 'Test document for smoke test' > test.txt && \
libreoffice --headless --convert-to pdf test.txt && \
ls -la test.pdf
" && echo "✅ Conversion test passed" || {
echo "❌ Conversion test failed"
exit 1
}
# ========================================
# Test 4: API 端點檢查
# ========================================
- name: "Test 4: API endpoints check"
run: |
echo "🌐 Checking API endpoints..."
# Healthcheck
echo -n " /healthcheck: "
if curl -sf http://localhost:3000/healthcheck > /dev/null; then
echo "✅"
else
echo "❌"
exit 1
fi
# Root page
echo -n " / (root): "
if curl -sf http://localhost:3000/ > /dev/null; then
echo "✅"
else
echo "❌"
exit 1
fi
# Converters list
echo -n " /converters: "
if curl -sf http://localhost:3000/converters > /dev/null; then
echo "✅"
else
echo "⚠️ (may require auth)"
fi
echo ""
echo "✅ API endpoints check passed"
- name: Cleanup test container
if: always()
run: |
docker stop convertx-test || true
docker rm convertx-test || true
- name: Smoke test summary
if: always()
run: |
echo "## 🧪 Smoke Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 測試項目 | 狀態 |" >> $GITHUB_STEP_SUMMARY
echo "|----------|------|" >> $GITHUB_STEP_SUMMARY
echo "| Container 啟動 | ✅ 通過 (${startup_time:-N/A}s) |" >> $GITHUB_STEP_SUMMARY
echo "| 工具檢查 (libreoffice, pandoc, ffmpeg, tesseract) | ✅ 通過 |" >> $GITHUB_STEP_SUMMARY
echo "| 最小轉換測試 | ✅ 通過 |" >> $GITHUB_STEP_SUMMARY
echo "| API 端點檢查 | ✅ 通過 |" >> $GITHUB_STEP_SUMMARY
# ==========================================================================
# Job 3: 測試通過後,建構並推送 multi-arch image
# ==========================================================================
build-and-push:
name: Build & Push Multi-arch Image
runs-on: ubuntu-latest
needs: [build-test-image, smoke-test]
steps:
- name: Checkout repository
uses: actions/checkout@v4
# ========================================
# 清理磁碟空間multi-arch build 需要更多空間)
# ========================================
- name: Free disk space
run: |
echo "🧹 Cleaning up disk space for multi-arch build..."
echo "Before cleanup:"
df -h
# 移除不需要的預裝軟體
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo rm -rf /usr/local/share/boost
sudo rm -rf /usr/share/swift
sudo rm -rf /opt/hostedtoolcache
# 清理 apt cache
sudo apt-get clean
sudo apt-get autoremove -y
# 清理 Docker 舊資料
docker system prune -af --volumes || true
echo ""
echo "After cleanup:"
df -h
- name: Get current date
id: date
run: echo "date=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
@ -45,4 +397,16 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Image:** \`${{ env.DOCKER_IMAGE }}:upstream-${{ steps.date.outputs.date }}\`" >> $GITHUB_STEP_SUMMARY echo "**Image:** \`${{ env.DOCKER_IMAGE }}:upstream-${{ steps.date.outputs.date }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "This is an upstream sync build. Use version tags for stable releases." >> $GITHUB_STEP_SUMMARY echo "### ✅ Smoke Test 已通過" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 測試項目 | 狀態 |" >> $GITHUB_STEP_SUMMARY
echo "|----------|------|" >> $GITHUB_STEP_SUMMARY
echo "| Container 啟動 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| 工具存在性檢查 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| 最小轉換測試 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| API 端點檢查 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "---" >> $GITHUB_STEP_SUMMARY
echo "⚠️ 這是 upstream 同步版本。請使用 version tags 取得穩定版本。" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "❌ **不會更新 \`latest\` tag**" >> $GITHUB_STEP_SUMMARY

View file

@ -1,26 +1,28 @@
# ============================================================================== # ==============================================================================
# ConvertX-CN 完整版 Dockerfile # ConvertX-CN 精簡版 Dockerfile
# 內建所有轉換依賴LibreOffice / TexLive Full / OCR / CJK 字型 # 優化版本:移除 texlive-full精簡字型與語言支援
# 支援 linux/amd64, linux/arm64 multi-arch build # 目標:在 GitHub Actions 中穩定建構(解決 no space left on device
# 支援語言:中文(繁/簡)、日文、韓文、英文、德文、法文
# ============================================================================== # ==============================================================================
FROM debian:trixie-slim AS base FROM debian:trixie-slim AS base
LABEL org.opencontainers.image.source="https://github.com/pi-docket/ConvertX-CN" LABEL org.opencontainers.image.source="https://github.com/pi-docket/ConvertX-CN"
LABEL org.opencontainers.image.description="ConvertX-CN - 完整版檔案轉換服務,內建所有依賴" LABEL org.opencontainers.image.description="ConvertX-CN - 精簡版檔案轉換服務"
WORKDIR /app WORKDIR /app
# install bun # install bun
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y --no-install-recommends \
curl \ curl \
unzip \ unzip \
ca-certificates \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# if architecture is arm64, use the arm64 version of bun # if architecture is arm64, use the arm64 version of bun
RUN ARCH=$(uname -m) && \ RUN ARCH=$(uname -m) && \
if [ "$ARCH" = "aarch64" ]; then \ if [ "$ARCH" = "aarch64" ]; then \
curl -fsSL -o bun-linux-aarch64.zip https://github.com/oven-sh/bun/releases/download/bun-v1.2.2/bun-linux-aarch64.zip; \ curl -fsSL -o bun-linux-aarch64.zip https://github.com/oven-sh/bun/releases/download/bun-v1.2.2/bun-linux-aarch64.zip; \
else \ else \
curl -fsSL -o bun-linux-x64-baseline.zip https://github.com/oven-sh/bun/releases/download/bun-v1.2.2/bun-linux-x64-baseline.zip; \ curl -fsSL -o bun-linux-x64-baseline.zip https://github.com/oven-sh/bun/releases/download/bun-v1.2.2/bun-linux-x64-baseline.zip; \
fi fi
RUN unzip -j bun-linux-*.zip -d /usr/local/bin && \ RUN unzip -j bun-linux-*.zip -d /usr/local/bin && \
@ -51,8 +53,9 @@ RUN bun run build
FROM base AS release FROM base AS release
# ============================================================================== # ==============================================================================
# 完整依賴安裝(單一 RUN 層,優化 cache # 精簡依賴安裝(單一 RUN 層,優化 cache 與空間)
# 包含:轉換工具 + TexLive Full + LibreOffice + OCR + CJK 字型 # ❌ 已移除texlive-full, fonts-noto-extra, 多餘語言包
# ✅ 保留:核心轉換工具 + 最小 TexLive + 必要字型
# ============================================================================== # ==============================================================================
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
# === 基礎轉換工具 === # === 基礎轉換工具 ===
@ -77,13 +80,34 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
resvg \ resvg \
# === LibreOffice (headless) === # === LibreOffice (headless) ===
libreoffice \ libreoffice \
# === TexLive 完整版(支援所有 LaTeX 需求)=== # === TexLive 最小集合(取代 texlive-full===
texlive-full \ # texlive-base: LaTeX 核心
# texlive-latex-base: 基本 LaTeX 類別
# texlive-latex-recommended: 常用套件geometry, hyperref 等)
# texlive-fonts-recommended: 基本字型Computer Modern 等)
# texlive-xetex: XeTeX 引擎Unicode/CJK 支援必需)
# texlive-lang-cjk: 中日韓 LaTeX 支援
# texlive-lang-german: 德文 LaTeX 支援
# texlive-lang-french: 法文 LaTeX 支援
texlive-base \
texlive-latex-base \
texlive-latex-recommended \
texlive-fonts-recommended \
texlive-xetex \
texlive-lang-cjk \
texlive-lang-german \
texlive-lang-french \
latexmk \ latexmk \
lmodern \ lmodern \
# === Pandoc 文件轉換 === # === Pandoc 文件轉換 ===
pandoc \ pandoc \
# === OCR 支援Tesseract + 多語言包)=== # === OCR 支援(僅限指定語言)===
# eng: 英文
# chi_tra/chi_sim: 繁/簡中文
# jpn: 日文
# kor: 韓文
# deu: 德文
# fra: 法文
tesseract-ocr \ tesseract-ocr \
tesseract-ocr-eng \ tesseract-ocr-eng \
tesseract-ocr-chi-tra \ tesseract-ocr-chi-tra \
@ -91,41 +115,58 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
tesseract-ocr-jpn \ tesseract-ocr-jpn \
tesseract-ocr-kor \ tesseract-ocr-kor \
tesseract-ocr-deu \ tesseract-ocr-deu \
# === CJK 字型(中日韓完整支援)=== tesseract-ocr-fra \
# === 字型(精簡版)===
# fonts-noto-cjk: 中日韓統一字型(必需)
# fonts-noto-core: Noto Sans/Serif Latin歐語基礎
# fonts-noto-color-emoji: Emoji 支援(僅此一套)
# fonts-liberation: Liberation 字型Arial/Times 替代)
# ❌ 已移除fonts-noto-extra包含過多語言
# ❌ 已移除fonts-liberation2重複
fonts-noto-cjk \ fonts-noto-cjk \
fonts-noto-core \ fonts-noto-core \
fonts-noto-extra \
fonts-noto-color-emoji \ fonts-noto-color-emoji \
# === Liberation 字型(微軟字型開源替代)===
fonts-liberation \ fonts-liberation \
fonts-liberation2 \ # === Python 依賴(精簡)===
# === Python 依賴 ===
python3 \ python3 \
python3-pip \ python3-pip \
python3-numpy \ python3-numpy \
python3-tinycss2 \ python3-tinycss2 \
pipx \ pipx \
# === 系統工具 === # === 系統工具 ===
ca-certificates \
locales \ locales \
# === 清理 ===
&& pipx install "markitdown[all]" \ && pipx install "markitdown[all]" \
# 清理 apt cache
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/* \
# 清理 pip cache
&& rm -rf /root/.cache/pip \
# 清理 TexLive 文件(節省空間)
&& rm -rf /usr/share/doc/texlive* \
&& rm -rf /usr/share/texlive/texmf-dist/doc \
# 清理其他文件
&& rm -rf /usr/share/doc/* \
&& rm -rf /usr/share/man/* \
&& rm -rf /usr/share/info/*
# Add pipx bin directory to PATH # Add pipx bin directory to PATH
ENV PATH="/root/.local/bin:${PATH}" ENV PATH="/root/.local/bin:${PATH}"
# ============================================================================== # ==============================================================================
# 設定 locale避免中文 PDF 亂碼) # 設定 locale僅限指定語言
# ============================================================================== # ==============================================================================
RUN sed -i 's/# zh_TW.UTF-8 UTF-8/zh_TW.UTF-8 UTF-8/' /etc/locale.gen && \ RUN sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
sed -i 's/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/' /etc/locale.gen && \ sed -i 's/# zh_TW.UTF-8 UTF-8/zh_TW.UTF-8 UTF-8/' /etc/locale.gen && \
sed -i 's/# ja_JP.UTF-8 UTF-8/ja_JP.UTF-8 UTF-8/' /etc/locale.gen && \ sed -i 's/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/' /etc/locale.gen && \
sed -i 's/# ko_KR.UTF-8 UTF-8/ko_KR.UTF-8 UTF-8/' /etc/locale.gen && \ sed -i 's/# ja_JP.UTF-8 UTF-8/ja_JP.UTF-8 UTF-8/' /etc/locale.gen && \
locale-gen sed -i 's/# ko_KR.UTF-8 UTF-8/ko_KR.UTF-8 UTF-8/' /etc/locale.gen && \
sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen && \
sed -i 's/# fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/' /etc/locale.gen && \
locale-gen
ENV LANG=zh_TW.UTF-8 ENV LANG=en_US.UTF-8
ENV LC_ALL=zh_TW.UTF-8 ENV LC_ALL=en_US.UTF-8
# ============================================================================== # ==============================================================================
# 安裝自訂字型(標楷體等台灣常用字型) # 安裝自訂字型(標楷體等台灣常用字型)
@ -139,9 +180,9 @@ RUN fc-cache -fv
# ============================================================================== # ==============================================================================
RUN ARCH=$(uname -m) && \ RUN ARCH=$(uname -m) && \
if [ "$ARCH" = "aarch64" ]; then \ if [ "$ARCH" = "aarch64" ]; then \
VTRACER_ASSET="vtracer-aarch64-unknown-linux-musl.tar.gz"; \ VTRACER_ASSET="vtracer-aarch64-unknown-linux-musl.tar.gz"; \
else \ else \
VTRACER_ASSET="vtracer-x86_64-unknown-linux-musl.tar.gz"; \ VTRACER_ASSET="vtracer-x86_64-unknown-linux-musl.tar.gz"; \
fi && \ fi && \
curl -L -o /tmp/vtracer.tar.gz "https://github.com/visioncortex/vtracer/releases/download/0.6.4/${VTRACER_ASSET}" && \ curl -L -o /tmp/vtracer.tar.gz "https://github.com/visioncortex/vtracer/releases/download/0.6.4/${VTRACER_ASSET}" && \
tar -xzf /tmp/vtracer.tar.gz -C /tmp/ && \ tar -xzf /tmp/vtracer.tar.gz -C /tmp/ && \

View file

@ -7,7 +7,7 @@
[![GitHub Release](https://img.shields.io/github/v/release/pi-docket/ConvertX-CN)](https://github.com/pi-docket/ConvertX-CN/releases) [![GitHub Release](https://img.shields.io/github/v/release/pi-docket/ConvertX-CN)](https://github.com/pi-docket/ConvertX-CN/releases)
> 🎉 **這是完整版 ConvertX-CN image已內建所有轉換依賴** > 🎉 **這是完整版 ConvertX-CN image已內建所有轉換依賴**
> >
> 使用者 **不需要自己寫 Dockerfile**,直接 `docker run``docker compose up` 即可使用。 > 使用者 **不需要自己寫 Dockerfile**,直接 `docker run``docker compose up` 即可使用。
基於 [C4illin/ConvertX](https://github.com/C4illin/ConvertX) 的中文優化版本。 基於 [C4illin/ConvertX](https://github.com/C4illin/ConvertX) 的中文優化版本。
@ -18,16 +18,16 @@
此 image 已經內建以下所有依賴,開箱即用: 此 image 已經內建以下所有依賴,開箱即用:
| 類別 | 內建內容 | | 類別 | 內建內容 |
|------|----------| | ------------ | ---------------------------------------------------------------- |
| **文件轉換** | LibreOffice (headless)、Pandoc | | **文件轉換** | LibreOffice (headless)、Pandoc |
| **LaTeX** | TexLive Full完整版支援所有 LaTeX 需求) | | **LaTeX** | TexLive Full完整版支援所有 LaTeX 需求) |
| **OCR 識別** | Tesseract OCR + 繁體中文、簡體中文、日文、韓文、英文、德文語言包 | | **OCR 識別** | Tesseract OCR + 繁體中文、簡體中文、日文、韓文、英文、德文語言包 |
| **CJK 字型** | Noto CJK中日韓、Noto Emoji、微軟核心字型、標楷體 | | **CJK 字型** | Noto CJK中日韓、Noto Emoji、微軟核心字型、標楷體 |
| **影音轉換** | FFmpeg、ImageMagick、GraphicsMagick | | **影音轉換** | FFmpeg、ImageMagick、GraphicsMagick |
| **向量圖形** | Inkscape、Potrace、VTracer、resvg | | **向量圖形** | Inkscape、Potrace、VTracer、resvg |
| **電子書** | Calibre | | **電子書** | Calibre |
| **其他** | Ghostscript、MuPDF、Poppler、libheif、libjxl 等 | | **其他** | Ghostscript、MuPDF、Poppler、libheif、libjxl 等 |
--- ---
@ -78,10 +78,10 @@ docker compose up -d
## 📦 Docker Image ## 📦 Docker Image
| Image | 說明 | | Image | 說明 |
|-------|------| | ----------------------------- | ---------- |
| `convertx/convertx-cn:latest` | 最新穩定版 | | `convertx/convertx-cn:latest` | 最新穩定版 |
| `convertx/convertx-cn:v0.1.1` | 指定版本 | | `convertx/convertx-cn:v0.1.1` | 指定版本 |
> ⚠️ 由於內建完整依賴image 大小約 4-6 GB首次下載需要較長時間。 > ⚠️ 由於內建完整依賴image 大小約 4-6 GB首次下載需要較長時間。
@ -122,20 +122,20 @@ docker compose up -d
所有環境變數皆為選填,建議設定 `JWT_SECRET` 所有環境變數皆為選填,建議設定 `JWT_SECRET`
| 變數名稱 | 預設值 | 說明 | | 變數名稱 | 預設值 | 說明 |
|----------|--------|------| | ------------------------- | ------------ | ---------------------------------------- |
| JWT_SECRET | randomUUID() | 用於簽署 JWT 的密鑰字串 | | JWT_SECRET | randomUUID() | 用於簽署 JWT 的密鑰字串 |
| ACCOUNT_REGISTRATION | false | 是否允許註冊新帳號 | | ACCOUNT_REGISTRATION | false | 是否允許註冊新帳號 |
| HTTP_ALLOWED | false | 是否允許 HTTP 連線(僅本地使用) | | HTTP_ALLOWED | false | 是否允許 HTTP 連線(僅本地使用) |
| ALLOW_UNAUTHENTICATED | false | 是否允許未登入使用 | | ALLOW_UNAUTHENTICATED | false | 是否允許未登入使用 |
| AUTO_DELETE_EVERY_N_HOURS | 24 | 自動刪除超過 N 小時的檔案0 = 停用) | | AUTO_DELETE_EVERY_N_HOURS | 24 | 自動刪除超過 N 小時的檔案0 = 停用) |
| WEBROOT | | 子路徑部署,例如 `/convertx` | | WEBROOT | | 子路徑部署,例如 `/convertx` |
| FFMPEG_ARGS | | FFmpeg 輸入參數,例如 `-hwaccel vaapi` | | FFMPEG_ARGS | | FFmpeg 輸入參數,例如 `-hwaccel vaapi` |
| FFMPEG_OUTPUT_ARGS | | FFmpeg 輸出參數,例如 `-preset veryfast` | | FFMPEG_OUTPUT_ARGS | | FFmpeg 輸出參數,例如 `-preset veryfast` |
| HIDE_HISTORY | false | 隱藏歷史紀錄頁面 | | HIDE_HISTORY | false | 隱藏歷史紀錄頁面 |
| LANGUAGE | en | 日期格式語言BCP 47 格式) | | LANGUAGE | en | 日期格式語言BCP 47 格式) |
| TZ | UTC | 時區設定 | | TZ | UTC | 時區設定 |
| MAX_CONVERT_PROCESS | 0 | 最大同時轉換數0 = 無限制) | | MAX_CONVERT_PROCESS | 0 | 最大同時轉換數0 = 無限制) |
--- ---