惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

U
Unit 42
C
Cybersecurity and Infrastructure Security Agency CISA
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Know Your Adversary
Know Your Adversary
S
Securelist
I
Intezer
AWS News Blog
AWS News Blog
L
LINUX DO - 热门话题
P
Privacy International News Feed
Recent Announcements
Recent Announcements
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
博客园 - 聂微东
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Attack and Defense Labs
Attack and Defense Labs
N
News and Events Feed by Topic
The GitHub Blog
The GitHub Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
Schneier on Security
Schneier on Security
N
Netflix TechBlog - Medium
爱范儿
爱范儿
B
Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
CERT Recently Published Vulnerability Notes
Hacker News: Ask HN
Hacker News: Ask HN
Google DeepMind News
Google DeepMind News
Engineering at Meta
Engineering at Meta
Blog — PlanetScale
Blog — PlanetScale
WordPress大学
WordPress大学
S
Secure Thoughts
K
Kaspersky official blog
N
News | PayPal Newsroom
O
OpenAI News
Last Week in AI
Last Week in AI
C
Check Point Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Cyberwarzone
Cyberwarzone
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tor Project blog
大猫的无限游戏
大猫的无限游戏
Vercel News
Vercel News
D
Docker
Hugging Face - Blog
Hugging Face - Blog
T
Threat Research - Cisco Blogs
Cisco Talos Blog
Cisco Talos Blog
The Register - Security
The Register - Security
博客园 - 司徒正美
Martin Fowler
Martin Fowler
人人都是产品经理
人人都是产品经理
P
Palo Alto Networks Blog

少数派

