更新书签处理逻辑,生成用户自定义的 bookmarks.user.yml 配置文件

This commit is contained in:
Zuoling Rong
2025-05-02 02:25:25 +08:00
parent 9a043ec82f
commit 89946cb5c4
5 changed files with 155 additions and 67 deletions

View File

@@ -53,21 +53,51 @@ jobs:
- name: Process bookmark file - name: Process bookmark file
if: steps.check_bookmark_files.outputs.found == 'true' if: steps.check_bookmark_files.outputs.found == 'true'
run: node src/bookmark-processor.js run: |
echo "Processing bookmark files..."
node src/bookmark-processor.js
- name: Commit bookmarks.yml changes - name: Debug directory contents
if: steps.check_bookmark_files.outputs.found == 'true'
run: |
echo "Current directory contents:"
ls -la
echo "Does bookmarks.user.yml exist?"
if [ -f bookmarks.user.yml ]; then
echo "YES - bookmarks.user.yml exists"
cat bookmarks.user.yml | head -n 10
else
echo "NO - bookmarks.user.yml does not exist"
fi
- name: Commit bookmarks.user.yml changes
if: steps.check_bookmark_files.outputs.found == 'true' if: steps.check_bookmark_files.outputs.found == 'true'
run: | run: |
git config --local user.email "action@github.com" git config --local user.email "action@github.com"
git config --local user.name "GitHub Action (Bookmarks)" git config --local user.name "GitHub Action (Bookmarks)"
# 检查 bookmarks.yml 是否真的被修改了
if ! git diff --quiet bookmarks.yml; then # Check if the file exists
echo "bookmarks.yml changed, committing..." if [ -f bookmarks.user.yml ]; then
git add bookmarks.yml # Check if file is already tracked by git
git commit -m "Update bookmarks.yml from imported bookmarks" if git ls-files --error-unmatch bookmarks.user.yml 2>/dev/null; then
# 不需要push因为构建步骤会使用当前工作区的内容 echo "bookmarks.user.yml exists and is tracked by git"
# Check if it has changes
if ! git diff --quiet bookmarks.user.yml; then
echo "bookmarks.user.yml has changes, committing..."
git add bookmarks.user.yml
git commit -m "Update bookmarks.user.yml from imported bookmarks"
else else
echo "No changes to bookmarks.yml" echo "No changes to bookmarks.user.yml"
fi
else
echo "bookmarks.user.yml exists but is not tracked by git (new file)"
git add bookmarks.user.yml
git commit -m "Add bookmarks.user.yml from imported bookmarks"
fi
else
echo "ERROR: bookmarks.user.yml does not exist! Bookmark processing may have failed."
echo "Current directory contents:"
ls -la
fi fi
- name: Clean up processed bookmark files - name: Clean up processed bookmark files
@@ -97,6 +127,20 @@ jobs:
# 使用 GITHUB_TOKEN 推送 # 使用 GITHUB_TOKEN 推送
if: steps.check_bookmark_files.outputs.found == 'true' if: steps.check_bookmark_files.outputs.found == 'true'
run: | run: |
echo "Checking git status before pushing..."
git status
echo "Checking bookmarks.user.yml existence before pushing..."
if [ -f bookmarks.user.yml ]; then
echo "bookmarks.user.yml exists with content:"
ls -la bookmarks.user.yml
echo "First 5 lines:"
head -n 5 bookmarks.user.yml
else
echo "WARNING: bookmarks.user.yml does not exist before pushing!"
fi
echo "Pushing changes to repository..."
git push "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" HEAD:${{ github.ref_name }} git push "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" HEAD:${{ github.ref_name }}
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -206,14 +206,15 @@ npm run dev
- 系统会扫描 `bookmarks` 目录查找最新的HTML书签文件 - 系统会扫描 `bookmarks` 目录查找最新的HTML书签文件
- 解析书签文件中的链接和文件夹结构 - 解析书签文件中的链接和文件夹结构
- 自动为书签分配适当的图标 - 自动为书签分配适当的图标
- 生成 `bookmarks.yml` 配置文件 - 生成 `bookmarks.user.yml` 配置文件(而不是直接修改 `bookmarks.yml`
- 处理完成后会自动清空 `bookmarks` 目录(防止重复处理) - 处理完成后会自动清空 `bookmarks` 目录(防止重复处理)
- 重新构建并部署网站 - 重新构建并部署网站
4. **注意事项** 4. **注意事项**
- 每次只处理一个书签文件,如有多个文件,系统会选择最新的那个 - 每次只处理一个书签文件,如有多个文件,系统会选择最新的那个
- 书签导入是构建时的一次性操作,不会在浏览器中保存或同步您的书签 - 书签导入是构建时的一次性操作,不会在浏览器中保存或同步您的书签
- 如果想要更新书签,可以直接编辑 `bookmarks.yml`,或重新导出书签文件并重新导入 - 如果想要更新书签,可以直接编辑 `bookmarks.user.yml`,或重新导出书签文件并重新导入
- 系统会优先使用 `bookmarks.user.yml`,如果同时存在 `bookmarks.yml`,它们的内容会被合并(用户配置优先)
### 自动化工作流程详解 ### 自动化工作流程详解
@@ -226,7 +227,7 @@ MeNav使用单一的GitHub Actions工作流处理书签导入与网站部署
2. **书签处理步骤**: 2. **书签处理步骤**:
- 自动检测 `bookmarks` 目录中的HTML文件 - 自动检测 `bookmarks` 目录中的HTML文件
- 使用 `bookmark-processor.js` 脚本处理书签文件 - 使用 `bookmark-processor.js` 脚本处理书签文件
- 生成/更新 `bookmarks.yml` 配置文件 - 生成/更新 `bookmarks.user.yml` 配置文件
- 提交更改(如有)并保存至仓库 - 提交更改(如有)并保存至仓库
- 自动清理已处理的HTML书签文件 - 自动清理已处理的HTML书签文件
@@ -241,10 +242,10 @@ MeNav使用单一的GitHub Actions工作流处理书签导入与网站部署
### 书签配置自定义 ### 书签配置自定义
处理后生成的 `bookmarks.yml` 文件可以手动编辑以进一步自定义: 处理后生成的 `bookmarks.user.yml` 文件可以手动编辑以进一步自定义:
```yaml ```yaml
# 自动生成的书签配置示例 # 自动生成的书签配置示例(用户自定义版本)
title: 我的书签 title: 我的书签
subtitle: 从浏览器导入的书签收藏 subtitle: 从浏览器导入的书签收藏
categories: categories:
@@ -265,7 +266,10 @@ categories:
- 重新组织书签分类结构 - 重新组织书签分类结构
- 添加或删除特定书签 - 添加或删除特定书签
**提示**: 尽管自动处理会清理原始HTML文件但修改后的 `bookmarks.yml` 会被保留,您可以随时手动编辑它来更新书签内容。 **提示**:
- 尽管自动处理会清理原始HTML文件但修改后的 `bookmarks.user.yml` 会被保留,您可以随时手动编辑它来更新书签内容
- 如果项目中同时存在 `bookmarks.yml``bookmarks.user.yml`,系统会合并两者的内容,以 `bookmarks.user.yml` 中的配置为优先
- 这种设计允许您在更新源仓库时保留自己的书签配置
### 模板说明 ### 模板说明

View File

@@ -18,11 +18,12 @@
git push git push
``` ```
4. GitHub Actions将自动处理书签文件生成`bookmarks.yml`,并重新构建站点 4. GitHub Actions将自动处理书签文件生成`bookmarks.user.yml`,并重新构建站点
## 注意事项 ## 注意事项
- 仅支持标准HTML格式的书签文件 - 仅支持标准HTML格式的书签文件
- 每次只会处理目录中最新的一个书签文件 - 每次只会处理目录中最新的一个书签文件
- 处理完成后,书签文件会被自动清除,以防止重复处理 - 处理完成后,书签文件会被自动清除,以防止重复处理
- 已导入的书签可以在生成的`bookmarks.yml`文件中查看和编辑 - 已导入的书签可以在生成的`bookmarks.user.yml`文件中查看和编辑
- 系统会优先使用`bookmarks.user.yml`的配置,如果存在`bookmarks.yml`,会自动合并两者的内容(用户配置优先)

View File

@@ -2,10 +2,12 @@ const fs = require('fs');
const path = require('path'); const path = require('path');
const yaml = require('js-yaml'); const yaml = require('js-yaml');
// 书签文件夹路径 // 书签文件夹路径 - 使用相对路径
const BOOKMARKS_DIR = path.join(__dirname, '..', 'bookmarks'); const BOOKMARKS_DIR = 'bookmarks';
// 输出配置文件路径 // 输出配置文件路径 - 使用相对路径
const OUTPUT_FILE = path.join(__dirname, '..', 'bookmarks.yml'); const OUTPUT_FILE = 'bookmarks.user.yml';
// 默认书签配置文件路径 - 使用相对路径
const DEFAULT_BOOKMARKS_FILE = 'bookmarks.yml';
// 图标映射根据URL关键字匹配合适的图标 // 图标映射根据URL关键字匹配合适的图标
const ICON_MAPPING = { const ICON_MAPPING = {
@@ -191,9 +193,10 @@ function generateBookmarksYaml(bookmarks) {
// 添加注释 // 添加注释
const yamlWithComment = const yamlWithComment =
`# 自动生成的书签配置文件 - 请勿手动编辑 `# 自动生成的书签配置文件 - 用户自定义版本
# 由bookmark-processor.js生成于 ${new Date().toISOString()} # 由bookmark-processor.js生成于 ${new Date().toISOString()}
# 若要更新请将新的书签HTML文件放入bookmarks/目录 # 若要更新请将新的书签HTML文件放入bookmarks/目录
# 注意此文件会覆盖bookmarks.yml中的同名配置
${yamlString}`; ${yamlString}`;
@@ -206,8 +209,8 @@ ${yamlString}`;
// 更新现有config.yml中的导航添加书签页面 // 更新现有config.yml中的导航添加书签页面
function updateConfigWithBookmarks() { function updateConfigWithBookmarks() {
const configFile = path.join(__dirname, '..', 'config.yml'); const configFile = 'config.yml';
const userConfigFile = path.join(__dirname, '..', 'config.user.yml'); const userConfigFile = 'config.user.yml';
// 优先使用用户配置文件,如果存在 // 优先使用用户配置文件,如果存在
const targetConfigFile = fs.existsSync(userConfigFile) ? userConfigFile : configFile; const targetConfigFile = fs.existsSync(userConfigFile) ? userConfigFile : configFile;
@@ -245,6 +248,10 @@ function updateConfigWithBookmarks() {
// 主函数 // 主函数
async function main() { async function main() {
console.log('Starting bookmark processing...');
console.log(`Current working directory: ${process.cwd()}`);
console.log(`Output file will be: ${OUTPUT_FILE} (absolute: ${path.resolve(OUTPUT_FILE)})`);
// 获取最新的书签文件 // 获取最新的书签文件
const bookmarkFile = getLatestBookmarkFile(); const bookmarkFile = getLatestBookmarkFile();
if (!bookmarkFile) { if (!bookmarkFile) {
@@ -254,21 +261,67 @@ async function main() {
try { try {
// 读取文件内容 // 读取文件内容
console.log(`Reading bookmark file: ${bookmarkFile}`);
const htmlContent = fs.readFileSync(bookmarkFile, 'utf8'); const htmlContent = fs.readFileSync(bookmarkFile, 'utf8');
// 解析书签 // 解析书签
const bookmarks = parseBookmarks(htmlContent); const bookmarks = parseBookmarks(htmlContent);
console.log(`Found ${bookmarks.categories.length} categories with bookmarks`); console.log(`Found ${bookmarks.categories.length} categories with bookmarks`);
if (bookmarks.categories.length === 0) {
console.error('ERROR: No bookmark categories found in the HTML file. Processing aborted.');
return;
}
console.log('Categories found:');
bookmarks.categories.forEach(cat => {
console.log(`- ${cat.name}: ${cat.sites.length} sites`);
});
// 生成YAML // 生成YAML
const yaml = generateBookmarksYaml(bookmarks); const yaml = generateBookmarksYaml(bookmarks);
if (yaml) { if (!yaml) {
console.error('ERROR: Failed to generate YAML from bookmarks. Processing aborted.');
return;
}
// 显示将要写入的YAML前几行
console.log('Generated YAML preview (first 5 lines):');
console.log(yaml.split('\n').slice(0, 5).join('\n') + '\n...');
try {
// 确保目标目录存在
const outputDir = path.dirname(OUTPUT_FILE);
if (!fs.existsSync(outputDir) && outputDir !== '.') {
console.log(`Creating output directory: ${outputDir}`);
fs.mkdirSync(outputDir, { recursive: true });
}
// 保存YAML文件 // 保存YAML文件
console.log(`Writing to: ${OUTPUT_FILE}`);
fs.writeFileSync(OUTPUT_FILE, yaml, 'utf8'); fs.writeFileSync(OUTPUT_FILE, yaml, 'utf8');
console.log(`Saved bookmarks configuration to ${OUTPUT_FILE}`);
// 验证文件是否确实被创建
if (fs.existsSync(OUTPUT_FILE)) {
const stats = fs.statSync(OUTPUT_FILE);
console.log(`Successfully saved bookmarks configuration to ${OUTPUT_FILE}`);
console.log(`Verified file exists: ${OUTPUT_FILE}`);
console.log(`File size: ${stats.size} bytes`);
console.log(`File permissions: ${stats.mode.toString(8)}`);
// 列出当前目录内容以确认
console.log('Current directory contains:');
fs.readdirSync('.').forEach(file => {
console.log(`- ${file}`);
});
} else {
console.error(`ERROR: File was not created: ${OUTPUT_FILE}`);
process.exit(1);
}
// 更新导航 // 更新导航
updateConfigWithBookmarks(); updateConfigWithBookmarks();
} catch (writeError) {
console.error(`ERROR writing file ${OUTPUT_FILE}:`, writeError);
process.exit(1);
} }
} catch (error) { } catch (error) {
console.error('Error processing bookmark file:', error); console.error('Error processing bookmark file:', error);

View File

@@ -17,40 +17,45 @@ function escapeHtml(unsafe) {
// 读取配置文件 // 读取配置文件
function loadConfig() { function loadConfig() {
let config = {}; let config = null;
// 读取默认配置
try {
const defaultConfigFile = fs.readFileSync('config.yml', 'utf8');
config = yaml.load(defaultConfigFile);
} catch (e) {
console.error('Error loading default config file:', e);
process.exit(1);
}
// 尝试读取用户配置并合并
try { try {
// 优先尝试读取用户配置
if (fs.existsSync('config.user.yml')) { if (fs.existsSync('config.user.yml')) {
const userConfigFile = fs.readFileSync('config.user.yml', 'utf8'); const userConfigFile = fs.readFileSync('config.user.yml', 'utf8');
const userConfig = yaml.load(userConfigFile); config = yaml.load(userConfigFile);
// 深度合并配置,用户配置优先
config = mergeConfigs(config, userConfig);
console.log('Using user configuration from config.user.yml'); console.log('Using user configuration from config.user.yml');
} else { }
// 如果没有用户配置,则使用默认配置
else {
const defaultConfigFile = fs.readFileSync('config.yml', 'utf8');
config = yaml.load(defaultConfigFile);
console.log('No user configuration found, using default config.yml'); console.log('No user configuration found, using default config.yml');
} }
} catch (e) { } catch (e) {
console.error('Error loading user config file:', e); console.error('Error loading configuration file:', e);
console.log('Falling back to default configuration'); process.exit(1);
} }
// 尝试读取书签配置并合并 // 尝试读取书签配置
try { try {
if (fs.existsSync('bookmarks.yml')) { let bookmarksConfig = null;
// 优先尝试读取用户书签配置
if (fs.existsSync('bookmarks.user.yml')) {
const userBookmarksFile = fs.readFileSync('bookmarks.user.yml', 'utf8');
bookmarksConfig = yaml.load(userBookmarksFile);
console.log('Using user bookmarks configuration from bookmarks.user.yml');
}
// 如果没有用户书签配置,则尝试读取默认书签配置
else if (fs.existsSync('bookmarks.yml')) {
const bookmarksFile = fs.readFileSync('bookmarks.yml', 'utf8'); const bookmarksFile = fs.readFileSync('bookmarks.yml', 'utf8');
const bookmarksConfig = yaml.load(bookmarksFile); bookmarksConfig = yaml.load(bookmarksFile);
console.log('Using default bookmarks configuration from bookmarks.yml');
}
// 添加书签页面配置 // 添加书签页面配置
if (bookmarksConfig) {
config.bookmarks = bookmarksConfig; config.bookmarks = bookmarksConfig;
// 确保导航中有书签页面 // 确保导航中有书签页面
@@ -63,8 +68,6 @@ function loadConfig() {
active: false active: false
}); });
} }
console.log('Loaded bookmarks configuration from bookmarks.yml');
} }
} catch (e) { } catch (e) {
console.error('Error loading bookmarks configuration:', e); console.error('Error loading bookmarks configuration:', e);
@@ -73,23 +76,6 @@ function loadConfig() {
return config; return config;
} }
// 深度合并配置对象
function mergeConfigs(defaultConfig, userConfig) {
if (!userConfig) return defaultConfig;
const merged = { ...defaultConfig };
for (const key in userConfig) {
if (typeof userConfig[key] === 'object' && !Array.isArray(userConfig[key])) {
merged[key] = mergeConfigs(defaultConfig[key] || {}, userConfig[key]);
} else {
merged[key] = userConfig[key];
}
}
return merged;
}
// 生成导航菜单 // 生成导航菜单
function generateNavigation(navigation) { function generateNavigation(navigation) {
return navigation.map(nav => ` return navigation.map(nav => `