导航站增加导出为书签格式文件功能

说明

此次调整是为提高静态导航的自由度及降低我的网站的过量访问增加的这个功能,同时降低站长角色为仅收录推送、定期维护站点的角色,你可以在导航站的右下角侧边图标中选择一键导出下载为浏览器书签格式文件,你可以通过近期收录的标签星球等精选app将书签设置为自己的浏览器新标签页

1728305924402

附:导航本身是为个人及所需要了解不同站点的人群而服务,本次增加的功能为对其部署运行的API发送请求并接受新文件,路由为:”/api/export-bookmarks“,同时你也可以在导航中找到检测失效网站的记录,记录会保留,如有误删的你也可以随时提醒我。

此次是在nav-manage这个项目上所增加的新路由,更新文件为本地及云服务器server文件,更新代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// 输出书签格式的目录
const BOOKMARKS_OUTPUT_DIR = path.resolve('/请修改为你的文件实际路径/bookmarks/');

// 确保目录存在的辅助函数
async function ensureDirectoryExists(dirPath) {
try {
await fs.promises.access(dirPath);
} catch (error) {
if (error.code === 'ENOENT') {
await fs.promises.mkdir(dirPath, { recursive: true });
} else {
throw error;
}
}
}

// 删除文件的辅助函数
async function deleteOldBookmarks(dirPath) {
const files = await fs.promises.readdir(dirPath);
const now = Date.now();

for (const file of files) {
const filePath = path.join(dirPath, file);
const stats = await fs.promises.stat(filePath);

// 检查文件是否超过 3 分钟(180000 毫秒)
if (now - stats.mtimeMs > 180000) {
await fs.promises.unlink(filePath);
console.log(`Deleted old bookmark file: ${filePath}`);
}
}
}

// 启动定时器每 3 分钟检查并删除旧文件
setInterval(() => {
deleteOldBookmarks(BOOKMARKS_OUTPUT_DIR).catch(err => console.error('Error deleting old bookmarks:', err));
}, 180000); // 180000 毫秒 = 3 分钟

// 导出为书签格式的路由
app.get('/api/export-bookmarks', async (req, res) => {
console.log('Received request for export-bookmarks:', req.query);
const { outputDir } = req.query; // 从查询参数获取输出目录
const dataDir = path.resolve('请修改为你的文件实际路径/data/');
const bookmarks = [];

// 确保输出目录存在
const outputPath = path.resolve(outputDir || BOOKMARKS_OUTPUT_DIR);
await ensureDirectoryExists(outputPath);

const yamlFiles = await fs.promises.readdir(dataDir);

for (const file of yamlFiles) {
if (file.endsWith('.yaml') || file.endsWith('.yml')) {
const filePath = path.join(dataDir, file);
const yamlContent = await fs.promises.readFile(filePath, 'utf8');
const yamlData = yaml.load(yamlContent);

yamlData.forEach(category => {
// 添加一级标题
const taxonomyTitle = category.taxonomy;
if (taxonomyTitle) {
bookmarks.push({ title: taxonomyTitle, url: '', isHeader: true });
}

if (Array.isArray(category.links)) {
category.links.forEach(link => {
bookmarks.push({ title: link.title, url: link.url });
});
}

if (Array.isArray(category.list)) {
category.list.forEach(subCategory => {
// 添加二级标题
const termTitle = subCategory.term;
if (termTitle) {
bookmarks.push({ title: termTitle, url: '', isHeader: true });
}

if (Array.isArray(subCategory.links)) {
subCategory.links.forEach(link => {
bookmarks.push({ title: link.title, url: link.url });
});
}
});
}
});
}
}

// 生成书签 HTML
let bookmarkHtml = '<!DOCTYPE NETSCAPE-Bookmark-file-1>\n';
bookmarkHtml += '<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">\n';
bookmarkHtml += '<TITLE>Bookmarks</TITLE>\n<H1>Bookmarks</H1>\n<DL><p>\n';

bookmarks.forEach(bookmark => {
if (bookmark.isHeader) {
bookmarkHtml += ` <DT><H3 ADD_DATE="${Date.now()}">${bookmark.title}</H3>\n`;
} else {
bookmarkHtml += ` <DT><A HREF="${bookmark.url}">${bookmark.title}</A>\n`;
}
});

bookmarkHtml += '</DL><p>';

// 写入书签文件
const outputFilename = `bookmarks_${Date.now()}.html`;
const fullOutputPath = path.join(outputPath, outputFilename);
await fs.promises.writeFile(fullOutputPath, bookmarkHtml, 'utf8');

// 直接下载生成的书签文件
res.download(fullOutputPath, outputFilename, (err) => {
if (err) {
console.error('Error downloading file:', err);
res.status(500).send('文件下载失败');
}
});
});

功能

一、导出导航站yml文件为浏览器书签格式html文件,带有导航站本身的一级目录标题及二级目录标题并设置输出路径下生成的文件自动3分钟删除

二、导入浏览器书签格式文件并增加到原始yml文件

还未增加到前端扩展中,也会随时间推移再调整,你也可以自行随意调整更改