diff --git a/.obsidian/app.json b/.obsidian/app.json index 9de6706..be601d2 100644 --- a/.obsidian/app.json +++ b/.obsidian/app.json @@ -22,7 +22,5 @@ "showIndentGuide": false, "spellcheck": false, "foldIndent": false, - "userIgnoreFilters": [ - "attachment/" - ] + "userIgnoreFilters": null } \ No newline at end of file diff --git a/.obsidian/appearance.json b/.obsidian/appearance.json index af3f060..f86445f 100644 --- a/.obsidian/appearance.json +++ b/.obsidian/appearance.json @@ -1,7 +1,5 @@ { - "enabledCssSnippets": [ - "myTheme" - ], + "enabledCssSnippets": [], "monospaceFontFamily": "JetBrainsMono Nerd Font Mono", "textFontFamily": "思源黑体", "interfaceFontFamily": "JetBrainsMono Nerd Font Mono", diff --git a/.obsidian/community-plugins.json b/.obsidian/community-plugins.json index f6b446b..f8808f5 100644 --- a/.obsidian/community-plugins.json +++ b/.obsidian/community-plugins.json @@ -5,7 +5,5 @@ "oz-clear-unused-images", "obsidian-excalidraw-plugin", "templater-obsidian", - "obsidian-linter", - "obsidian-paste-image-rename", - "recent-files-obsidian" + "obsidian-linter" ] \ No newline at end of file diff --git a/.obsidian/plugins/obsidian-paste-image-rename/data.json b/.obsidian/plugins/obsidian-paste-image-rename/data.json deleted file mode 100644 index ab7e908..0000000 --- a/.obsidian/plugins/obsidian-paste-image-rename/data.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "imageNamePattern": "image-{{DATE:YYYYMMDDHHmmssSSS}}", - "dupNumberAtStart": false, - "dupNumberDelimiter": "-", - "dupNumberAlways": false, - "autoRename": true, - "handleAllAttachments": false, - "excludeExtensionPattern": "", - "disableRenameNotice": true -} \ No newline at end of file diff --git a/.obsidian/plugins/obsidian-paste-image-rename/main.js b/.obsidian/plugins/obsidian-paste-image-rename/main.js deleted file mode 100644 index 9a0fa6d..0000000 --- a/.obsidian/plugins/obsidian-paste-image-rename/main.js +++ /dev/null @@ -1,942 +0,0 @@ -/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD */ -var __defProp = Object.defineProperty; -var __defProps = Object.defineProperties; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropDescs = Object.getOwnPropertyDescriptors; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getOwnPropSymbols = Object.getOwnPropertySymbols; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __propIsEnum = Object.prototype.propertyIsEnumerable; -var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; -var __spreadValues = (a, b) => { - for (var prop in b || (b = {})) - if (__hasOwnProp.call(b, prop)) - __defNormalProp(a, prop, b[prop]); - if (__getOwnPropSymbols) - for (var prop of __getOwnPropSymbols(b)) { - if (__propIsEnum.call(b, prop)) - __defNormalProp(a, prop, b[prop]); - } - return a; -}; -var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); -var __commonJS = (cb, mod) => function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; -}; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var __async = (__this, __arguments, generator) => { - return new Promise((resolve, reject) => { - var fulfilled = (value) => { - try { - step(generator.next(value)); - } catch (e) { - reject(e); - } - }; - var rejected = (value) => { - try { - step(generator.throw(value)); - } catch (e) { - reject(e); - } - }; - var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); - step((generator = generator.apply(__this, __arguments)).next()); - }); -}; - -// package.json -var require_package = __commonJS({ - "package.json"(exports, module2) { - module2.exports = { - name: "obsidian-paste-image-rename", - version: "1.6.1", - main: "main.js", - scripts: { - start: "node esbuild.config.mjs", - build: "tsc -noEmit -skipLibCheck && BUILD_ENV=production node esbuild.config.mjs && cp manifest.json build", - version: "node version-bump.mjs && git add manifest.json versions.json", - release: "npm run build && gh release create ${npm_package_version} build/*" - }, - keywords: [], - author: "Reorx", - license: "MIT", - devDependencies: { - "@types/node": "^18.11.18", - "@typescript-eslint/eslint-plugin": "^5.49.0", - "@typescript-eslint/parser": "^5.49.0", - "builtin-modules": "^3.3.0", - esbuild: "0.16.17", - obsidian: "^1.1.1", - tslib: "2.5.0", - typescript: "4.9.4" - }, - dependencies: { - "cash-dom": "^8.1.2" - } - }; - } -}); - -// src/main.ts -var main_exports = {}; -__export(main_exports, { - default: () => PasteImageRenamePlugin -}); -module.exports = __toCommonJS(main_exports); -var import_obsidian2 = require("obsidian"); - -// src/batch.ts -var import_obsidian = require("obsidian"); - -// src/utils.ts -var DEBUG = false; -if (DEBUG) - console.log("DEBUG is enabled"); -function debugLog(...args) { - if (DEBUG) { - console.log(new Date().toISOString().slice(11, 23), ...args); - } -} -function createElementTree(rootEl, opts) { - const result = { - el: rootEl.createEl(opts.tag, opts), - children: [] - }; - const children = opts.children || []; - for (const child of children) { - result.children.push(createElementTree(result.el, child)); - } - return result; -} -var path = { - // Credit: @creationix/path.js - join(...partSegments) { - let parts = []; - for (let i = 0, l = partSegments.length; i < l; i++) { - parts = parts.concat(partSegments[i].split("/")); - } - const newParts = []; - for (let i = 0, l = parts.length; i < l; i++) { - const part = parts[i]; - if (!part || part === ".") - continue; - else - newParts.push(part); - } - if (parts[0] === "") - newParts.unshift(""); - return newParts.join("/"); - }, - // returns the last part of a path, e.g. 'foo.jpg' - basename(fullpath) { - const sp = fullpath.split("/"); - return sp[sp.length - 1]; - }, - // return extension without dot, e.g. 'jpg' - extension(fullpath) { - const positions = [...fullpath.matchAll(new RegExp("\\.", "gi"))].map((a) => a.index); - return fullpath.slice(positions[positions.length - 1] + 1); - } -}; -var filenameNotAllowedChars = /[^\p{L}0-9~`!@$&*()\-_=+{};'",<.>? ]/ug; -var sanitizer = { - filename(s) { - return s.replace(filenameNotAllowedChars, "").trim(); - }, - delimiter(s) { - s = this.filename(s); - if (!s) - s = "-"; - return s; - } -}; -function escapeRegExp(s) { - return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); -} -function lockInputMethodComposition(el) { - const state = { - lock: false - }; - el.addEventListener("compositionstart", () => { - state.lock = true; - }); - el.addEventListener("compositionend", () => { - state.lock = false; - }); - return state; -} - -// src/batch.ts -var ImageBatchRenameModal = class extends import_obsidian.Modal { - constructor(app, activeFile, renameFunc, onClose) { - super(app); - this.activeFile = activeFile; - this.renameFunc = renameFunc; - this.onCloseExtra = onClose; - this.state = { - namePattern: "", - extPattern: "", - nameReplace: "", - renameTasks: [] - }; - } - onOpen() { - this.containerEl.addClass("image-rename-modal"); - const { contentEl, titleEl } = this; - titleEl.setText("Batch rename embeded files"); - const namePatternSetting = new import_obsidian.Setting(contentEl).setName("Name pattern").setDesc("Please input the name pattern to match files (regex)").addText((text) => text.setValue(this.state.namePattern).onChange( - (value) => __async(this, null, function* () { - this.state.namePattern = value; - }) - )); - const npInputEl = namePatternSetting.controlEl.children[0]; - npInputEl.focus(); - const npInputState = lockInputMethodComposition(npInputEl); - npInputEl.addEventListener("keydown", (e) => __async(this, null, function* () { - if (e.key === "Enter" && !npInputState.lock) { - e.preventDefault(); - if (!this.state.namePattern) { - errorEl.innerText = 'Error: "Name pattern" could not be empty'; - errorEl.style.display = "block"; - return; - } - this.matchImageNames(tbodyEl); - } - })); - const extPatternSetting = new import_obsidian.Setting(contentEl).setName("Extension pattern").setDesc("Please input the extension pattern to match files (regex)").addText((text) => text.setValue(this.state.extPattern).onChange( - (value) => __async(this, null, function* () { - this.state.extPattern = value; - }) - )); - const extInputEl = extPatternSetting.controlEl.children[0]; - extInputEl.addEventListener("keydown", (e) => __async(this, null, function* () { - if (e.key === "Enter") { - e.preventDefault(); - this.matchImageNames(tbodyEl); - } - })); - const nameReplaceSetting = new import_obsidian.Setting(contentEl).setName("Name replace").setDesc("Please input the string to replace the matched name (use $1, $2 for regex groups)").addText((text) => text.setValue(this.state.nameReplace).onChange( - (value) => __async(this, null, function* () { - this.state.nameReplace = value; - }) - )); - const nrInputEl = nameReplaceSetting.controlEl.children[0]; - const nrInputState = lockInputMethodComposition(nrInputEl); - nrInputEl.addEventListener("keydown", (e) => __async(this, null, function* () { - if (e.key === "Enter" && !nrInputState.lock) { - e.preventDefault(); - this.matchImageNames(tbodyEl); - } - })); - const matchedContainer = contentEl.createDiv({ - cls: "matched-container" - }); - const tableET = createElementTree(matchedContainer, { - tag: "table", - children: [ - { - tag: "thead", - children: [ - { - tag: "tr", - children: [ - { - tag: "td", - text: "Original path" - }, - { - tag: "td", - text: "Renamed Name" - } - ] - } - ] - }, - { - tag: "tbody" - } - ] - }); - const tbodyEl = tableET.children[1].el; - const errorEl = contentEl.createDiv({ - cls: "error", - attr: { - style: "display: none;" - } - }); - new import_obsidian.Setting(contentEl).addButton((button) => { - button.setButtonText("Rename all").setClass("mod-cta").onClick(() => { - new ConfirmModal( - this.app, - "Confirm rename all", - `Are you sure? This will rename all the ${this.state.renameTasks.length} images matched the pattern.`, - () => { - this.renameAll(); - this.close(); - } - ).open(); - }); - }).addButton((button) => { - button.setButtonText("Cancel").onClick(() => { - this.close(); - }); - }); - } - onClose() { - const { contentEl } = this; - contentEl.empty(); - this.onCloseExtra(); - } - renameAll() { - return __async(this, null, function* () { - debugLog("renameAll", this.state); - for (const task of this.state.renameTasks) { - yield this.renameFunc(task.file, task.name); - } - }); - } - matchImageNames(tbodyEl) { - const { state } = this; - const renameTasks = []; - tbodyEl.empty(); - const fileCache = this.app.metadataCache.getFileCache(this.activeFile); - if (!fileCache || !fileCache.embeds) - return; - const namePatternRegex = new RegExp(state.namePattern, "g"); - const extPatternRegex = new RegExp(state.extPattern); - fileCache.embeds.forEach((embed) => { - const file = this.app.metadataCache.getFirstLinkpathDest(embed.link, this.activeFile.path); - if (!file) { - console.warn("file not found", embed.link); - return; - } - if (state.extPattern) { - const m0 = extPatternRegex.exec(file.extension); - if (!m0) - return; - } - const stem = file.basename; - namePatternRegex.lastIndex = 0; - const m1 = namePatternRegex.exec(stem); - if (!m1) - return; - let renamedName = file.name; - if (state.nameReplace) { - namePatternRegex.lastIndex = 0; - renamedName = stem.replace(namePatternRegex, state.nameReplace); - renamedName = `${renamedName}.${file.extension}`; - } - renameTasks.push({ - file, - name: renamedName - }); - createElementTree(tbodyEl, { - tag: "tr", - children: [ - { - tag: "td", - children: [ - { - tag: "span", - text: file.name - }, - { - tag: "div", - text: file.path, - attr: { - class: "file-path" - } - } - ] - }, - { - tag: "td", - children: [ - { - tag: "span", - text: renamedName - }, - { - tag: "div", - text: path.join(file.parent.path, renamedName), - attr: { - class: "file-path" - } - } - ] - } - ] - }); - }); - debugLog("new renameTasks", renameTasks); - state.renameTasks = renameTasks; - } -}; -var ConfirmModal = class extends import_obsidian.Modal { - constructor(app, title, message, onConfirm) { - super(app); - this.title = title; - this.message = message; - this.onConfirm = onConfirm; - } - onOpen() { - const { contentEl, titleEl } = this; - titleEl.setText(this.title); - contentEl.createEl("p", { - text: this.message - }); - new import_obsidian.Setting(contentEl).addButton((button) => { - button.setButtonText("Yes").setClass("mod-warning").onClick(() => { - this.onConfirm(); - this.close(); - }); - }).addButton((button) => { - button.setButtonText("No").onClick(() => { - this.close(); - }); - }); - } -}; - -// src/template.ts -var dateTmplRegex = /{{DATE:([^}]+)}}/gm; -var frontmatterTmplRegex = /{{frontmatter:([^}]+)}}/gm; -var replaceDateVar = (s, date) => { - const m = dateTmplRegex.exec(s); - if (!m) - return s; - return s.replace(m[0], date.format(m[1])); -}; -var replaceFrontmatterVar = (s, frontmatter) => { - if (!frontmatter) - return s; - const m = frontmatterTmplRegex.exec(s); - if (!m) - return s; - return s.replace(m[0], frontmatter[m[1]] || ""); -}; -var renderTemplate = (tmpl, data, frontmatter) => { - const now = window.moment(); - let text = tmpl; - let newtext; - while ((newtext = replaceDateVar(text, now)) != text) { - text = newtext; - } - while ((newtext = replaceFrontmatterVar(text, frontmatter)) != text) { - text = newtext; - } - text = text.replace(/{{imageNameKey}}/gm, data.imageNameKey).replace(/{{fileName}}/gm, data.fileName).replace(/{{dirName}}/gm, data.dirName).replace(/{{firstHeading}}/gm, data.firstHeading); - return text; -}; - -// src/main.ts -var DEFAULT_SETTINGS = { - imageNamePattern: "{{fileName}}", - dupNumberAtStart: false, - dupNumberDelimiter: "-", - dupNumberAlways: false, - autoRename: false, - handleAllAttachments: false, - excludeExtensionPattern: "", - disableRenameNotice: false -}; -var PASTED_IMAGE_PREFIX = "Pasted image "; -var PasteImageRenamePlugin = class extends import_obsidian2.Plugin { - constructor() { - super(...arguments); - this.modals = []; - } - onload() { - return __async(this, null, function* () { - const pkg = require_package(); - console.log(`Plugin loading: ${pkg.name} ${pkg.version} BUILD_ENV=${"production"}`); - yield this.loadSettings(); - this.registerEvent( - this.app.vault.on("create", (file) => { - if (!(file instanceof import_obsidian2.TFile)) - return; - const timeGapMs = new Date().getTime() - file.stat.ctime; - if (timeGapMs > 1e3) - return; - if (isMarkdownFile(file)) - return; - if (isPastedImage(file)) { - debugLog("pasted image created", file); - this.startRenameProcess(file, this.settings.autoRename); - } else { - if (this.settings.handleAllAttachments) { - debugLog("handleAllAttachments for file", file); - if (this.testExcludeExtension(file)) { - debugLog("excluded file by ext", file); - return; - } - this.startRenameProcess(file, this.settings.autoRename); - } - } - }) - ); - const startBatchRenameProcess = () => { - this.openBatchRenameModal(); - }; - this.addCommand({ - id: "batch-rename-embeded-files", - name: "Batch rename embeded files (in the current file)", - callback: startBatchRenameProcess - }); - if (DEBUG) { - this.addRibbonIcon("wand-glyph", "Batch rename embeded files", startBatchRenameProcess); - } - const batchRenameAllImages = () => { - this.batchRenameAllImages(); - }; - this.addCommand({ - id: "batch-rename-all-images", - name: "Batch rename all images instantly (in the current file)", - callback: batchRenameAllImages - }); - if (DEBUG) { - this.addRibbonIcon("wand-glyph", "Batch rename all images instantly (in the current file)", batchRenameAllImages); - } - this.addSettingTab(new SettingTab(this.app, this)); - }); - } - startRenameProcess(file, autoRename = false) { - return __async(this, null, function* () { - const activeFile = this.getActiveFile(); - if (!activeFile) { - new import_obsidian2.Notice("Error: No active file found."); - return; - } - const { stem, newName, isMeaningful } = this.generateNewName(file, activeFile); - debugLog("generated newName:", newName, isMeaningful); - if (!isMeaningful || !autoRename) { - this.openRenameModal(file, isMeaningful ? stem : "", activeFile.path); - return; - } - this.renameFile(file, newName, activeFile.path, true); - }); - } - renameFile(file, inputNewName, sourcePath, replaceCurrentLine) { - return __async(this, null, function* () { - const { name: newName } = yield this.deduplicateNewName(inputNewName, file); - debugLog("deduplicated newName:", newName); - const originName = file.name; - const linkText = this.app.fileManager.generateMarkdownLink(file, sourcePath); - const newPath = path.join(file.parent.path, newName); - try { - yield this.app.fileManager.renameFile(file, newPath); - } catch (err) { - new import_obsidian2.Notice(`Failed to rename ${newName}: ${err}`); - throw err; - } - if (!replaceCurrentLine) { - return; - } - const newLinkText = this.app.fileManager.generateMarkdownLink(file, sourcePath); - debugLog("replace text", linkText, newLinkText); - const editor = this.getActiveEditor(); - if (!editor) { - new import_obsidian2.Notice(`Failed to rename ${newName}: no active editor`); - return; - } - const cursor = editor.getCursor(); - const line = editor.getLine(cursor.line); - const replacedLine = line.replace(linkText, newLinkText); - debugLog("current line -> replaced line", line, replacedLine); - editor.transaction({ - changes: [ - { - from: __spreadProps(__spreadValues({}, cursor), { ch: 0 }), - to: __spreadProps(__spreadValues({}, cursor), { ch: line.length }), - text: replacedLine - } - ] - }); - if (!this.settings.disableRenameNotice) { - new import_obsidian2.Notice(`Renamed ${originName} to ${newName}`); - } - }); - } - openRenameModal(file, newName, sourcePath) { - const modal = new ImageRenameModal( - this.app, - file, - newName, - (confirmedName) => { - debugLog("confirmedName:", confirmedName); - this.renameFile(file, confirmedName, sourcePath, true); - }, - () => { - this.modals.splice(this.modals.indexOf(modal), 1); - } - ); - this.modals.push(modal); - modal.open(); - debugLog("modals count", this.modals.length); - } - openBatchRenameModal() { - const activeFile = this.getActiveFile(); - const modal = new ImageBatchRenameModal( - this.app, - activeFile, - (file, name) => __async(this, null, function* () { - yield this.renameFile(file, name, activeFile.path); - }), - () => { - this.modals.splice(this.modals.indexOf(modal), 1); - } - ); - this.modals.push(modal); - modal.open(); - } - batchRenameAllImages() { - return __async(this, null, function* () { - const activeFile = this.getActiveFile(); - const fileCache = this.app.metadataCache.getFileCache(activeFile); - if (!fileCache || !fileCache.embeds) - return; - const extPatternRegex = /jpe?g|png|gif|tiff|webp/i; - for (const embed of fileCache.embeds) { - const file = this.app.metadataCache.getFirstLinkpathDest(embed.link, activeFile.path); - if (!file) { - console.warn("file not found", embed.link); - return; - } - const m0 = extPatternRegex.exec(file.extension); - if (!m0) - return; - const { newName, isMeaningful } = this.generateNewName(file, activeFile); - debugLog("generated newName:", newName, isMeaningful); - if (!isMeaningful) { - new import_obsidian2.Notice("Failed to batch rename images: the generated name is not meaningful"); - break; - } - yield this.renameFile(file, newName, activeFile.path, false); - } - }); - } - // returns a new name for the input file, with extension - generateNewName(file, activeFile) { - let imageNameKey = ""; - let firstHeading = ""; - let frontmatter; - const fileCache = this.app.metadataCache.getFileCache(activeFile); - if (fileCache) { - debugLog("frontmatter", fileCache.frontmatter); - frontmatter = fileCache.frontmatter; - imageNameKey = (frontmatter == null ? void 0 : frontmatter.imageNameKey) || ""; - firstHeading = getFirstHeading(fileCache.headings); - } else { - console.warn("could not get file cache from active file", activeFile.name); - } - const stem = renderTemplate( - this.settings.imageNamePattern, - { - imageNameKey, - fileName: activeFile.basename, - dirName: activeFile.parent.name, - firstHeading - }, - frontmatter - ); - const meaninglessRegex = new RegExp(`[${this.settings.dupNumberDelimiter}\\s]`, "gm"); - return { - stem, - newName: stem + "." + file.extension, - isMeaningful: stem.replace(meaninglessRegex, "") !== "" - }; - } - // newName: foo.ext - deduplicateNewName(newName, file) { - return __async(this, null, function* () { - const dir = file.parent.path; - const listed = yield this.app.vault.adapter.list(dir); - debugLog("sibling files", listed); - const newNameExt = path.extension(newName), newNameStem = newName.slice(0, newName.length - newNameExt.length - 1), newNameStemEscaped = escapeRegExp(newNameStem), delimiter = this.settings.dupNumberDelimiter, delimiterEscaped = escapeRegExp(delimiter); - let dupNameRegex; - if (this.settings.dupNumberAtStart) { - dupNameRegex = new RegExp( - `^(?\\d+)${delimiterEscaped}(?${newNameStemEscaped})\\.${newNameExt}$` - ); - } else { - dupNameRegex = new RegExp( - `^(?${newNameStemEscaped})${delimiterEscaped}(?\\d+)\\.${newNameExt}$` - ); - } - debugLog("dupNameRegex", dupNameRegex); - const dupNameNumbers = []; - let isNewNameExist = false; - for (let sibling of listed.files) { - sibling = path.basename(sibling); - if (sibling == newName) { - isNewNameExist = true; - continue; - } - const m = dupNameRegex.exec(sibling); - if (!m) - continue; - dupNameNumbers.push(parseInt(m.groups.number)); - } - if (isNewNameExist || this.settings.dupNumberAlways) { - const newNumber = dupNameNumbers.length > 0 ? Math.max(...dupNameNumbers) + 1 : 1; - if (this.settings.dupNumberAtStart) { - newName = `${newNumber}${delimiter}${newNameStem}.${newNameExt}`; - } else { - newName = `${newNameStem}${delimiter}${newNumber}.${newNameExt}`; - } - } - return { - name: newName, - stem: newName.slice(0, newName.length - newNameExt.length - 1), - extension: newNameExt - }; - }); - } - getActiveFile() { - const view = this.app.workspace.getActiveViewOfType(import_obsidian2.MarkdownView); - const file = view == null ? void 0 : view.file; - debugLog("active file", file == null ? void 0 : file.path); - return file; - } - getActiveEditor() { - const view = this.app.workspace.getActiveViewOfType(import_obsidian2.MarkdownView); - return view == null ? void 0 : view.editor; - } - onunload() { - this.modals.map((modal) => modal.close()); - } - testExcludeExtension(file) { - const pattern = this.settings.excludeExtensionPattern; - if (!pattern) - return false; - return new RegExp(pattern).test(file.extension); - } - loadSettings() { - return __async(this, null, function* () { - this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData()); - }); - } - saveSettings() { - return __async(this, null, function* () { - yield this.saveData(this.settings); - }); - } -}; -function getFirstHeading(headings) { - if (headings && headings.length > 0) { - for (const heading of headings) { - if (heading.level === 1) { - return heading.heading; - } - } - } - return ""; -} -function isPastedImage(file) { - if (file instanceof import_obsidian2.TFile) { - if (file.name.startsWith(PASTED_IMAGE_PREFIX)) { - return true; - } - } - return false; -} -function isMarkdownFile(file) { - if (file instanceof import_obsidian2.TFile) { - if (file.extension === "md") { - return true; - } - } - return false; -} -var ImageRenameModal = class extends import_obsidian2.Modal { - constructor(app, src, stem, renameFunc, onClose) { - super(app); - this.src = src; - this.stem = stem; - this.renameFunc = renameFunc; - this.onCloseExtra = onClose; - } - onOpen() { - this.containerEl.addClass("image-rename-modal"); - const { contentEl, titleEl } = this; - titleEl.setText("Rename image"); - const imageContainer = contentEl.createDiv({ - cls: "image-container" - }); - imageContainer.createEl("img", { - attr: { - src: this.app.vault.getResourcePath(this.src) - } - }); - let stem = this.stem; - const ext = this.src.extension; - const getNewName = (stem2) => stem2 + "." + ext; - const getNewPath = (stem2) => path.join(this.src.parent.path, getNewName(stem2)); - const infoET = createElementTree(contentEl, { - tag: "ul", - cls: "info", - children: [ - { - tag: "li", - children: [ - { - tag: "span", - text: "Origin path" - }, - { - tag: "span", - text: this.src.path - } - ] - }, - { - tag: "li", - children: [ - { - tag: "span", - text: "New path" - }, - { - tag: "span", - text: getNewPath(stem) - } - ] - } - ] - }); - const doRename = () => __async(this, null, function* () { - debugLog("doRename", `stem=${stem}`); - this.renameFunc(getNewName(stem)); - }); - const nameSetting = new import_obsidian2.Setting(contentEl).setName("New name").setDesc("Please input the new name for the image (without extension)").addText((text) => text.setValue(stem).onChange( - (value) => __async(this, null, function* () { - stem = sanitizer.filename(value); - infoET.children[1].children[1].el.innerText = getNewPath(stem); - }) - )); - const nameInputEl = nameSetting.controlEl.children[0]; - nameInputEl.focus(); - const nameInputState = lockInputMethodComposition(nameInputEl); - nameInputEl.addEventListener("keydown", (e) => __async(this, null, function* () { - if (e.key === "Enter" && !nameInputState.lock) { - e.preventDefault(); - if (!stem) { - errorEl.innerText = 'Error: "New name" could not be empty'; - errorEl.style.display = "block"; - return; - } - doRename(); - this.close(); - } - })); - const errorEl = contentEl.createDiv({ - cls: "error", - attr: { - style: "display: none;" - } - }); - new import_obsidian2.Setting(contentEl).addButton((button) => { - button.setButtonText("Rename").onClick(() => { - doRename(); - this.close(); - }); - }).addButton((button) => { - button.setButtonText("Cancel").onClick(() => { - this.close(); - }); - }); - } - onClose() { - const { contentEl } = this; - contentEl.empty(); - this.onCloseExtra(); - } -}; -var imageNamePatternDesc = ` -The pattern indicates how the new name should be generated. - -Available variables: -- {{fileName}}: name of the active file, without ".md" extension. -- {{imageNameKey}}: this variable is read from the markdown file's frontmatter, from the same key "imageNameKey". -- {{DATE:$FORMAT}}: use "$FORMAT" to format the current date, "$FORMAT" must be a Moment.js format string, e.g. {{DATE:YYYY-MM-DD}}. - -Here are some examples from pattern to image names (repeat in sequence), variables: fileName = "My note", imageNameKey = "foo": -- {{fileName}}: My note, My note-1, My note-2 -- {{imageNameKey}}: foo, foo-1, foo-2 -- {{imageNameKey}}-{{DATE:YYYYMMDD}}: foo-20220408, foo-20220408-1, foo-20220408-2 -`; -var SettingTab = class extends import_obsidian2.PluginSettingTab { - constructor(app, plugin) { - super(app, plugin); - this.plugin = plugin; - } - display() { - const { containerEl } = this; - containerEl.empty(); - new import_obsidian2.Setting(containerEl).setName("Image name pattern").setDesc(imageNamePatternDesc).setClass("long-description-setting-item").addText((text) => text.setPlaceholder("{{imageNameKey}}").setValue(this.plugin.settings.imageNamePattern).onChange( - (value) => __async(this, null, function* () { - this.plugin.settings.imageNamePattern = value; - yield this.plugin.saveSettings(); - }) - )); - new import_obsidian2.Setting(containerEl).setName("Duplicate number at start (or end)").setDesc(`If enabled, duplicate number will be added at the start as prefix for the image name, otherwise it will be added at the end as suffix for the image name.`).addToggle((toggle) => toggle.setValue(this.plugin.settings.dupNumberAtStart).onChange( - (value) => __async(this, null, function* () { - this.plugin.settings.dupNumberAtStart = value; - yield this.plugin.saveSettings(); - }) - )); - new import_obsidian2.Setting(containerEl).setName("Duplicate number delimiter").setDesc(`The delimiter to generate the number prefix/suffix for duplicated names. For example, if the value is "-", the suffix will be like "-1", "-2", "-3", and the prefix will be like "1-", "2-", "3-". Only characters that are valid in file names are allowed.`).addText((text) => text.setValue(this.plugin.settings.dupNumberDelimiter).onChange( - (value) => __async(this, null, function* () { - this.plugin.settings.dupNumberDelimiter = sanitizer.delimiter(value); - yield this.plugin.saveSettings(); - }) - )); - new import_obsidian2.Setting(containerEl).setName("Always add duplicate number").setDesc(`If enabled, duplicate number will always be added to the image name. Otherwise, it will only be added when the name is duplicated.`).addToggle((toggle) => toggle.setValue(this.plugin.settings.dupNumberAlways).onChange( - (value) => __async(this, null, function* () { - this.plugin.settings.dupNumberAlways = value; - yield this.plugin.saveSettings(); - }) - )); - new import_obsidian2.Setting(containerEl).setName("Auto rename").setDesc(`By default, the rename modal will always be shown to confirm before renaming, if this option is set, the image will be auto renamed after pasting.`).addToggle((toggle) => toggle.setValue(this.plugin.settings.autoRename).onChange( - (value) => __async(this, null, function* () { - this.plugin.settings.autoRename = value; - yield this.plugin.saveSettings(); - }) - )); - new import_obsidian2.Setting(containerEl).setName("Handle all attachments").setDesc(`By default, the plugin only handles images that starts with "Pasted image " in name, - which is the prefix Obsidian uses to create images from pasted content. - If this option is set, the plugin will handle all attachments that are created in the vault.`).addToggle((toggle) => toggle.setValue(this.plugin.settings.handleAllAttachments).onChange( - (value) => __async(this, null, function* () { - this.plugin.settings.handleAllAttachments = value; - yield this.plugin.saveSettings(); - }) - )); - new import_obsidian2.Setting(containerEl).setName("Exclude extension pattern").setDesc(`This option is only useful when "Handle all attachments" is enabled. - Write a Regex pattern to exclude certain extensions from being handled. Only the first line will be used.`).setClass("single-line-textarea").addTextArea((text) => text.setPlaceholder("docx?|xlsx?|pptx?|zip|rar").setValue(this.plugin.settings.excludeExtensionPattern).onChange( - (value) => __async(this, null, function* () { - this.plugin.settings.excludeExtensionPattern = value; - yield this.plugin.saveSettings(); - }) - )); - new import_obsidian2.Setting(containerEl).setName("Disable rename notice").setDesc(`Turn off this option if you don't want to see the notice when renaming images. - Note that Obsidian may display a notice when a link has changed, this option cannot disable that.`).addToggle((toggle) => toggle.setValue(this.plugin.settings.disableRenameNotice).onChange( - (value) => __async(this, null, function* () { - this.plugin.settings.disableRenameNotice = value; - yield this.plugin.saveSettings(); - }) - )); - } -}; diff --git a/.obsidian/plugins/obsidian-paste-image-rename/manifest.json b/.obsidian/plugins/obsidian-paste-image-rename/manifest.json deleted file mode 100644 index 152d913..0000000 --- a/.obsidian/plugins/obsidian-paste-image-rename/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "obsidian-paste-image-rename", - "name": "Paste image rename", - "version": "1.6.1", - "minAppVersion": "0.12.0", - "description": "Rename pasted images and all the other attchments added to the vault", - "author": "Reorx", - "authorUrl": "https://github.com/reorx", - "isDesktopOnly": false -} \ No newline at end of file diff --git a/.obsidian/plugins/obsidian-paste-image-rename/styles.css b/.obsidian/plugins/obsidian-paste-image-rename/styles.css deleted file mode 100644 index d542d56..0000000 --- a/.obsidian/plugins/obsidian-paste-image-rename/styles.css +++ /dev/null @@ -1,79 +0,0 @@ -/* src/styles.css */ -:root { - --shadow-color: 0deg 0% 0%; - --shadow-elevation-medium: - 0.5px 0.5px 0.7px hsl(var(--shadow-color) / 0.14), - 1.1px 1.1px 1.5px -0.9px hsl(var(--shadow-color) / 0.12), - 2.4px 2.5px 3.3px -1.8px hsl(var(--shadow-color) / 0.1), - 5.3px 5.6px 7.3px -2.7px hsl(var(--shadow-color) / 0.09), - 11px 11.4px 15.1px -3.6px hsl(var(--shadow-color) / 0.07); -} -.image-rename-modal .modal { - width: 65%; - min-width: 600px; -} -.image-rename-modal .modal-content { - padding: 10px 5px; -} -.image-rename-modal .image-container { - display: flex; - justify-content: center; -} -.image-rename-modal .info { - padding: 10px 0; - color: var(--text-muted); - user-select: text; -} -.image-rename-modal .info li > span:nth-of-type(1) { - display: inline-block; - width: 6em; - margin-right: .5em; -} -.image-rename-modal .info li > span:nth-of-type(1):after { - content: ":"; - float: right; -} -.image-rename-modal .image-container img { - display: block; - max-height: 300px; - box-shadow: var(--shadow-elevation-medium); -} -.image-rename-modal .setting-item-control input { - min-width: 300px; -} -.image-rename-modal .error { - border: 1px solid rgb(201, 90, 90); - color: rgb(134, 22, 22); - padding: 10px; -} -.image-rename-modal table { - font-size: .9em; - line-height: 1.8; - margin-bottom: 1.5em; - user-select: text; -} -.image-rename-modal table td { - padding-right: 1em; -} -.image-rename-modal table thead td { - font-weight: 700; -} -.image-rename-modal table tbody td .file-path { - font-size: .8em; - color: var(--text-faint); - line-height: 1; -} -.long-description-setting-item { - flex-wrap: wrap; -} -.long-description-setting-item .setting-item-description { - white-space: pre-wrap; - line-height: 1.3em; -} -.long-description-setting-item .setting-item-control { - padding-top: 10px; -} -.long-description-setting-item .setting-item-control input { - min-width: 300px; - width: 50%; -} diff --git a/.obsidian/plugins/recent-files-obsidian/data.json b/.obsidian/plugins/recent-files-obsidian/data.json deleted file mode 100644 index 5e59087..0000000 --- a/.obsidian/plugins/recent-files-obsidian/data.json +++ /dev/null @@ -1,208 +0,0 @@ -{ - "recentFiles": [ - { - "basename": "jinja", - "path": "000-inbox/jinja.md" - }, - { - "basename": "20260328124189", - "path": "000-Inbox/20260328124189.md" - }, - { - "basename": "Qwen3.5(通义千问 3.5)系列的多模态图文大模型(Vision-Language Models)", - "path": "resource/ai/大模型安装笔记/Qwen3.5(通义千问 3.5)系列的多模态图文大模型(Vision-Language Models).md" - }, - { - "basename": "x-csrf-token", - "path": "work/移动杭研/业务梳理/x-csrf-token.md" - }, - { - "basename": "需求-命中率计算", - "path": "000-inbox/需求-命中率计算.md" - }, - { - "basename": "Docker 核心知识与实战笔记", - "path": "000-inbox/Docker 核心知识与实战笔记.md" - }, - { - "basename": "GNU Screen 命令全解析", - "path": "resource/系统/GNU Screen 命令全解析.md" - }, - { - "basename": "结构化输出和工具调用", - "path": "resource/ai/大模型安装笔记/结构化输出和工具调用.md" - }, - { - "basename": "如何成为一个 React 工程师呢?", - "path": "resource/前端/如何成为一个 React 工程师呢?.md" - }, - { - "basename": "20260327113359", - "path": "000-Inbox/20260327113359.md" - }, - { - "basename": "20260327105648", - "path": "000-Inbox/20260327105648.md" - }, - { - "basename": "20260327101490", - "path": "000-Inbox/20260327101490.md" - }, - { - "basename": "开发笔记", - "path": "work/移动杭研/开发记录/7.19.0/开发笔记.md" - }, - { - "basename": "IBS 智能体具体落实技术方案", - "path": "work/移动杭研/AI 项目/IBS 智能体具体落实技术方案.md" - }, - { - "basename": "20260327091590", - "path": "000-Inbox/20260327091590.md" - }, - { - "basename": "20260327083230", - "path": "000-Inbox/20260327083230.md" - }, - { - "basename": "20260326175860", - "path": "000-Inbox/20260326175860.md" - }, - { - "basename": "001 大模型启动流程", - "path": "resource/ai/大模型安装笔记/001 大模型启动流程.md" - }, - { - "basename": "20260326173620", - "path": "000-Inbox/20260326173620.md" - }, - { - "basename": "关于模型思考问题", - "path": "resource/ai/大模型安装笔记/关于模型思考问题.md" - }, - { - "basename": "大模型中的参数、权重与数值类型整理", - "path": "resource/ai/大模型安装笔记/大模型中的参数、权重与数值类型整理.md" - }, - { - "basename": "LLM 三件套", - "path": "resource/ai/大模型安装笔记/LLM 三件套.md" - }, - { - "basename": "000 autodl 机器信息", - "path": "resource/ai/大模型安装笔记/000 autodl 机器信息.md" - }, - { - "basename": "函数调用 和 工具调用", - "path": "resource/ai/大模型安装笔记/函数调用 和 工具调用.md" - }, - { - "basename": "ubuntu", - "path": "resource/系统/ubuntu.md" - }, - { - "basename": "tg-bot", - "path": "000-inbox/tg-bot.md" - }, - { - "basename": "20260326141824", - "path": "000-Inbox/20260326141824.md" - }, - { - "basename": "20260326140857", - "path": "000-Inbox/20260326140857.md" - }, - { - "basename": "20260326093371", - "path": "000-Inbox/20260326093371.md" - }, - { - "basename": "核心策略", - "path": "resource/ai/核心策略.md" - }, - { - "basename": "002 vllm 安装日志", - "path": "resource/ai/大模型安装笔记/002 vllm 安装日志.md" - }, - { - "basename": "netflix 界面切换为简中", - "path": "resource/系统/netflix 界面切换为简中.md" - }, - { - "basename": "构建 HUGO 博客的完整指南:从搭建到部署", - "path": "resource/系统/构建 HUGO 博客的完整指南:从搭建到部署.md" - }, - { - "basename": "20260325172730", - "path": "000-Inbox/20260325172730.md" - }, - { - "basename": "服务器-香港", - "path": "personal/服务器-香港.md" - }, - { - "basename": "20260325150017", - "path": "000-Inbox/20260325150017.md" - }, - { - "basename": "Prompt 03 COSMIC 子过程", - "path": "resource/ai/prompts/cosmic/Prompt 03 COSMIC 子过程.md" - }, - { - "basename": "003 vllm 启动日志", - "path": "resource/ai/大模型安装笔记/003 vllm 启动日志.md" - }, - { - "basename": "20260325083535", - "path": "000-Inbox/20260325083535.md" - }, - { - "basename": "20260324182248", - "path": "000-Inbox/20260324182248.md" - }, - { - "basename": "接口收纳", - "path": "work/移动杭研/业务梳理/接口收纳.md" - }, - { - "basename": "开发笔记", - "path": "work/移动杭研/开发记录/7.18.0/开发笔记.md" - }, - { - "basename": "0323-邮件发送异常", - "path": "work/移动杭研/问题处理/2026-03/0323-邮件发送异常.md" - }, - { - "basename": "TG 备忘录", - "path": "personal/TG 备忘录.md" - }, - { - "basename": "CLAUDE.md", - "path": "work/移动杭研/AI 项目/CLAUDE.md.md" - }, - { - "basename": "图纸-IBS 智能体-v3-项目架构", - "path": "work/移动杭研/AI 项目/图纸-IBS 智能体-v3-项目架构.md" - }, - { - "basename": "图纸-IBS 智能体-v1-流量查询 demo 对象存储", - "path": "work/移动杭研/AI 项目/图纸-IBS 智能体-v1-流量查询 demo 对象存储.md" - }, - { - "basename": "图纸-IBS 智能体-v1-流量查询 demo", - "path": "work/移动杭研/AI 项目/图纸-IBS 智能体-v1-流量查询 demo.md" - }, - { - "basename": "ibs-ai 项目梳理", - "path": "work/移动杭研/AI 项目/ibs-ai 项目梳理.md" - } - ], - "omittedPaths": [ - "^attachment/", - "^calendar/" - ], - "omittedTags": [], - "updateOn": "file-open", - "omitBookmarks": false, - "maxLength": null -} \ No newline at end of file diff --git a/.obsidian/plugins/recent-files-obsidian/main.js b/.obsidian/plugins/recent-files-obsidian/main.js deleted file mode 100644 index 3ca63cd..0000000 --- a/.obsidian/plugins/recent-files-obsidian/main.js +++ /dev/null @@ -1,53 +0,0 @@ -/* -THIS IS A GENERATED/BUNDLED FILE BY ESBUILD -if you want to view the source, please visit the github repository of this plugin -*/ - -var W=Object.create;var y=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var J=Object.getPrototypeOf,K=Object.prototype.hasOwnProperty;var D=(C,t)=>()=>(t||C((t={exports:{}}).exports,t),t.exports),X=(C,t)=>{for(var e in t)y(C,e,{get:t[e],enumerable:!0})},Z=(C,t,e,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of G(t))!K.call(C,n)&&n!==e&&y(C,n,{get:()=>t[n],enumerable:!(a=$(t,n))||a.enumerable});return C};var Y=(C,t,e)=>(e=C!=null?W(J(C)):{},Z(t||!C||!C.__esModule?y(e,"default",{value:C,enumerable:!0}):e,C)),Q=C=>Z(y({},"__esModule",{value:!0}),C);var I=D(R=>{"use strict";Object.defineProperty(R,"__esModule",{value:!0})});var S=D(A=>{"use strict";Object.defineProperty(A,"__esModule",{value:!0})});var H=D(B=>{"use strict";Object.defineProperty(B,"__esModule",{value:!0})});var V=D(p=>{"use strict";var e1=p&&p.__createBinding||(Object.create?function(C,t,e,a){a===void 0&&(a=e);var n=Object.getOwnPropertyDescriptor(t,e);(!n||("get"in n?!t.__esModule:n.writable||n.configurable))&&(n={enumerable:!0,get:function(){return t[e]}}),Object.defineProperty(C,a,n)}:function(C,t,e,a){a===void 0&&(a=e),C[a]=t[e]}),T=p&&p.__exportStar||function(C,t){for(var e in C)e!=="default"&&!Object.prototype.hasOwnProperty.call(t,e)&&e1(t,C,e)};Object.defineProperty(p,"__esModule",{value:!0});p.getApiSafe=p.getDefer=p.isPluginEnabled=p.PluginNotEnabledError=p.pluginId=void 0;T(I(),p);T(S(),p);T(H(),p);p.pluginId="obsidian-front-matter-title-plugin";var w=class extends Error{};p.PluginNotEnabledError=w;function t1(C){var t,e,a;return(a=(e=(t=C==null?void 0:C.plugins)===null||t===void 0?void 0:t.enabledPlugins)===null||e===void 0?void 0:e.has(p.pluginId))!==null&&a!==void 0?a:!1}p.isPluginEnabled=t1;function z(C){var t,e,a,n;let s=(e=(t=C==null?void 0:C.plugins)===null||t===void 0?void 0:t.getPlugin(p.pluginId))!==null&&e!==void 0?e:null,h=(n=(a=s==null?void 0:s.getDefer)===null||a===void 0?void 0:a.call(s))!==null&&n!==void 0?n:null;if(h===null)throw new w(`Plugin ${p.pluginId} is not enabled or old version`);return h}p.getDefer=z;function a1(C){return new k(null,C)}p.getApiSafe=a1;var k=class{constructor(t,e){this.api=t,this.app=e}before(){if(this.api!==null)return;let t=this.getDeffer();if(t===null)return;let e=t.getApi();if(e===null)return t.awaitPlugin().then(()=>{this.api=t.getApi()});this.api=e}getDeffer(){try{return z(this.app)}catch(t){if(t instanceof w)return null;throw t}}getResolverFactory(){var t,e;return this.before(),(e=(t=this.api)===null||t===void 0?void 0:t.getResolverFactory())!==null&&e!==void 0?e:null}getEventDispatcher(){var t,e;return this.before(),(e=(t=this.api)===null||t===void 0?void 0:t.getEventDispatcher())!==null&&e!==void 0?e:null}getEnabledFeatures(){var t,e;return this.before(),(e=(t=this.api)===null||t===void 0?void 0:t.getEnabledFeatures())!==null&&e!==void 0?e:[]}}});var l1={};X(l1,{default:()=>M});module.exports=Q(l1);var l=require("obsidian"),N=Y(V()),q=50,i1={recentFiles:[],omittedPaths:[],omittedTags:[],updateOn:"file-open",omitBookmarks:!1},u="recent-files",b=class extends l.ItemView{constructor(e,a,n){super(e);this.redraw=()=>{var o;let e=this.app.workspace.getActiveFile(),a=createDiv({cls:"nav-folder mod-root"}),n=a.createDiv({cls:"nav-folder-children"}),s=(0,N.getApiSafe)(this.app),g=s&&s.getEnabledFeatures().contains("explorer")?(o=s.getResolverFactory())==null?void 0:o.createResolver("explorer"):null;this.data.recentFiles.forEach(i=>{var _;let d=n.createDiv({cls:"tree-item nav-file recent-files-file"}),r=d.createDiv({cls:"tree-item-self is-clickable nav-file-title recent-files-title"}),f=r.createDiv({cls:"tree-item-inner nav-file-title-content"}),m=r.createDiv({cls:"nav-file-tag"}),r1=r.createDiv({cls:"tree-item-spacer"}),U=g&&(_=g.resolve(i.path))!=null?_:i.basename;f.setText(U);let F=this.app.vault.getFileByPath(i.path),E=F==null?void 0:F.extension;E&&E!=="md"&&m.setText(E),(0,l.setTooltip)(d,i.path),e&&i.path===e.path&&r.addClass("is-active"),r.setAttr("draggable","true"),r.addEventListener("dragstart",c=>{if(!(i!=null&&i.path))return;let v=this.app.metadataCache.getFirstLinkpathDest(i.path,""),L=this.app.dragManager,P=L.dragFile(c,v);L.onDragStart(c,P)}),r.addEventListener("mouseover",c=>{i!=null&&i.path&&this.app.workspace.trigger("hover-link",{event:c,source:u,hoverParent:a,targetEl:d,linktext:i.path})}),r.addEventListener("contextmenu",c=>{if(!(i!=null&&i.path))return;let v=new l.Menu;v.addItem(P=>P.setSection("action").setTitle("Open in new tab").setIcon("file-plus").onClick(()=>{this.focusFile(i,"tab")}));let L=this.app.vault.getAbstractFileByPath(i==null?void 0:i.path);this.app.workspace.trigger("file-menu",v,L,"link-context-menu"),v.showAtPosition({x:c.clientX,y:c.clientY})}),r.addEventListener("click",c=>{if(!i)return;let v=l.Keymap.isModEvent(c);this.focusFile(i,v)}),r.addEventListener("mousedown",c=>{i&&c.button===1&&(c.preventDefault(),this.focusFile(i,"tab"))});let O=r.createDiv({cls:"recent-files-file-delete menu-item-icon"});(0,l.setIcon)(O,"lucide-x"),O.addEventListener("click",async c=>{c.stopPropagation(),await this.removeFile(i),this.redraw()})}),this.contentEl.setChildrenInPlace([a])};this.removeFile=async e=>{this.data.recentFiles=this.data.recentFiles.filter(a=>a.path!==e.path),await this.plugin.saveData()};this.focusFile=(e,a)=>{let n=this.app.vault.getFiles().find(s=>s.path===e.path);n?this.app.workspace.getLeaf(a).openFile(n):(new l.Notice("Cannot find a file with that name"),this.data.recentFiles=this.data.recentFiles.filter(s=>s.path!==e.path),this.plugin.saveData(),this.redraw())};this.plugin=a,this.data=n}async onOpen(){this.redraw()}getViewType(){return u}getDisplayText(){return"Recent Files"}getIcon(){return"clock"}onPaneMenu(e){e.addItem(a=>{a.setTitle("Clear list").setIcon("sweep").onClick(async()=>{this.data.recentFiles=[],await this.plugin.saveData(),this.redraw()})}).addItem(a=>{a.setTitle("Close").setIcon("cross").onClick(()=>{this.app.workspace.detachLeavesOfType(u)})})}},M=class extends l.Plugin{constructor(){super(...arguments);this.pruneOmittedFiles=async()=>{let e=this.data.recentFiles.length;this.data.recentFiles=this.data.recentFiles.filter(this.shouldAddFile),e!==this.data.recentFiles.length&&await this.saveData()};this.pruneLength=async()=>{let e=this.data.recentFiles.length-(this.data.maxLength||q);e>0&&(this.data.recentFiles.splice(this.data.recentFiles.length-e,e),await this.saveData())};this.shouldAddFile=e=>{var g,o;let a=this.data.omittedPaths.filter(i=>i.length>0),n=i=>{try{return new RegExp(i).test(e.path)}catch(d){return console.error("Recent Files: Invalid regex pattern: "+i),!1}};if(a.some(n))return!1;let s=this.app.vault.getFileByPath(e.path);if(s){let i=this.data.omittedTags.filter(f=>f.length>0),d=(o=(g=this.app.metadataCache.getFileCache(s))==null?void 0:g.frontmatter)==null?void 0:o.tags,r=f=>{try{return new RegExp(f).test(d.toString())}catch(m){return console.error("Recent Files: Invalid regex pattern: "+f),!1}};if(i.some(r))return!1}let h=this.app.internalPlugins.getEnabledPluginById("bookmarks");return!(s&&this.data.omitBookmarks&&h&&h.items.some(({path:d})=>d===s.path))};this.update=async e=>{if(!e)return;await this.updateData(e);let a=this.app.workspace.getLeavesOfType(u).first();a&&a.view instanceof b&&a.view.redraw()};this.onFileOpen=async e=>{if(!e)return;this.data.updateOn==="file-edit"?(this.app.workspace.off("quick-preview",this.waitingForEdit),this.registerEvent(this.app.workspace.on("quick-preview",this.waitingForEdit))):this.update(e);let a=this.app.workspace.getLeavesOfType(u).first();a&&a.view instanceof b&&a.view.redraw()};this.waitingForEdit=async(e,a)=>{this.update(e),this.app.workspace.off("quick-preview",this.waitingForEdit)};this.updateData=async e=>{let a=this.data.recentFiles.length;this.data.recentFiles=this.data.recentFiles.filter(s=>s.path!==e.path);let n=a!==this.data.recentFiles.length;this.shouldAddFile(e)&&(this.data.recentFiles.unshift({basename:e.basename,path:e.path}),n=!0),await this.pruneLength(),n&&await this.saveData()};this.handleRename=async(e,a)=>{var s;let n=this.data.recentFiles.find(h=>h.path===a);n&&(n.path=e.path,n.basename=this.trimExtension(e.name),(s=this.view)==null||s.redraw(),await this.saveData())};this.handleDelete=async e=>{var n;let a=this.data.recentFiles.length;this.data.recentFiles=this.data.recentFiles.filter(s=>s.path!==e.path),a!==this.data.recentFiles.length&&((n=this.view)==null||n.redraw(),await this.saveData())};this.trimExtension=e=>e.replace(/\.[^/.]+$/,"")}async onload(){console.log("Recent Files: Loading plugin v"+this.manifest.version),await this.loadData(),(0,l.addIcon)("sweep",C1),this.registerView(u,e=>this.view=new b(e,this,this.data)),this.addCommand({id:"recent-files-open",name:"Open",callback:async()=>{let e;[e]=this.app.workspace.getLeavesOfType(u),e||(e=this.app.workspace.getLeftLeaf(!1),await(e==null?void 0:e.setViewState({type:u}))),e&&this.app.workspace.revealLeaf(e)}}),this.app.workspace.registerHoverLinkSource(u,{display:"Recent Files",defaultMod:!0}),this.registerEvent(this.app.vault.on("rename",this.handleRename)),this.registerEvent(this.app.vault.on("delete",this.handleDelete)),this.registerEvent(this.app.workspace.on("file-open",this.onFileOpen)),this.addSettingTab(new x(this.app,this))}onunload(){this.app.workspace.unregisterHoverLinkSource(u)}async loadData(){this.data=Object.assign(i1,await super.loadData())}async saveData(){await super.saveData(this.data)}async onExternalSettingsChange(){var e;await this.loadData(),await this.pruneLength(),await this.pruneOmittedFiles(),(e=this.view)==null||e.redraw()}onUserEnable(){this.app.workspace.ensureSideLeaf(u,"left",{reveal:!0})}},x=class extends l.PluginSettingTab{constructor(t,e){super(t,e),this.plugin=e}display(){let{containerEl:t}=this;t.empty();let e=document.createDocumentFragment(),a=document.createElement("a");a.href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#writing_a_regular_expression_pattern",a.text="MDN - Regular expressions",e.append("RegExp patterns to ignore. One pattern per line. See "),e.append(a),e.append(" for help."),new l.Setting(t).setName("Omitted pathname patterns").setDesc(e).addTextArea(o=>{o.inputEl.setAttr("rows",6),o.setPlaceholder(`^daily/ -\\.png$ -foobar.*baz`).setValue(this.plugin.data.omittedPaths.join(` -`)),o.inputEl.onblur=i=>{var r;let d=i.target.value;this.plugin.data.omittedPaths=d.split(` -`),this.plugin.pruneOmittedFiles(),(r=this.plugin.view)==null||r.redraw()}});let n=document.createDocumentFragment();n.append("Frontmatter-tag patterns to ignore. One pattern per line."),new l.Setting(t).setName("Omitted frontmatter-tag patterns").setDesc(n).addTextArea(o=>{o.inputEl.setAttr("rows",6),o.setPlaceholder(`ignore -archive/a/b`).setValue(this.plugin.data.omittedTags.join(` -`)),o.inputEl.onblur=i=>{var r;let d=i.target.value;this.plugin.data.omittedTags=d.split(` -`),this.plugin.pruneOmittedFiles(),(r=this.plugin.view)==null||r.redraw()}}),new l.Setting(t).setName("Omit bookmarked files").addToggle(o=>{o.setValue(this.plugin.data.omitBookmarks).onChange(i=>{var d;this.plugin.data.omitBookmarks=i,this.plugin.pruneOmittedFiles(),(d=this.plugin.view)==null||d.redraw()})}),new l.Setting(t).setName("Update list when file is:").addDropdown(o=>{o.addOption("file-open","Opened").addOption("file-edit","Changed").setValue(this.plugin.data.updateOn).onChange(i=>{var d;this.plugin.data.updateOn=i,this.plugin.pruneOmittedFiles(),(d=this.plugin.view)==null||d.redraw()})}),new l.Setting(t).setName("List length").setDesc("Maximum number of filenames to keep in the list.").addText(o=>{var i;o.inputEl.setAttr("type","number"),o.inputEl.setAttr("placeholder",q),o.setValue(((i=this.plugin.data.maxLength)==null?void 0:i.toString())||"").onChange(d=>{let r=parseInt(d,10);if(!Number.isNaN(r)&&r<=0){new l.Notice("List length must be a positive integer");return}}),o.inputEl.onblur=d=>{var m;let r=d.target.value,f=parseInt(r,10);this.plugin.data.maxLength=f,this.plugin.pruneLength(),(m=this.plugin.view)==null||m.redraw()}});let s=t.createEl("div",{cls:"recent-files-donation"}),h=document.createElement("p");h.appendText("If this plugin adds value for you and you would like to help support continued development, please use the buttons below:"),s.appendChild(h);let g=new DOMParser;s.appendChild(j("https://paypal.me/tgrosinger",g.parseFromString(s1,"text/xml").documentElement)),s.appendChild(j("https://www.buymeacoffee.com/tgrosinger",g.parseFromString(n1,"text/xml").documentElement))}},j=(C,t)=>{let e=document.createElement("a");return e.setAttribute("href",C),e.addClass("recent-files-donate-button"),e.appendChild(t),e},C1=` - - - - - - - -`,n1=` - - - - - - - - - - - - - - - - - - - - - -`,s1=` - - - - - - - -`; - -/* nosourcemap */ \ No newline at end of file diff --git a/.obsidian/plugins/recent-files-obsidian/manifest.json b/.obsidian/plugins/recent-files-obsidian/manifest.json deleted file mode 100644 index b8c9d82..0000000 --- a/.obsidian/plugins/recent-files-obsidian/manifest.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "id": "recent-files-obsidian", - "name": "Recent Files", - "version": "1.7.6", - "minAppVersion": "0.16.3", - "description": "List files by most recently opened", - "author": "Tony Grosinger", - "authorUrl": "https://grosinger.net", - "isDesktopOnly": false, - "fundingUrl": { - "Github Sponsor": "https://github.com/sponsors/tgrosinger", - "Buy me a Coffee": "https://buymeacoffee.com/tgrosinger", - "Paypal": "https://paypal.me/tgrosinger" - }, - "donation": "https://buymeacoffee.com/tgrosinger" -} \ No newline at end of file diff --git a/.obsidian/plugins/recent-files-obsidian/styles.css b/.obsidian/plugins/recent-files-obsidian/styles.css deleted file mode 100644 index 87e0c2d..0000000 --- a/.obsidian/plugins/recent-files-obsidian/styles.css +++ /dev/null @@ -1,34 +0,0 @@ -.recent-files-file { - .tree-item-spacer { - flex-grow: 1; - } -} - -.recent-files-title { - justify-content: flex-start; - align-items: unset; -} - -.recent-files-file-delete { - justify-content: right; - display: none; -} - -.recent-files-title:hover .recent-files-file-delete { - display: flex; - cursor: var(--cursor); -} - -.recent-files-file-delete:hover { - color: var(--nav-item-color-hover); -} - -.recent-files-donation { - width: 70%; - margin: 0 auto; - text-align: center; -} - -.recent-files-donate-button { - margin: 10px; -} \ No newline at end of file diff --git a/.obsidian/snippets/myTheme.css b/.obsidian/snippets/myTheme.css deleted file mode 100644 index a042929..0000000 --- a/.obsidian/snippets/myTheme.css +++ /dev/null @@ -1,25 +0,0 @@ -/* === 颜色变量 === */ -:root { - --h1-color: #172a4f; - --h2-color: #4a5c7a; - --h3-color: #6b7280; - - --bold-color: var(--h1-color); -} - -/* === 标题样式 === */ -h1 { - color: var(--h1-color); -} -h2 { - color: var(--h2-color); -} -h3 { - color: var(--h3-color); -} - -/* === 粗体样式 === */ -div.cm-line span.cm-strong, -div p strong { - color: var(--bold-color) !important; -} diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index b1a8a0b..a831550 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -4,11 +4,11 @@ "type": "split", "children": [ { - "id": "907e9a7a1202bddd", + "id": "f5a820b24c2967c5", "type": "tabs", "children": [ { - "id": "b38877d81f5d7556", + "id": "5ac4315e91879622", "type": "leaf", "state": { "type": "empty", @@ -29,7 +29,6 @@ { "id": "6836caf2765d7139", "type": "tabs", - "dimension": 71.87039764359352, "children": [ { "id": "c8718c0c63702202", @@ -50,7 +49,7 @@ "state": { "type": "search", "state": { - "query": "openclaw", + "query": "path: resource/工具/obsidian/scripts ", "matchingCase": false, "explainSearch": true, "collapseAll": false, @@ -72,27 +71,10 @@ } } ] - }, - { - "id": "467278b27553fb8c", - "type": "tabs", - "dimension": 28.12960235640648, - "children": [ - { - "id": "c7138b775f1dd80e", - "type": "leaf", - "state": { - "type": "recent-files", - "state": {}, - "icon": "clock", - "title": "Recent Files" - } - } - ] } ], "direction": "horizontal", - "width": 302.5 + "width": 235.5 }, "right": { "id": "ca733f6d5936ae40", @@ -101,7 +83,7 @@ { "id": "1f21045435bfa327", "type": "tabs", - "dimension": 57.8883495145631, + "dimension": 57.038834951456316, "children": [ { "id": "43a2e8e1d9201229", @@ -183,9 +165,7 @@ "type": "leaf", "state": { "type": "footnotes", - "state": { - "file": "000-Inbox/20260305103657.md" - }, + "state": {}, "icon": "lucide-file-signature", "title": "脚注" } @@ -193,12 +173,12 @@ ] }, { - "id": "ea8a40d57ef90e62", + "id": "e2c44b9c5d0747bb", "type": "tabs", - "dimension": 42.1116504854369, + "dimension": 42.961165048543684, "children": [ { - "id": "499dbd491c6fb256", + "id": "736f0891b55bede0", "type": "leaf", "state": { "type": "calendar", @@ -211,8 +191,7 @@ } ], "direction": "horizontal", - "width": 300.5, - "collapsed": true + "width": 297.5 }, "left-ribbon": { "hiddenItems": { @@ -222,48 +201,48 @@ "daily-notes:打开/创建今天的日记": false, "canvas:新建白板": false, "bases:新建数据库": false, - "templater-obsidian:Templater": true, - "obsidian-excalidraw-plugin:New drawing": false + "obsidian-excalidraw-plugin:New drawing": false, + "templater-obsidian:Templater": false } }, "active": "c8718c0c63702202", "lastOpenFiles": [ + "000-inbox/20260328215585.md", + "000-inbox/20260328220243.md", + "000-inbox/20260328213028.md", + "000-Inbox/20260328215585.md", + "000-Inbox/20260328220243.md", + "000-Inbox/20260328213028.md", + "000-inbox/20260328212556.md", + "000-inbox/20260328212865.md", + "000-inbox/20260328182832.md", + "000-inbox/20260328182250.md", + "000-Inbox/20260328212865.md", + "resource/工具/obsidian/x-callback-url.md", + "000-Inbox/20260328212556.md", + "000-Inbox/20260328182832.md", + "000-Inbox/20260328182250.md", + "attachment/templates/移动杭研-问题记录.md", + "attachment/templates/移动杭研-开发笔记.md", + "attachment/templates/日常记录-闪念笔记.md", + "attachment/templates/日常记录-日记模板.md", + "000-inbox/20260328181207.md", + "000-Inbox/20260328181207.md", "000-inbox/jinja.md", - "000-inbox/20260328124189.md", - "000-Inbox/20260328124189.md", - "resource/ai/大模型安装笔记/Qwen3.5(通义千问 3.5)系列的多模态图文大模型(Vision-Language Models).md", - "calendar/diary/2026-03-27.md", - "work/移动杭研/业务梳理/x-csrf-token.md", - "calendar/diary/2026-03-26.md", - "000-inbox/需求-命中率计算.md", "000-inbox/Docker 核心知识与实战笔记.md", - "resource/系统/GNU Screen 命令全解析.md", - "resource/ai/大模型安装笔记/结构化输出和工具调用.md", - "resource/前端/如何成为一个 React 工程师呢?.md", - "000-inbox/20260327101490.md", - "000-Inbox/20260327113359.md", - "000-Inbox/20260327151942.md", - "000-inbox/20260327151942.md", - "000-Inbox/20260327105648.md", - "calendar/diary/2026-03-02.md", - "000-Inbox/20260327101490.md", - "calendar/diary/2026-03-23.md", - "calendar/diary/2026-03-20.md", - "calendar/diary/2026-03-21.md", - "calendar/diary/2026-03-25.md", - "calendar/diary/2026-03-24.md", - "calendar/diary/2026-03-19.md", - "calendar/diary/2026-03-18.md", - "attachment/image-20260325224201537.png", - "attachment/image-20260325224152205.png", - "attachment/image-20260325224141721.png", - "attachment/image-20260325224132102.png", - "attachment/image-20260325224123001.png", - "attachment/image-20260325224113880.png", - "attachment/image-20260325224055087.png", - "attachment/image-20260325224046176.png", - "attachment/image-20260325224034041.png", - "attachment/image-20260325224025519.png", + "000-inbox/需求-命中率计算.md", + "000-inbox/20260328145480111111.md", + "000-inbox/202603281454171.md", + "attachment/images-paste/image-20260325102650978.png", + "attachment/images-paste/image-20260325224014579.png", + "attachment/images-paste/image-20260325224132102.png", + "attachment/images-paste/image-20260325224152205.png", + "attachment/images-paste/image-20260325224201537.png", + "attachment/images-paste/image-20260325224141721.png", + "attachment/images-paste/image-20260325224123001.png", + "attachment/images-paste/image-20260325224113880.png", + "attachment/images-paste/image-20260325224055087.png", + "attachment/images-paste/image-20260325224046176.png", "resource/ai/大模型安装笔记", "work/移动杭研/问题处理/2026-03", "resource/ai/prompts/cosmic 业务版本", diff --git a/attachment/image-20260325102650978.png b/attachment/images-paste/image-20260325102650978.png similarity index 100% rename from attachment/image-20260325102650978.png rename to attachment/images-paste/image-20260325102650978.png diff --git a/attachment/image-20260325103231202.png b/attachment/images-paste/image-20260325103231202.png similarity index 100% rename from attachment/image-20260325103231202.png rename to attachment/images-paste/image-20260325103231202.png diff --git a/attachment/image-20260325103309652.png b/attachment/images-paste/image-20260325103309652.png similarity index 100% rename from attachment/image-20260325103309652.png rename to attachment/images-paste/image-20260325103309652.png diff --git a/attachment/image-20260325141838198.png b/attachment/images-paste/image-20260325141838198.png similarity index 100% rename from attachment/image-20260325141838198.png rename to attachment/images-paste/image-20260325141838198.png diff --git a/attachment/image-20260325223507125.png b/attachment/images-paste/image-20260325223507125.png similarity index 100% rename from attachment/image-20260325223507125.png rename to attachment/images-paste/image-20260325223507125.png diff --git a/attachment/image-20260325223528301.png b/attachment/images-paste/image-20260325223528301.png similarity index 100% rename from attachment/image-20260325223528301.png rename to attachment/images-paste/image-20260325223528301.png diff --git a/attachment/image-20260325224014579.png b/attachment/images-paste/image-20260325224014579.png similarity index 100% rename from attachment/image-20260325224014579.png rename to attachment/images-paste/image-20260325224014579.png diff --git a/attachment/image-20260325224025519.png b/attachment/images-paste/image-20260325224025519.png similarity index 100% rename from attachment/image-20260325224025519.png rename to attachment/images-paste/image-20260325224025519.png diff --git a/attachment/image-20260325224034041.png b/attachment/images-paste/image-20260325224034041.png similarity index 100% rename from attachment/image-20260325224034041.png rename to attachment/images-paste/image-20260325224034041.png diff --git a/attachment/image-20260325224046176.png b/attachment/images-paste/image-20260325224046176.png similarity index 100% rename from attachment/image-20260325224046176.png rename to attachment/images-paste/image-20260325224046176.png diff --git a/attachment/image-20260325224055087.png b/attachment/images-paste/image-20260325224055087.png similarity index 100% rename from attachment/image-20260325224055087.png rename to attachment/images-paste/image-20260325224055087.png diff --git a/attachment/image-20260325224113880.png b/attachment/images-paste/image-20260325224113880.png similarity index 100% rename from attachment/image-20260325224113880.png rename to attachment/images-paste/image-20260325224113880.png diff --git a/attachment/image-20260325224123001.png b/attachment/images-paste/image-20260325224123001.png similarity index 100% rename from attachment/image-20260325224123001.png rename to attachment/images-paste/image-20260325224123001.png diff --git a/attachment/image-20260325224132102.png b/attachment/images-paste/image-20260325224132102.png similarity index 100% rename from attachment/image-20260325224132102.png rename to attachment/images-paste/image-20260325224132102.png diff --git a/attachment/image-20260325224141721.png b/attachment/images-paste/image-20260325224141721.png similarity index 100% rename from attachment/image-20260325224141721.png rename to attachment/images-paste/image-20260325224141721.png diff --git a/attachment/image-20260325224152205.png b/attachment/images-paste/image-20260325224152205.png similarity index 100% rename from attachment/image-20260325224152205.png rename to attachment/images-paste/image-20260325224152205.png diff --git a/attachment/image-20260325224201537.png b/attachment/images-paste/image-20260325224201537.png similarity index 100% rename from attachment/image-20260325224201537.png rename to attachment/images-paste/image-20260325224201537.png diff --git a/calendar/diary/2026-03-25.md b/calendar/diary/2026-03-25.md index 1baf46f..db56475 100644 --- a/calendar/diary/2026-03-25.md +++ b/calendar/diary/2026-03-25.md @@ -26,7 +26,7 @@ DeepSeek-V3.2 | `--enable-auto-tool-choice` | 默认关闭(False) | 传 `--enable-auto-tool-choice` 开启;或显式传 `--no-enable-auto-tool-choice` 关闭 | 允许模型自己决定是否调用工具 | 不开时,模型通常不会主动发起 tool call;开了后,模型可根据问题自动选择 MCP/tool | | `--tool-call-parser` | 默认无(None) | 传一个解析器名字,比如 `openai`、`llama3_json`、`hermes`、`mistral`、`qwen3_xml` 等 | 指定如何解析模型输出的工具调用格式 | 不传时,即使模型输出了工具调用内容,也可能无法被正确识别;传错了会导致 tool call 解析失败 | -![](../../attachment/image-20260325141838198.png) +![](../../attachment/images-paste/image-20260325141838198.png) # 总结 diff --git a/resource/ai/大模型安装笔记/大模型中的参数、权重与数值类型整理.md b/resource/ai/大模型安装笔记/大模型中的参数、权重与数值类型整理.md index f6fdafb..34aac44 100644 --- a/resource/ai/大模型安装笔记/大模型中的参数、权重与数值类型整理.md +++ b/resource/ai/大模型安装笔记/大模型中的参数、权重与数值类型整理.md @@ -200,7 +200,7 @@ benchmark } ``` -![](../../../attachment/image-20260325103309652.png) +![](../../../attachment/images-paste/image-20260325103309652.png) ``` { @@ -254,4 +254,4 @@ benchmark } ``` -![](../../../attachment/image-20260325103231202.png) +![](../../../attachment/images-paste/image-20260325103231202.png) diff --git a/resource/系统/netflix 界面切换为简中.md b/resource/系统/netflix 界面切换为简中.md index 4b3e4a8..3482a7d 100644 --- a/resource/系统/netflix 界面切换为简中.md +++ b/resource/系统/netflix 界面切换为简中.md @@ -19,7 +19,7 @@ 4. 然后将请求发出去就可以了。(这里我是把 bash 的 cURL 放到了 Postman 中请求了一下。大家可以任意发挥,只要是能请求通就行啦。) 5. 然后你的电脑和手机都会变为简中。 -![](../../attachment/image-20260325224152205.png) +![](../../attachment/images-paste/image-20260325224152205.png) > [!TIP] > @@ -27,4 +27,4 @@ > > 它可能是空白或者 Dansk,不用管,后台配置已经是简中了。 -![](../../attachment/image-20260325224201537.png) +![](../../attachment/images-paste/image-20260325224201537.png) diff --git a/resource/系统/构建 HUGO 博客的完整指南:从搭建到部署.md b/resource/系统/构建 HUGO 博客的完整指南:从搭建到部署.md index 44e8d9b..a7cf528 100644 --- a/resource/系统/构建 HUGO 博客的完整指南:从搭建到部署.md +++ b/resource/系统/构建 HUGO 博客的完整指南:从搭建到部署.md @@ -477,7 +477,7 @@ jobs: 对应了设置中的如下配置,我图片存储在了 images 下: -![](../../attachment/image-20260325223507125.png) +![](../../attachment/images-paste/image-20260325223507125.png) **Hugo 配置** @@ -515,19 +515,19 @@ attachments/ 我的配置如下: -![](../../attachment/image-20260325223528301.png) +![](../../attachment/images-paste/image-20260325223528301.png) 上图重 `Attachment location` 需为 `/`,否则不适配插件会有找不到图片的异常信息。 -![](../../attachment/image-20260325224014579.png) +![](../../attachment/images-paste/image-20260325224014579.png) 上图所需要的配置在 R2 配置界面均可以找到: -![](../../attachment/image-20260325224025519.png) +![](../../attachment/images-paste/image-20260325224025519.png) 存储桶设置中,推荐自定义域,当然前提时你需要在 Cloud flare 进行域名托管。才可以使用子域。 -![](../../attachment/image-20260325224034041.png) +![](../../attachment/images-paste/image-20260325224034041.png) # 缓存加速 @@ -541,21 +541,21 @@ attachments/ 将域名托管到 Cf 后,可以新增 Cache Rules。 -![](../../attachment/image-20260325224046176.png) +![](../../attachment/images-paste/image-20260325224046176.png) 具体规则如下: -![](../../attachment/image-20260325224055087.png) +![](../../attachment/images-paste/image-20260325224055087.png) -![](../../attachment/image-20260325224113880.png) +![](../../attachment/images-paste/image-20260325224113880.png) ## 3. SSL/TLS 加密 -![](../../attachment/image-20260325224123001.png) +![](../../attachment/images-paste/image-20260325224123001.png) -![](../../attachment/image-20260325224132102.png) +![](../../attachment/images-paste/image-20260325224132102.png) -![](../../attachment/image-20260325224141721.png) +![](../../attachment/images-paste/image-20260325224141721.png) CloudFlare 为用户提供的源服务器证书是由 Cloudflare 签名的免费 TLS 证书,该域名证书属于泛域名证书,最长支持 15 年,主要用于源服务器和 Cloudflare 之间的流量加密。但是这个证书属于自签名证书,证书链不完整,缺少根证书。