派早报:Google 发布 Fitbit Air 等 - 少数派 「新人报到」確認需求,再開始 - 少数派 从 SOLO 独立开发者社区,我看到了越来越多开发者开始做自己的产品 - 少数派 我怎么管理那些"不常做,但总会忘"的生活事项 - 少数派 人形机器人量产元年,数据才是具身智能的“生死线” - 少数派 BuhoLaunchpad 高度还原 Mac 启动台:开发历程与思考 - 少数派 五年陪伴依然不舍,DIY 换壳后让罗技 MX Master 3 继续服役 - 少数派 新玩意 240|少数派的编辑们最近买了啥? - 少数派 一日一技|为什么你应该关闭 iOS 的键盘声音 - 少数派 我做了个插件和 Skills,一键提取任何网站的设计规范 Design.md - 少数派 住在三四线城市的你,该开始录播客了 - 少数派 甘南秘境,大白高国 - 少数派 AI的审美:谁让把我变成川内倫子 - 少数派 返工怎能不烦恼,打工人片单总有一部是你的「嘴替」 - 少数派 为了让「上厕所」更健康,我做了一个小工具 - 少数派 AI + Skill,能够让生成的文章去除 AI 味吗? - 少数派 新玩意|韶音OpenDots ONE 耳夹式耳机 - 少数派 《美满》| 在每一个春天的晚上相爱(362) - 少数派 新玩意|优篮子 PS01 MagSnap 磁吸支架 - 少数派 自我整合手记 | 我开始早睡了:用稳定规则,为自由托底 - 少数派 用龙虾(OpenClaw)两个多月,我最深的12个体会 - 少数派 听歌时间到,12 张你可能错过的 2025 华语乐坛好专辑 - 少数派 承诺能追吗 - 少数派 macOS 26启动台没了? 我做了个不一样的App启动器 - Keboard - 少数派 《四海为家的人》| INTJ对话INTJ(361) - 少数派 你发过的那些黑历史,是时候一次清干净了 - 少数派 新玩意:安安静静玩,越玩越专注:计客密码机 - 少数派 iPad 用户首次体验 Android 平板:vivo Pad6 Pro - 少数派 数据逻辑强 - 少数派 极北行+ | 一路向北,探访日本至北之地 | 001 - 少数派 万字剖析:千问App深度体验报告(2026) - 少数派 在2026年,如何真正防止别人抄袭你的作品 - 少数派 怎么用 50 块搭个 AI 语音助手?我踩了 3 天坑 - 少数派 YeeroAI:让 AI 对话真正成为知识管理的一部分 - 少数派 爬泰山 - 少数派 「旅图显影」 App 更新:这次,我们补上了一点「手感」 - 少数派 假期出门太折磨?我的 23 条经验帮你规划惬意旅行 - 少数派 工作流会变吗 - 少数派 Claude Opus 4.6 怎么用最省钱?我测了 5 种方案 - 少数派 GPT Image 2 让图文并茂不再稀罕 - 少数派 用户侧出发——什么是AI,我要不要学习? - 少数派 找片、转存、整理、播放一条龙!让你的付费网盘值回票价 - 少数派 欢迎试用!日课一问2.0插件 - 少数派 自己做的MDeditor,原本想购买 Typora 试了两次支付不成功,干脆自己做一个 - 少数派 vibe coding了一个 3MB 的小工具,让 ~/Downloads 彻底告别混乱 - 少数派 因为受不了 Mac 的风扇策略,我做了一个风扇控制工具 - 少数派 别只怪模型 - 少数派 Warp 终端的 AI 功能怎么用?我测了一周的体验 - 少数派 AI 写代码老是出 bug?这 5 个配置我后悔没早知道 - 少数派 「新玩意」苹果出相机可能就这样:Sigma BF + 45mm F2.8 DG Contemporary - 少数派 一个面向2030年的AI操作系统是什么样子的:浅谈cola这款有灵魂的Agent - 少数派 别只看写代码 - 少数派 每天解决10个问题,还是一口气攻坚解决400个? - 少数派 AI 交易机器人怎么搭?我用 Claude 跑了一周实盘 - 少数派 Maptoposter Online:把你爱的城市画成艺术海报 - 少数派 Function Calling 怎么用?我测了 3 个模型发现差距真大 - 少数派 Legend Talk:我做了个 AI 圆桌,让 160 位思想家围着你的问题转 - 少数派 如何找到自己的蓝方?在小县城寻找压力测试 - 少数派 语音输入与软件接口|2026年聊AI时,我们都聊些什么(上) - 少数派 混动已经卖爆,纯电又来补刀——钛7闪充版简直“不讲武德” - 少数派 本月玩什么|朋友收藏、识质存在、沙罗周期 - 少数派 为什么要每天坚持输出? - 少数派 Claude API 挂了好几个小时,你的项目有备用方案吗? - 少数派 Function Calling 没你想的复杂——我用它做了个有点用的工具 - 少数派 登录系统立即播放视频或者图片音乐的软件 - 少数派 我为什么创建 FlipHTML5 下载工具 - 少数派 残局没电?多品牌外设电量统一管理软件EasyBluetooth已支持RTSS游戏内显示以及AIDA64 - 少数派 前往通义路的路 - 少数派 太好看了,媲美Sun的个人导航页,NAS部署星云门户 - 少数派 乌黑嘴唇“一键检测”上线了 - 少数派 派早报:Claude AI 接入多个创意软件生态、FILCO 生产方接手品牌等 - 少数派 【更新】BearCLI、Claude 连接器与 MCP 服务器 - 少数派 记了上千条流水,还是看不懂财务?我做了一个让 AI 读懂账本的工作台 - 少数派 MINI R56 升级原厂 Sport 模式 - 少数派 新玩意 | 一棵柠檬树(仿真版) - 少数派 Momenta的“物理AI”野望,需迈过“含摩量”这道关 - 少数派 网页直接投屏控制手机!NAS一键部署PandaScrcpy,流畅丝滑可远程。 - 少数派 众测|邀你一同探索随身 AI 硬件入口 YoooClaw C·ONE - 少数派 2050大会:分享时间是真诚 参会记 - 少数派 iPad 赋能电影创作:国内首部宣纸手绘长片《燃比娃》的幕后故事 - 少数派 AI的审美:我用 8 个大模型给 100 张旅行照片打分 - 少数派 普通人如何破圈?去参加一个本地协会 - 少数派 把极空间的图标全换了,主题DIY全攻略打造你的专属NAS桌面 - 少数派 电子便签墙,帮你实现便签自由 - 少数派 我如何用三个 CLI 工具取代文档创建需求 - 少数派 原来真的有人可以玩一辈子 - 少数派 社区速递 139 | 派友热议三月买了啥、复古单反尼康 Df 体验 - 少数派 06 作品的赏析与评价 - 少数派 TDS REVIEW|索尼 WF-1000XM6 降噪真无线耳机体验 - 少数派 35.98万起售的第二代腾势D9,我看重的不是堆料,而是不凑合 - 少数派 鼠须管 Squirrel 皮肤配置指北 - 少数派 从watch ultra2换到redmi watch6 - 少数派 派早报:阿里巴巴发布视频生成模型 HappyHorse 1.0 等 - 少数派 别迷信1M - 少数派 家人们天塌了!网盘“大封杀”,多个渠道多条路,NAS部署PanHub - 少数派 AI与人勾心斗角!NAS一键部署AI狼人杀,假日休闲必备。 - 少数派 电商必备!Comfyui工作流批量生图插件,一次生成12张!支持Nano banana pro模型 - 少数派 Comfyui工作流配置Gpt-image-2模型教程,0.03/张 - 少数派 OpenClaw第三方APi怎么配置?可使用Gpt-image-2模型 - 少数派 会员社区话题精选 Ep. 103 - 少数派
Obsidian 修改annotator引用格式,外链图片转图床,根据字幕跳转视频 - 少数派
2022-09-27 · via 少数派

