-
[js] 英语学习者的福音,一键播放音频链接
2024-12-19 01:47【建议根据下面的介绍,动手一步步试试,更容易理解】
和插入一个普通的链接一样。
比如,你的链接是
https://res.iciba.com/resource/amp3/1/0/75/5f/755f85c2723bb39381c7379a604160d8.mp3
,没有用这个代码片段前,你点击这个链接会跳转到浏览器,然后会显示一个音频播放器播放这个音频。使用这个代码片段后,你点击这个链接会直接播放音频,不会任何跳转。
那么它是怎么判断哪些链接是音频链接?哪些链接是普通链接的呢(普通链接需要跳转)?
就是通过代码中的
const audioLinkKeywords=['res.iciba.com',...]
参数指定的,比如这个参数里你配置了 res.iciba.com 这个关键词,那么,当你点击链接时,代码会判断这个链接中是否含有 res.iciba.com 关键词,如果有则当做音频链接,直接播放,如果没有则当做普通链接,继续跳转。知道这个原理后就知道怎样使用了吧。
然后进一步说明,在链接的锚文本中可以输入普通文本,emoji,* 等,当输入*号时,会把 * 号解析为一个图片按钮(比如一个小喇叭图片
),这个图片即 defaultImage 参数中指定的图片,这样链接就不仅仅显示为一个文本或 emoji 了,还可以显示一个自定义的图片,这样链接看起来更美观。
再进一步,如果你没有专门的音频播放链接的话,你可以把你的链接输入一个以 auto:开头的链接,比如在链接输入框中输入 auto:hello:en,这个链接会自动去 www.iciba.com 官网获取真实的音频链接,获取的是哪个单词的音频链接呢?就是 auto:后面的那个 hello 单词。最后一个 en,意思是获取 hello 单词的英音音频链接,美音是 am,美音也可以省略不写,比如 auto:hello:am 和 auto:hello 都代表获取 hello 单词的美音。
最后,如果你的链接中含有 start 或 end 参数时,比如你的链接是 assets/xxxx.mp3?start=10&end=20,则播放该音频时,会自定跳转到音频的第 10 秒处开始播放,播放到 20 秒处停止。
最后的最后,假设还有这样一种场景,你有一个英语学习音频,并且这个音频有一些字幕文件。你想把这些字幕文件复制到思源中,并且想点击某个句子播放音频中对应的部分。那么,你就可能用到文档中介绍的批量插入的内容了。意思是把字幕文件在编辑器中格式化成文本和链接的形式后,然后一次性粘贴到思源中。如果还不理解,建议看看这些帖子的使用场景 思源有声书制作可行性 或 希望思源笔记中能够点击单词进行播放单词的声音 或 怎么快速插入音频,并设置锚文本点击即播放? ,说不定就理解了。
-
日、周、月记录模板分享
2024-12-18 14:52好的,没事的,已修改。
根据这个帖子的原理 思源如何给日记模板添加天气
实现了,给日记模板添加天气的功能。
最新版更新:
完整日记模板代码(右键菜单另存为即可下载):
https://gitee.com/wish163/mysoft/raw/main/%E6%80%9D%E6%BA%90/daliy_note.md
如果想在自己已有模板基础上添加天气,可以把上述模板的最后一行的代码复制到你的模板任意一行即可,为防止意外,最好单独放置一行,通常放模板最后一行即可。
源码:
注意,以上模板的代码每次打开都是最新版。
也可以直接用这个代码,放到模板任意行即可(不推荐,因为这个代码是在帖子里写死的,不会实时更新)
{{//!js_esc_newline_return (async () => {_esc_newline_ // 等待时长,默认60秒_esc_newline_ const waitForTime = 60;_esc_newline_ getWeather();_esc_newline_ async function getWeather () {_esc_newline_ const weather = await fetch('https://wttr.in/?format=1');_esc_newline_ const text = await weather.text();_esc_newline_ render(text);_esc_newline_ };_esc_newline_ async function render(text) {_esc_newline_ const {datetimeP, datetimeEl} = getDatetimeEl();_esc_newline_ if(!datetimeP && !datetimeEl) {_esc_newline_ delItem();_esc_newline_ return;_esc_newline_ }_esc_newline_ const loadingEl = datetimeEl.querySelector('span[data-type~="loading"]');_esc_newline_ if(loadingEl) {_esc_newline_ loadingEl.remove();_esc_newline_ }_esc_newline_ datetimeEl.innerHTML = datetimeEl.innerHTML + ' ' + text.trim().replace(/\s+/g, ' ');_esc_newline_ // 更新日期块_esc_newline_ fetchSyncPost('/api/block/updateBlock', {_esc_newline_ "dataType": "dom",_esc_newline_ "data": datetimeP.outerHTML,_esc_newline_ "id": datetimeP.dataset.nodeId_esc_newline_ });_esc_newline_ // 删除嵌入块_esc_newline_ delItem();_esc_newline_ }_esc_newline_ function getDatetimeEl() {_esc_newline_ const protyle = item.closest('.protyle-wysiwyg');_esc_newline_ const datetimeP = protyle?.querySelector('.sb:first-child .p:first-child');_esc_newline_ if(!datetimeP) return {};_esc_newline_ const datetimeEl = datetimeP.querySelector('[contenteditable="true"]');_esc_newline_ if(!datetimeEl) return {datetimeP};_esc_newline_ return {datetimeP, datetimeEl};_esc_newline_ }_esc_newline_ function delItem() {_esc_newline_ // 删除嵌入块_esc_newline_ fetchSyncPost('/api/block/deleteBlock', {id: item?.dataset?.nodeId});_esc_newline_ // 清除定时器_esc_newline_ if(timer) clearTimeout(timer);_esc_newline_ }_esc_newline_ let timer = 0;_esc_newline_ whenRender().then(el => {_esc_newline_ el.outerHTML = '正在获取天气...';_esc_newline_ const {datetimeEl} = getDatetimeEl();_esc_newline_ if(datetimeEl) {_esc_newline_ item.style.display = 'none';_esc_newline_ datetimeEl.innerHTML = datetimeEl.innerHTML + '<span data-type="text loading"> Loading</span>';_esc_newline_ }_esc_newline_ timer = setTimeout(() => {_esc_newline_ // 删除嵌入块_esc_newline_ if(item?.dataset?.nodeId) fetchSyncPost('/api/block/deleteBlock', {id: item?.dataset?.nodeId});_esc_newline_ // 删除loading_esc_newline_ const loadingEl = datetimeEl.querySelector('span[data-type~="loading"]');_esc_newline_ if(loadingEl) loadingEl.remove();_esc_newline_ }, waitForTime * 1000);_esc_newline_ });_esc_newline_ function whenRender(selector = '.b3-form__space--small') {_esc_newline_ return new Promise(resolve => {_esc_newline_ const check = () => {_esc_newline_ let el = item.querySelector(selector);_esc_newline_ if (el) resolve(el); else requestAnimationFrame(check);_esc_newline_ };_esc_newline_ check();_esc_newline_ });_esc_newline_ }_esc_newline_ return [];_esc_newline_})();}}
-
求助隐藏面包屑中的部分文本
2024-12-18 13:22明白了,这个可以。
(()=>{ // 监听面包屑项出现 observeElementExist('.protyle-breadcrumb__item', (element) => { const xlinkHref = element.querySelector('svg use')?.getAttribute('xlink:href'); if(xlinkHref !== '#iconListItem') return; const text = element.querySelector('.protyle-breadcrumb__text'); if(!text) return; text.style.display = 'none'; }, document.body); // 监听元素出现 function observeElementExist(selector, callback, observeNode) { const handleMutations = (mutationsList, observer) => { for (let mutation of mutationsList) { if (mutation.type === 'childList') { mutation.addedNodes.forEach(node => { if(!node || node.nodeType !== Node.ELEMENT_NODE) return; if (node.matches && node.matches(selector)) { callback(node); } else if (node.querySelector(selector)) { const nodes = node.querySelectorAll(selector); nodes.forEach(node => { callback(node); }); } }); } } }; // 创建一个MutationObserver实例 const config = { attributes: false, childList: true, subtree: true }; const observer = new MutationObserver(handleMutations); // 选择需要监听的父节点 observeNode = typeof observeNode === 'string' ? document.querySelector(observeNode) : observeNode; const targetNode = observeNode || document.body; // 开始监听目标节点的变化 observer.observe(targetNode, config); } })();
另外吐槽下:
我也很奇怪那个 css,一摸一样的代码,我第一次试那个样式也没用,第二次试就好了 😄 。
-
求助隐藏面包屑中的部分文本
2024-12-18 10:01用这个代码试试。(之前的代码为了优化性能,缩小了监控范围导致的)
(()=>{ // 监听面包屑项出现 observeElementExist('.protyle-breadcrumb__item', (element) => { const xlinkHref = element.querySelector('svg use')?.getAttribute('xlink:href'); if(xlinkHref !== '#iconListItem') return; const text = element.querySelector('.protyle-breadcrumb__text'); if(!text) return; text.style.display = 'none'; }, document.body); // 监听元素出现 function observeElementExist(selector, callback, observeNode) { const handleMutations = (mutationsList, observer) => { for (let mutation of mutationsList) { if (mutation.type === 'childList') { mutation.addedNodes.forEach(node => { if (node.matches && node.matches(selector)) { callback(node); //observer.disconnect(); // 一旦找到元素,停止监听 } }); } } }; // 创建一个MutationObserver实例 const config = { attributes: false, childList: true, subtree: true }; const observer = new MutationObserver(handleMutations); // 选择需要监听的父节点 observeNode = typeof observeNode === 'string' ? document.querySelector(observeNode) : observeNode; const targetNode = observeNode || document.body; // 开始监听目标节点的变化 observer.observe(targetNode, config); } })();
如果还有问题,告诉我反链面板的面包屑怎么查看的?另外,你说的嵌入块面板屑应该指的是聚焦窗口的面包屑吧。
-
API 获取并处理块的一些疑问
2024-12-18 09:04一般没必要使用/api/transactions 这个 api 吧,这个 api 的使用场景应该是那些需要事务的操作,比如多个操作保证原子性。
-
日、周、月记录模板分享
2024-12-17 21:05不客气哈,也感谢你提供这么好的模板。
这是旧版本,不推荐使用,请参考上面的新版本
补充改进版:
- 改进加载时提示 Loading 在时间文本的右侧,不再出现在嵌入块处
- 其他细节优化
使用方法:
把下面的代码添加到日记模板的任意位置即可(目前仅支持了日记模板,周模板,月模板需自己修改)。
{{//!js_esc_newline_return (async () => {_esc_newline_ // 等待时长,默认60秒_esc_newline_ const waitForTime = 60;_esc_newline_ getWeather();_esc_newline_ async function getWeather () {_esc_newline_ const weather = await fetch('https://wttr.in/?format=1');_esc_newline_ const text = await weather.text();_esc_newline_ render(text);_esc_newline_ };_esc_newline_ async function render(text) {_esc_newline_ const {datetimeP, datetimeEl} = getDatetimeEl();_esc_newline_ if(!datetimeP && !datetimeEl) {_esc_newline_ delItem();_esc_newline_ return;_esc_newline_ }_esc_newline_ const loadingEl = datetimeEl.querySelector('span[data-type~="loading"]');_esc_newline_ if(loadingEl) {_esc_newline_ loadingEl.remove();_esc_newline_ }_esc_newline_ datetimeEl.innerHTML = datetimeEl.innerHTML + ' ' + text.trim().replace(/\s+/g, ' ');_esc_newline_ // 更新日期块_esc_newline_ fetchSyncPost('/api/block/updateBlock', {_esc_newline_ "dataType": "dom",_esc_newline_ "data": datetimeP.outerHTML,_esc_newline_ "id": datetimeP.dataset.nodeId_esc_newline_ });_esc_newline_ // 删除嵌入块_esc_newline_ delItem();_esc_newline_ }_esc_newline_ function getDatetimeEl() {_esc_newline_ const protyle = item.closest('.protyle-wysiwyg');_esc_newline_ const datetimeP = protyle?.querySelector('.sb:first-child .p:first-child');_esc_newline_ if(!datetimeP) return {};_esc_newline_ const datetimeEl = datetimeP.querySelector('[contenteditable="true"]');_esc_newline_ if(!datetimeEl) return {datetimeP};_esc_newline_ return {datetimeP, datetimeEl};_esc_newline_ }_esc_newline_ function delItem() {_esc_newline_ // 删除嵌入块_esc_newline_ fetchSyncPost('/api/block/deleteBlock', {id: item?.dataset?.nodeId});_esc_newline_ // 清除定时器_esc_newline_ if(timer) clearTimeout(timer);_esc_newline_ }_esc_newline_ let timer = 0;_esc_newline_ whenRender().then(el => {_esc_newline_ el.outerHTML = '正在获取天气...';_esc_newline_ const {datetimeEl} = getDatetimeEl();_esc_newline_ if(datetimeEl) {_esc_newline_ item.style.display = 'none';_esc_newline_ datetimeEl.innerHTML = datetimeEl.innerHTML + '<span data-type="text loading"> Loading</span>';_esc_newline_ }_esc_newline_ timer = setTimeout(() => {_esc_newline_ // 删除嵌入块_esc_newline_ if(item?.dataset?.nodeId) fetchSyncPost('/api/block/deleteBlock', {id: item?.dataset?.nodeId});_esc_newline_ // 删除loading_esc_newline_ const loadingEl = datetimeEl.querySelector('span[data-type~="loading"]');_esc_newline_ if(loadingEl) loadingEl.remove();_esc_newline_ }, waitForTime * 1000);_esc_newline_ });_esc_newline_ function whenRender(selector = '.b3-form__space--small') {_esc_newline_ return new Promise(resolve => {_esc_newline_ const check = () => {_esc_newline_ let el = item.querySelector(selector);_esc_newline_ if (el) resolve(el); else requestAnimationFrame(check);_esc_newline_ };_esc_newline_ check();_esc_newline_ });_esc_newline_ }_esc_newline_ return [];_esc_newline_})();}}
源码:
完整日记模板下载:
-
如何能启动后不出现界面,直接最小化到托盘
2024-12-17 19:16js 代码片段中新增这个代码试试
// 启动时最小化到托盘 // see https://github.com/siyuan-note/siyuan/blob/5129ad926a21176a352cf5f630e0651011bf9c83/app/src/boot/onGetConfig.ts#L115 if(!localStorage.getItem('__isFirstRun')){ localStorage.setItem('__isFirstRun', 1); if ("windows" === window.siyuan.config.system.os) { require('electron').ipcRenderer.send('siyuan-config-tray', { languages: window.siyuan.languages["_trayMenu"], }); } else { require('electron').ipcRenderer.send('siyuan-cmd', "closeButtonBehavior"); } }
-
求助隐藏面包屑中的部分文本
2024-12-17 18:50明白了,不过,css 实现不了,必须通过 js 实现。
你试试下面这个代码是否你想要的效果。
(()=>{ // 监听面包屑项出现 whenElementExist('.layout__center').then(() => { observeElementExist('.protyle-breadcrumb__item', (element) => { const xlinkHref = element.querySelector('svg use')?.getAttribute('xlink:href'); if(xlinkHref !== '#iconListItem') return; const text = element.querySelector('.protyle-breadcrumb__text'); if(!text) return; text.style.display = 'none'; }, '.layout__center'); }); // 等待元素出现(简版) function whenElementExist(selector) { return new Promise(resolve => { const check = () => { const el = typeof selector==='function'?selector():document.querySelector(selector); if (el) resolve(el); else requestAnimationFrame(check); }; check(); }); } // 监听元素出现 function observeElementExist(selector, callback, observeNode) { const handleMutations = (mutationsList, observer) => { for (let mutation of mutationsList) { if (mutation.type === 'childList') { mutation.addedNodes.forEach(node => { if (node.matches && node.matches(selector)) { callback(node); //observer.disconnect(); // 一旦找到元素,停止监听 } }); } } }; // 创建一个MutationObserver实例 const config = { attributes: false, childList: true, subtree: true }; const observer = new MutationObserver(handleMutations); // 选择需要监听的父节点 observeNode = typeof observeNode === 'string' ? document.querySelector(observeNode) : observeNode; const targetNode = observeNode || document.body; // 开始监听目标节点的变化 observer.observe(targetNode, config); } })();
-
日、周、月记录模板分享
2024-12-17 18:19这是旧版本,不推荐使用,请参考上面的新版本
根据这个帖子的原理 思源如何给日记模板添加天气
实现了,给日记模板添加天气的功能。
方法:
把下面的代码添加到日记模板的任意位置即可(目前仅支持了日记模板,周模板,月模板需自己修改)。
{{//!js_esc_newline_return (async () => {_esc_newline_ // 等待时长,默认60秒_esc_newline_ const waitForTime = 60;_esc_newline_ getWeather();_esc_newline_ async function getWeather () {_esc_newline_ const weather = await fetch('https://wttr.in/?format=1');_esc_newline_ const text = await weather.text();_esc_newline_ render(text);_esc_newline_ };_esc_newline_ async function render(text) {_esc_newline_ const protyle = item.closest('.protyle-wysiwyg');_esc_newline_ const datetimeP = protyle?.querySelector('.sb:first-child .p:first-child');_esc_newline_ if(!datetimeP) return;_esc_newline_ const datetimeEl = datetimeP.querySelector('[contenteditable="true"]');_esc_newline_ if(!datetimeEl) return;_esc_newline_ datetimeEl.innerHTML = datetimeEl.innerHTML + ' ' + text.trim().replace(/\s+/g, ' ');_esc_newline_ // 删除嵌入块_esc_newline_ fetchSyncPost('/api/block/deleteBlock', {id: item?.dataset?.nodeId});_esc_newline_ // 更新日期块_esc_newline_ fetchSyncPost('/api/block/updateBlock', {_esc_newline_ "dataType": "dom",_esc_newline_ "data": datetimeP.outerHTML,_esc_newline_ "id": datetimeP.dataset.nodeId_esc_newline_ });_esc_newline_ // 清除定时器_esc_newline_ if(timer) clearTimeout(timer);_esc_newline_ }_esc_newline_ let timer = 0;_esc_newline_ whenRender().then(el => {_esc_newline_ el.outerHTML = '正在获取天气...';_esc_newline_ timer = setTimeout(() => {_esc_newline_ // 删除嵌入块_esc_newline_ if(!item?.dataset?.nodeId) return;_esc_newline_ fetchSyncPost('/api/block/deleteBlock', {id: item?.dataset?.nodeId});_esc_newline_ }, waitForTime * 1000);_esc_newline_ });_esc_newline_ function whenRender(selector = '.b3-form__space--small') {_esc_newline_ return new Promise(resolve => {_esc_newline_ const check = () => {_esc_newline_ let el = item.querySelector(selector);_esc_newline_ if (el) resolve(el); else requestAnimationFrame(check);_esc_newline_ };_esc_newline_ check();_esc_newline_ });_esc_newline_ }_esc_newline_ return [];_esc_newline_})();}}
源码:
完整日记模板下载:
-
数据库操作方法求助
2024-12-17 11:33【1】参考楼上的 1,或写代码实现
【2】可参考 [js] 实现可手动修改数据库主键引用块的标题 或参考楼上 2
【3】我这里可以
【4】看电脑性能,可以写代码填入数据测试下 亦可参考 兄弟们,你们一个数据库最多使用到多少行,卡不卡顿?
-
思源笔记内嵌 sql 查询文档求助
2024-12-17 10:57这是以前写的代码,增加了显示封面功能,不知是否满足你的需求。
由于链接已经在标题中了,就没有再次显示。
效果:
代码:
使用说明:
第一步:编辑器中输入 {{}} ,然后把上述代码输入到输入框即可
第二步:
只需要修改这个 👇 标签名参数即可,更多功能请参考源码
const tag = 'demo1'; -
链接和定位
2024-12-16 11:28你可能想要的是目录树搜索吧,目前不支持,思源的目录树是动态加载的,仅仅用户点击父目录时才加载。
所以,要定位文档位置,必须先打开文档,然后再定位。
目前也只能搜索-打开-定位,三步实现了。
-
如何监听思源关闭操作
2024-12-16 10:50哦哦,明白了。
不过,通过 transcations 判断,范围还是有点大,它包括所有更新,包括普通块等。
如果数据库单元格更新的话,再判断下 updateAttrViewCell 就更精确了,建议循环下判断,防止可能有批量更新的情况
当然也可以通过 dom 监听方式,比如,监听
.av__cell
内容的变化,不过有了上面的方法,不推荐这种方法,只是提供一种思路。 -
AI 设置里面这几项填多少合适?
2024-12-16 09:50如果不清楚,默认即可。
超时时间: 单次请求的等待时间,如果这个时间内 ai 未响应,则提示请求失败。
最大 Token 数:这里的 token 可以理解为分割后的单词、子单词或者标点符号等单位,最大 token 数决定了一次请求中能包含多少个这样的单位,通常输入(提问)和输出(回答)都占用 token。
温度请求:高温度增加输出的多样性和不可预测性,这可能导致结果更具有创造性,但也可能太过天马行空。低温度,更可预测、更一致的结果,但可能太过保守。通常,温度设置为 1.0 表示使用原始的概率分布,而低于 1.0 的值会减少多样性,高于 1.0 则增加多样性。
最大上下文:指的是语言模型能够记住并用于生成回复的历史对话或文本的最大长度。这是指模型可以考虑的输入文本的总量,包括用户提供的提示以及之前的对话历史。
-
如何监听思源关闭操作
2024-12-16 09:06没太懂,日程不是你自己实现的插件吗?什么时候触发编辑,你自己不是可控的吗?
还是你的日程在文档中编辑的?建议描述下你的日程是什么?怎样操作的?
触发频繁,我没试过通过插件开发的方式监听,但我看官方源码大概率是 ws-main 里有很多情况被触发,你通过 data 参数里的 transactions 应该可以判断为更新操作的。
另外,通过源码可知,这个事件就是官方 ws 的 onmessage 的回调,所以,通过 onmessage 监听也应该是一样的。
比如:
siyuan.ws.ws.addEventListener('message', (e) => { const msg = JSON.parse(e.data); if(msg.cmd === "transactions") { // 这里获取更新后的数据 console.log(msg); } });
可参考 https://github.com/siyuan-note/siyuan/issues/13313#issuecomment-2515402535
如果非要关闭时生成一次的话,下面这个代码可以满足需求,该代码会拦截思源退出事件,当退出时,先执行回调代码,当完成后再继续退出。
但注意,该代码仅支持 electron 客户端,由于浏览器和手机端不好拦截暂不支持。
如果有兴趣研究,可以参考源码 https://github.com/siyuan-note/siyuan/blob/5129ad926a21176a352cf5f630e0651011bf9c83/app/src/dialog/processSystem.ts#L287
Demo 代码如下(仅支持 electron 客户端):
// 调用示例,当callback返回true时退出 listenExit(async () => { console.log('waiting'); await sleep(30000); return true; }); // 监听思源退出事件,退出前执行callback,当callback返回true时退出(仅支持electron客户端) // see https://github.com/siyuan-note/siyuan/blob/5129ad926a21176a352cf5f630e0651011bf9c83/app/src/dialog/processSystem.ts#L287 function listenExit(callback) { if(!navigator.userAgent.includes('Electron')) return; // 内核是否已退出 let isKernelExited = false; // 监听内核退出 const originalFetch = window.fetch; window.fetch = async function (url, ...args) { try { if(url.endsWith('/api/system/exit')) { for(;;) { if(await callback()) { isKernelExited = true; break; } await sleep(200); } } const response = await originalFetch(url, ...args); return response; } catch (error) { throw error; } }; // 监听客户端退出 // 保存原始方法 const ipcRenderer = require('electron').ipcRenderer; const originalSend = ipcRenderer.send; // 重写 ipcRenderer.send 方法 ipcRenderer.send = async function (...args) { if(args[0] === 'siyuan-quit'){ for(;;) { if(isKernelExited) { await sleep(400); break; } await sleep(200); } originalSend.apply(ipcRenderer, args); } else { originalSend.apply(ipcRenderer, args); } }; } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
虽然这个方法可行,但还是推荐之前的建议,即缩小生成时间间隔和监听日程修改事件。
-
如何监听思源关闭操作
2024-12-16 01:04我之前理解有误,去网上了解了下,生成 ics 和手机端同步是相互独立的。
既然这样,我觉得生成 ics 文件的过程可以适当的小些,比如 1 分钟,然后如果检测到日历没变化就不用生成,也不会太占用资源。
当然最好的方式,是监听日历修改事件,日历修改后就生成文件,不修改不生成,这样就不用担心关闭问题了。
-
如何监听思源关闭操作
2024-12-15 23:53即使监听到,也无法保证代码执行完就退出了,如果执行速度很快可以。长时间执行估计只能调用思源外的命令执行了。
建议说说实际需求和场景,说不定是 XY 问题。
-
手机版不显示图床的图片,请问防盗链应该把哪个域名加入白名单?
2024-12-15 14:11要看平台,貌似一般防盗链白名单需要同时输入端口吧,如果不支持模糊匹配的话,无解。因为思源端口是动态变化的,除非启动时指定端口。
-
用户之声
2024-12-14 21:38我觉得对普通用户保持简洁,对深度用户保持开放就好了。vscode 和 Sublime Text 之所以流行就是足够的灵活性,适合更多的场景和需求。另外,我觉得小众需求是站在大数据方面,就个人而言,再小众,自己需要的就会被认为是最重要的。
另外,吐槽下,vscode, sublime text, obsidian 命令都很强大,思源的命令竟然不充分利用,这一点真的很遗憾。