吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1262|回复: 24
收起左侧

[其他原创] 浏览器书签管理

[复制链接]
Su007 发表于 2026-9-22 16:43

一个浏览器扩展:跨文件夹任意勾选书签,聚合成一个文件导出。
支持 HTML(浏览器可直接导入)、JSON、Markdown、CSV 四种格式。纯本地运行,不联网、不收集任何数据。

shot-01-main.png

它能做什么

  • ✅ 跨层级任意勾选:书签、文件夹、跨文件夹混着选,三态复选框(全选 / 部分选中 / 未选)一目了然
  • ✅ Shift 区间连选:点第一项,按住 Shift 点另一项,中间整段一起选中,跟文件管理器一样;对已选中区间 Shift 点击则整段取消
  • ✅ 四种导出格式:
格式 用途
HTML(Netscape 格式) 浏览器「导入书签」直接还原,层级完整保留
JSON 备份 / 程序处理
Markdown 发帖、笔记、分享
CSV(带 BOM) Excel 直接打开,含 folder_path 列
  • ✅ 复制按钮:不下载文件,直接把「标题 + 链接」的 Markdown 列表复制进剪贴板,粘贴到聊天 / 文档即用
  • ✅ 搜索过滤:按标题 / URL 实时搜索,在结果里直接勾选
  • ✅ 网址去重:跨文件夹勾选时同一网址只保留一条(忽略末尾斜杠与大小写)
  • ✅ 自动清理:空文件夹不导出、无标题书签用网址兜底、选项自动记忆
  • ✅ 直接整理书签:勾选书签后(可跨文件夹、跨层级各自勾选),鼠标移到目标文件夹行上的 ⊕ 移到此 即可整批移入;文件夹行 +新建 / 顶部 +新建 可就地建子文件夹或顶层文件夹。把"剪切到临时文件夹再导出"也省了
  • ✅ 删除:勾选后点工具栏红色「删除」(带确认条,不可恢复)。删文件夹会连同子项一起删;书签栏 / 其他书签等根容器受保护不会被删

浏览器兼容性

  • Chrome / Edge / QQ 浏览器 / Firefox 等标准内核:读、导出、移动、新建、删除全部正常。
  • 360 极速浏览器 X:读 / 导出正常,但新建 / 移动 / 删除不可用——这是 360 自身的书签写入接口缺陷(chrome.bookmarks 的 create / move / remove / update 全部返回 Bookmark id is invalid,360 社区多人反馈、暂无官方修复,非本工具 bug)。本工具通过运行时实测探测(建一个临时文件夹再删,若 create 报错即判定写入接口不可用,不靠浏览器 UA 嗅探)识别此类缺陷,命中后页面显示提示条、并直接置灰「新建 / 删除」按钮、隐藏文件夹行的「移到此 / 新建」,写入报错也会给出明确原因。整理书签请改用 Chrome / Edge。

    两种导出结构,按需选择

shot-04-compare.png

  • 保留层级(默认):勾了文件夹就带文件夹名,导入后分组完整。适合备份和迁移。
  • 扁平导出:只输出链接,不带任何文件夹。适合临时凑一批链接分享、导入到别处。

另有「去掉根容器外壳」选项(默认开):导入后不会多出「书签栏 / 其他书签」这一层无意义的嵌套。每个选项都有悬浮说明,鼠标放上去就能看到解释。

shot-03-tip.png

Shift 区间连选

几百条书签里挑连续的一段?点第一个,按住 Shift 点最后一个,中间整段选中。折叠的分支不参与(只按当前可见顺序),搜索结果列表里同样可用。
shot-02-shift.png

隐私说明(重点)

  • 仅申请 bookmarks 一个权限,用于读取你勾选的内容
  • 不申请网络、下载、存储等任何其他权限——导出动作就是浏览器原生的文件保存
  • 所有逻辑跑在你本地,代码全部开源可审查,总共几百行,无构建、无混淆

    相关代码

1) 三态勾选的状态模型(取消某个子项时,把"整选的父文件夹"展开成"兄弟节点逐个勾选",这样导出时不会有空文件夹、也不会父子重复):

// 取消某节点时:把它的"已被整选的祖先"拆成兄弟节点的显式勾选,使该节点不再被祖先覆盖
function materializeAncestors(id) {
  let cur = id;
  const exclude = new Set([id]);
  const guard = new Set();
  while (cur != null && !guard.has(cur)) {
    guard.add(cur);
    const p = parentOf.get(cur);
    if (p == null) break;
    if (selected.has(p)) {
      selected.delete(p);
      const pn = index.get(p);
      if (pn && pn.children) {
        for (const c of pn.children) if (!exclude.has(c.id)) selected.add(c.id);
      }
    }
    exclude.add(p);
    cur = p;
  }
}

function setChecked(id, checked) {
  const n = index.get(id);
  if (!n) return;
  clearCache();
  if (checked) {
    if (ancestorSelected(id)) return; // 祖先已整选时跳过,避免父子重复入列
    selected.add(id);
    walk(n, (d) => { if (d.id !== id) selected.delete(d.id); });
  } else {
    materializeAncestors(id);
    selected.delete(id);
  }
  clearCache();
}

2) 生成可被任意浏览器导入的 Netscape HTML(这套格式 Chrome / Edge / Firefox / Safari 都能直接「导入书签」还原层级):