使用 Obsidian 的过程中发现一些痛点:

1> 使用插件 annotator 时,引用的文本内不能添加链接

如果强行将关键字改成链接,就会出现格式错乱

我想要的效果如下:引用的文本能够给添加链接

2> 使用简悦剪藏文章时 ,文章内的图片是外链。如果图片是外链,那么如果外链链接失效了就找不回图片了

我想要的效果如下:将外链转为图床的链接

3> Media Extended 虽然能使用链接跳转到视频指定时间点,但是手写链接太麻烦了

我想要的效果:自动生成一个视频的全部字幕和引用,且每句字幕和一点时间点引用呈一一对应的关系

❗❗❗为了节省大家的时间,我在文末写了我常用的 Obsidian 插件的下载链接,这些插件中有部分插件的源码都是被我修改过的,有两个需要注意的事项:

  • 被我修改过源码的插件不全是可以直接用的,比如发送图片到 Picgo 时的 url 要换成你在 Picgo 内设置的 url
  • 修改过源码的插件不要升级,如果升级了会导致修改失效

❗❗❗再附加一个注意事项:

  • 入门简悦的时候如果运气不好(比如我),会遇到很多问题,如果看了入门文章还是解决不了就到 https://github.com/Kenshin/simpread/issues 提交自己的问题,简悦的开发者回复消息还是挺快的(顺便夸夸开发者很积极,这很难得)

使用工具

Annotator:是一个用于给 pdf 做标注和跳转的开源插件

Linter:是一个用于格式化笔记的开源插件

配置 Linter

目标:修改其源代码,添加将 Annotator 样式修改为 📌

添加规则分类:

添加具体的规则处理:

代码如下:

new Rule('Reform Annotation', '修改 Annotation 链接的样式', RuleType.MINE, (text, options = {}) => {  
    const searchRegex = new RegExp(`${options['Find']}`, "gm");  
    text = text.replace(searchRegex, `${options['Replace']}`);  
    return text;  
},[  
], [  
    new TextOption('Find', 'regular expression for finding', "\\[\\[([^@]+)@annote#([^|]+)\\|([^📌\\]]+)\\]\\]"),  
    new TextOption('Replace', 'result of replacement', '[[$1@annote#$2|📌]]$3')  
])

保存后退出 ide,并重启 Obsidian,打开 Linter 的设置,并开启新功能的开关

测试一下:
(测试前)


(测试后)

外链图片转图床

使用工具

简悦(版本为 2.2):这是一个可以把网页文章保存为本地 markdown 格式笔记的工具

配置 Linter

修改 Linter 源代码,添加可以将图片外链转换成自己图床的链接
ps. 我使用的图床是 github,并且使用 PicGo 快速上传图片到图床。

首先引入 http、https、fs 库

var fs = require('fs');  
var http = require('http');  
var https = require('https');

添加自定义的方法

ps. 我的前端能力很菜很菜,献丑了。大佬们可以自己写这部分的功能。这段代码的逻辑就是先在本地新建一个文件夹 temp_pic_folder,然后通过正则表达式匹配到图片链接,然后通过这些链接把图片一个一个下载到文件夹 temp_pic_folder 中,然后再把下载下来的图片一个一个上传到用户设置的图床中,并修改文章中这些图片链接为最终图床上的图片链接,最后再把文件夹 temp_pic_folder 及其内部的图片都从本地删了。
注意!我这段代码只能匹配末尾有图片文件后缀名的链接,如 https://xxxx/xxx/.../xxx.jpg,如果是 https://xxxx/xxx/.../xxx 就不能识别,别问我为什么不处理这种情况,懒且够用

/**  
 * 将外链图片链接转换为自己的图床链接  
 *  
 * @param text 文档的文本  
 * @param options 插件在 setting tab 的设置  
 */  