function toNetscapeHtml(nodes) {
  const out = ['<!DOCTYPE NETSCAPE-Bookmark-file-1>',
    '<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">',
    '<TITLE>Bookmarks</TITLE>', '<H1>Bookmarks</H1>', '<DL><p>'];
  const walk = (list, depth) => {
    const pad = '    '.repeat(depth + 1);
    for (const n of list) {
      if (isFolder(n)) {                       // 文件夹 → <H3> 包一层 <DL>
        out.push(`${pad}<DT><H3 ADD_DATE="${toSec(n.dateAdded)}">${escapeHtml(n.title)}</H3>`);
        out.push(`${pad}<DL><p>`);
        if (n.children) walk(n.children, depth + 1);
        out.push(`${pad}</DL><p>`);
      } else {                                  // 书签 → <A HREF>
        out.push(`${pad}<DT><A HREF="${escapeHtml(n.url)}" ADD_DATE="${toSec(n.dateAdded)}">${escapeHtml(n.title)}</A>`);
      }
    }
  };
  walk(nodes, 0);
  out.push('</DL><p>');
  return out.join('\n') + '\n';
}

3) 移动书签 + 拦截"移进自己子文件夹"成环(新功能:跨文件夹勾选书签后整批移入目标文件夹;hasDescendant 防止把文件夹丢进自己的子树里导致书签丢失;移动后用 parentOf 核对是否真的落位,避免"API 报成功却没动"的假成功):

// 判断 maybeChild 是否为 ancestor 的子孙(拦截成环移动)
function hasDescendant(ancestorId, maybeChildId) {
  const a = index.get(ancestorId);
  if (!a || !a.children) return false;
  let found = false;
  walk(a, (n) => { if (n.id === maybeChildId) found = true; });
  return found;
}

// 把当前勾选的全部移入 targetId 下;移进自身或自身子树则跳过
async function moveSelectedTo(targetId) {
  if (targetId == null) return { moved: 0, skipped: 0 };
  const ids = Array.from(selected);
  let moved = 0, skipped = 0;
  for (const id of ids) {
    if (id === targetId) { skipped++; continue; }
    if (hasDescendant(id, targetId)) { skipped++; continue; }
    await call(api.move, id, { parentId: targetId });
    moved++;
  }
  selected.clear();
  clearCache();
  return { moved, skipped };
}

4) 删除书签 / 文件夹(勾选后工具栏「删除」:书签用 remove,文件夹用 removeTree 连子项一起删;顶层根容器受保护不删,且沿用上面的 call 会在出错时抛真实错误而不是假成功):

async function removeSelected() {
  const ids = Array.from(selected);
  if (!ids.length) return { removed: 0, skipped: 0 };
  let removed = 0, skipped = 0, lastErr = null;
  for (const id of ids) {
    const n = index.get(id);
    if (!n) { skipped++; continue; }
    if (parentOf.get(id) == null) { skipped++; continue; } // 根容器(书签栏/其他书签)不可删
    try {
      if (isFolder(n)) await call(api.removeTree, id);
      else await call(api.remove, id);
      removed++;
    } catch (e) { skipped++; lastErr = e; }
  }
  selected.clear();
  clearCache();
  if (removed === 0 && lastErr) throw lastErr; // 一条都没删成 → 抛出真实错误
  return { removed, skipped };
}

完整代码

蓝奏 https://wwbfw.lanzoue.com/b00mqnko2j 密码:52pj
百度网盘 https://pan.baidu.com/s/1ROGpsfvngLSbuJ6RVb_K0w?pwd=52pj 提取码: 52pj

免费评分

参与人数 5吾爱币 +11 热心值 +2 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Kayay + 1 我很赞同!
☆木木可可★ + 1 + 1 谢谢@Thanks!
wa1111 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
LFNT2010 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

eryuetiankong 发表于 2026-9-23 09:43
Su007 发表于 2026-9-23 09:34
这是运行中出现的错误吗,我检查一下

浏览器插件管理里的提示。Ai说:
`browser_specific_settings` 是 **Firefox(Gecko)专属 manifest 字段**,**Chrome / Edge(Chromium 内核)不认识这个 key**,所以在 Chrome 加载已解压扩展时抛出 `Unrecognized manifest key` 警告(&#9888;&#65039; 警告不是致命错误,扩展**大概率还能跑**,只是 Chrome 忽略这一段)MDN Web Do...。
这段作用:给 Firefox 指定扩展 ID、最低兼容 Firefox 版本,**Firefox Manifest V3 必须要有这个字段才能签名打包**
eryuetiankong 发表于 2026-9-23 08:11
Unrecognized manifest key 'browser_specific_settings'.
  "browser_specific_settings": {
    "gecko": {
      "id": "bookmark-partial-export@local",
      "strict_min_version": "109.0"
    }
  }
sholincong 发表于 2026-9-22 16:58
afti 发表于 2026-9-22 18:30
可被任意浏览器导入,这就很方便了
fuvenusck 发表于 2026-9-22 19:28
书签分组更合理了
wentao520 发表于 2026-9-22 19:58
这个工具好,很实用
cxwapj66 发表于 2026-9-22 21:22
这个好,很不错
WWsrg7790 发表于 2026-9-22 21:25
我来试试,标签确实是个头疼的东西。得整理一下
wa1111 发表于 2026-9-22 22:57
这个好,很不错,一直想要这样的功能呢,感谢分享
52up 发表于 2026-9-23 07:13
谢谢分享,书签多了,正好有类似的需求
1f2a 发表于 2026-9-23 07:56
来晚了,前几天被360浏览器恶心到了,极速浏览器不能保存网页状态每次关闭打开都要重新登陆,安全浏览器180M的安装包,安装完毕文件夹1.5G,什么游戏大厅,壁纸软件塞了一大推全家桶,最后导出收藏夹,安家火狐了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-10-9 14:44

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表