async changeOuterLink (text, options = {}, app) {  
    // 获取当前编辑文档的所在文件系统的绝对地址  
    const tempFolder = "temp_pic_folder";  
    const anchorFile = "anchor_file";  
    const parentPath = app.vault.getAbstractFileByPath(app.workspace.getActiveFile().path).parent.path;  
    // 以 \ 为分隔符的就当作是 path    const tempFolderRelativePath = parentPath + "\\" + tempFolder;  
    // 以 / 为分隔符的就当作是 url    const tempFolderRelativeUrl = parentPath + "/" + tempFolder;  
    const anchorFileRelativeUrl = tempFolderRelativeUrl + "/" + anchorFile;  
    const basePath = app.vault.adapter.getBasePath();  
    const absolutePath = basePath + "\\" + tempFolderRelativePath;  

    // 匹配图片网址的正则表达式(已测网站图床包括:知乎、CSDN等)  
    const searchRegex = new RegExp(`${options['Image regex']}`, "gm");  

    // 自己图床的 url    let myPicBedUrl = `${options['Host']}` + `${options['Repository']}`;  
    // 已经下载的文件的列表  
    let fileList = [];  
    // 文件名到其相应文件后缀的映射  
    let fileExtMap = {};  
    // 下载图片后返回的多个 promise    let promiseList = [];  
    // 存放图片的文件夹里的文件列表  
    let tempFileSet = new Set();  

    let folderAbstractFile = app.vault.getAbstractFileByPath(tempFolderRelativeUrl);  
    if (folderAbstractFile) {  
        // 将文件名保存到 set 中  
        let downloadedPicList = app.fileManager.getNewFileParent(anchorFileRelativeUrl).children;  
        for (let i = 0; i < downloadedPicList.length; i++) {  
            tempFileSet.add(downloadedPicList[i].basename);  
        }  
    } else {  
        // 创建存放图片的文件夹  
        await app.vault.createFolder(tempFolderRelativePath);  
        folderAbstractFile = app.vault.getAbstractFileByPath(tempFolderRelativeUrl);  
        await app.vault.create(anchorFileRelativeUrl, "");  
    }  

    text = text.replace(searchRegex, (rs, $1, $2) => {  
        // 检查是否是自己图床的图片  
        if ($1.indexOf(myPicBedUrl) === -1) {  
            // 检查本地是否已经下载  
            let picName = $1.slice($1.lastIndexOf('/') + 1).toString();  
            if (!tempFileSet.has(picName)) {  
                let perPromise = new Promise((resolve, reject) => {  
                    let request;  
                    if ($1[4] === "s") {  
                        request = https.get($1 + $2, (res) => {  
                            if (res.statusCode !== 200) {  
                                console.log("download image error!");  
                                return;                            }  
                            let ext = res.headers['content-type'].split('/')[1];  
                            let dest = absolutePath + "\\" + picName + "." + ext;  
                            let file = fs.createWriteStream(dest);  

                            res.on('end', () => {  
                                console.log("图片下载完毕");  
                            });  

                            // 进度、超时等  
                            file.on('finish', () => {  
                                file.close();  
                                fileList.push(dest);  
                                fileExtMap[picName] = ext;  
                                resolve();  
                            }).on('error', (err) => {  
                                fs.unlink(dest);  
                            });  
                            res.pipe(file);  
                        });  
                    } else {  
                        // todo http 的不管用  
                        // 和 https 一样的代码  
                    }  
                    request.on('error', reject);  
                    request.end();  
                });  
                promiseList.push(perPromise);  
            } else {  
                console.log("图片已存在");  
            }  
        } else {  
            console.log("自己的地址");  
        }  
        return rs;  
    });  

    return Promise.allSettled(promiseList)  
        .then((results) => {  
            console.log("文件列表 " + fileList);  
            if (fileList.length > 0) {  
                return new Promise((resolve, reject) => {  
                    const postOptions = {  
                        hostname: `${options['PicGoUrl']}`,  
                        port: `${options['PicGoPort']}`,  
                        path: `${options['PicGoPath']}`,  
                        method: 'POST',  
                        headers: {  
                            'Content-Type': 'application/json'  
                        }  
                    }  

                    const req = http.request(postOptions, async res => {  
                        if (res.statusCode === 200) {  
                            console.log("删除图片文件夹 " + folderAbstractFile.path);  
                            await app.vault.delete(folderAbstractFile, true);  
                            // 正则替换图片地址  
                            text = text.replace(searchRegex, (rs, $1) => {  
                                console.log("替换链接名");  
                                // 根据文件名在 map 中找到对应的后缀  
                                let picName = $1.slice($1.lastIndexOf('/') + 1);  
                                let ext = fileExtMap[picName];  
                                return "![](" + myPicBedUrl + picName + "." + ext;  
                            });  
                        } else {  
                            console.log("上传失败");  
                        }  
                        resolve(text);  
                    });  

                    req.on('error', error => {  
                        console.error(error);  
                        reject(error);  
                    });  

                    req.write(JSON.stringify({list: fileList}));  
                    req.end();  
                });  
            } else {  
                return new Promise((resolve, reject) => {  
                    resolve(text);  
                });  
            }  
        });  
}

该方法调用处也要做修改:

因为 changeOuterLink 方法是异步的,所以调用该方法的地方要加上 await

然后在 rules 上添加新的规则

new Rule('Upload Image', 'Switch', RuleType.MINE, (text, options = {}, app, changeOuterLink) => {  
    return changeOuterLink(text, options, app);  
},[  
], [  
    new TextOption('PicGoUrl', '', "127.0.0.1"), 
    //  PicGoPort 是 picgo 默认的端口号
    new TextOption('PicGoPort', '', "36677"),  
    new TextOption('PicGoPath', '', "/upload"),  
    new TextOption('Host', 'target host', "https://raw.githubusercontent.com"),  
    // Repository 为 github 的仓库名
    new TextOption('Repository', '', "/xxx/xx/"),  
    new TextOption('Image regex', '', '\\!\\[[^\\[\\]]*\\]\\(([a-zA-z]+://[^/]+/[^.?)]+)([^)?]*)')  
])

根据字幕跳转视频

使用工具

Media Extended:使用这个插件能够播放网络视频并能跳转进度条(我已测试能行的网站有 youtube,其他没试过)

Media Extended BiliBili Plugin:这个插件是支持播放 bilibili 视频并能跳转进度条的插件

Regex Find and Replace:该插件可用于正则表达式查找和替换

Language Reactor:这是个 chrome 插件,可以在看 youtube 的时候把英文字幕翻译成中文(或其他语言),并且能选中字幕中的单词查看释义甚至可以把单词加入生词库,在生词库可以使用类似 anki 的复习方式背诵单词

安装 chrome 插件

设置 Regex Find and Replace

修改该插件的源代码

// 匹配 xxs
let regDocumentText = documentText.replace(/(^[0-5]?[0-9])s$/gm, (rs, $1) => {  
    return ">👇[" + $1 + "s](" + replaceString + "#t=" + $1 + ")";  
});  

// 匹配 mm:ssregDocumentText = regDocumentText.replace(/(^[0-5]?[0-9]):([0-5][0-9])$/gm, (rs, $1, $2) => {  
    return ">👇[" + $1 + ":" + $2 + "](" + replaceString + "#t=" + ($1 * 60 + $2 * 1) + ")";  
});  

// 匹配 hh:mm:ssregDocumentText = regDocumentText.replace(/((^[0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]))$/gm, (rs, $1, $2, $3) => {  
    return ">👇[" + $1 + ":" + $2 + ":" + $3 + "](" + replaceString + "#t=" + ($1 * 60 * 60 + $2 * 60 + $3 * 1) + ")";  
});  

editor.setValue(regDocumentText);

第一个正则表达式 ([0-5]?[0-9])s$ 是转换 xxs\n 格式的字符串
第二个正则表达式 ([0-5]?[0-9]):([0-5][0-9]) 是转换 m:ssmm:ss 格式的字符串
第三个正则表达式 (([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]))$ 是转换 hh:mm:ss 格式的字符串
以上统一最终转换为 >👇[$1s](网址#t=$1)

之所以要设置以上正则,是为了匹配 Language Reactor 生成的字幕文件,下面工作流会介绍到

然后设置一下该插件的快捷键:

导出视频的中英字幕

先打开 Language Reactor

20220521214053.png

一开始打开某个视频可能默认是中文字幕,要改成英文的:

点击 设置 查看字幕情况:

(一般没有人类翻译的话相应的单选框是选择不了的)
因为根据上图可以知道这个视频是有人类翻译的,所以导出字幕时可以仅仅导出英文字幕和人类翻译:
 

接着按 导出 就会弹出字幕的 html:

接着 ctrl + a 全选整个 html 并且 ctrl + c 复制:

新建新的关于这个视频笔记的 markdown 并插入自己设置好的视频模板(其实就只是一些元数据):

接着在这个 markdown 里 ctrl + v 一下,可以看到复制进来了,并且把选中的这三行没用的信息删了:

使用正则替换修改字幕笔记的格式

复制一下视频的地址:

回到刚刚新建的笔记,按 ctrl + alt + f 进行正则替换:

可以看到替换成功了 👇

注意:想跳转视频一定要切换到 查看视图

20220521220838.png

结尾

这篇文章末尾就不写参考了,因为纯纯是我的经验分享,如有雷同是他抄我的。
该给的链接都给了,希望大家不要忘了给那些开源插件点个 star 哦~

我常用的 Obsidian 插件链接:

链接:https://pan.baidu.com/s/1i-eKm4UdqXAigvwUEQn8QQ

提取码:oyac

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!