diff --git a/manifest.json b/manifest.json index 520b861..f509ee7 100755 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { - "id": "Obsidian-Attachment-Upload-Command", + "id": "Obsidian-Attachment-Upload", "name": "Attachment Upload", "version": "1.0.0", "minAppVersion": "0.15.0", diff --git a/package-lock.json b/package-lock.json index c1bd1a4..e13a4ac 100755 --- a/package-lock.json +++ b/package-lock.json @@ -37,9 +37,9 @@ "peer": true }, "node_modules/@codemirror/view": { - "version": "6.21.4", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.21.4.tgz", - "integrity": "sha512-WKVZ7nvN0lwWPfAf05WxWqTpwjC8YN3q5goj3CsSig7//DD81LULgOx3nBegqpqP0iygBqRmW8z0KSc2QTAdAg==", + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.22.0.tgz", + "integrity": "sha512-6zLj4YIoIpfTGKrDMTbeZRpa8ih4EymMCKmddEDcJWrCdp/N1D46B38YEz4creTb4T177AVS9EyXkLeC/HL2jA==", "dev": true, "peer": true, "dependencies": { @@ -427,9 +427,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "peer": true, "dependencies": { @@ -451,9 +451,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz", + "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==", "dev": true, "peer": true, "engines": { @@ -541,21 +541,21 @@ } }, "node_modules/@types/estree": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.4.tgz", - "integrity": "sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/node": { - "version": "16.18.59", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.59.tgz", - "integrity": "sha512-PJ1w2cNeKUEdey4LiPra0ZuxZFOGvetswE8qHRriV/sUkL5Al4tTmPV9D2+Y/TPIxTHHgxTfRjZVKWhPw/ORhQ==", + "version": "16.18.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.60.tgz", + "integrity": "sha512-ZUGPWx5vKfN+G2/yN7pcSNLkIkXEvlwNaJEd4e0ppX7W2S8XAkdc/37hM4OUNJB9sa0p12AOvGvxL4JCPiz9DA==", "dev": true }, "node_modules/@types/tern": { @@ -1051,16 +1051,16 @@ } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz", + "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==", "dev": true, "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.53.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -1274,9 +1274,9 @@ "peer": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", diff --git a/src/main.ts b/src/main.ts index 2dd3a8c..5e358f4 100755 --- a/src/main.ts +++ b/src/main.ts @@ -3,7 +3,6 @@ import { App, Editor, MarkdownView, - Modal, Notice, Plugin, PluginSettingTab, @@ -37,8 +36,8 @@ interface uploadCommandDict { } const uploadCommandDict: uploadCommandDict = { uPic: "/Applications/uPic.app/Contents/MacOS/uPic -o url -u %s", - custom: "your custom command here", - imgur: "imgur uploader command", + Picsee: "/Applications/Picsee.app/Contents/MacOS/Picsee -u %s", + custom: "", }; const DEFAULT_SETTINGS: PluginSettings = { uploadService: "uPic", @@ -51,8 +50,8 @@ export default class AttachmentUpload extends Plugin { settings: PluginSettings; async onload() { - const currentDate = new Date(); - console.log(String(currentDate)); + // const currentDate = new Date(); + // console.log(String(currentDate)); await this.loadSettings(); const ribbonIconEl = this.addRibbonIcon( @@ -60,43 +59,18 @@ export default class AttachmentUpload extends Plugin { "Upload Attachments", (evt: MouseEvent) => { this.uploadEditorAttachment(); - new Notice("替换完成"); } ); - // Perform additional things with the ribbon - ribbonIconEl.addClass("my-plugin-ribbon-class"); + ribbonIconEl.addClass("ribbon-class"); this.addCommand({ - id: "sample-editor-command", - name: "Sample editor command", + id: "upload-editor-attachment", + name: "Upload editor attachment", editorCallback: (editor: Editor, view: MarkdownView) => { - editor.replaceSelection(String(this.uploadEditorAttachment())); this.uploadEditorAttachment(); }, }); - // This adds a complex command that can check whether the current state of the app allows execution of the command - this.addCommand({ - id: "open-sample-modal-complex", - name: "Open sample modal (complex)", - checkCallback: (checking: boolean) => { - this.uploadEditorAttachment(); - // Conditions to check - const markdownView = - this.app.workspace.getActiveViewOfType(MarkdownView); - if (markdownView) { - // If checking is true, we're simply "checking" if the command can be run. - // If checking is false, then we want to actually perform the operation. - if (!checking) { - new SampleModal(this.app).open(); - } - - // This command will only show up in Command Palette when the check function returns true - return true; - } - }, - }); - // This adds a settings tab so the user can configure various aspects of the plugin this.addSettingTab(new SettingTab(this.app, this)); } @@ -104,8 +78,31 @@ export default class AttachmentUpload extends Plugin { const activeEditor = this.app.workspace.activeEditor; if (activeEditor) { const attachments = this.getEditorAttachments(activeEditor); + const countExistenceState = attachments.reduce( + (acc: Record, attachment) => { + if (!acc[attachment.existenceState]) { + acc[attachment.existenceState] = 0; + } + acc[attachment.existenceState]++; + return acc; + }, + {} + ); + new Notice( + (countExistenceState["local"] + ? countExistenceState["local"] + : 0) + + "个本地附件\n" + + (countExistenceState["network"] + ? countExistenceState["network"] + : 0) + + "个网络附件\n" + + (countExistenceState["missing"] + ? countExistenceState["missing"] + : 0) + + "个未创建附件\n" + ); attachments.forEach(async (attachment) => { - console.log(attachment.inSystemPath); if (attachment.existenceState === "missing") { return; } @@ -113,7 +110,7 @@ export default class AttachmentUpload extends Plugin { return; } if (attachment.existenceState === "local") { - const uploadUrl = await this.uploadServe( + const uploadResult = await this.uploadServe( attachment.inSystemPath ); activeEditor?.editor?.setValue( @@ -121,7 +118,7 @@ export default class AttachmentUpload extends Plugin { ?.getValue() .replace( attachment.source, - `![${attachment.alt}](${uploadUrl})` + `![${attachment.alt}](${uploadResult.url})` ) ); } @@ -144,11 +141,17 @@ export default class AttachmentUpload extends Plugin { const alt = match.match(/\[(.*?)\]/)?.[1]; if (attSourcePath) { const file = parse(normalizePath(decodeURI(attSourcePath))); - const searchFile = this.app.vault - .getFiles() - .find( - (f) => f.name === file.name + file.ext.toLowerCase() - ); + // TODO 改用getAbstractFileByPath方法 + console.log(file.base); + console.log(attSourcePath); + const searchFile = this.app.vault.getAbstractFileByPath( + normalizePath(decodeURI(attSourcePath)) + ); + console.log(searchFile?.name); + // .getFiles() + // .find( + // (f) => f.name === file.name + file.ext.toLowerCase() + // ); const attachment = { source: match, alt: alt ? alt : file.name, @@ -176,22 +179,35 @@ export default class AttachmentUpload extends Plugin { /** 上传命令执行后从shell输出中提取上传后的链接 * @param path 要上传的文件在系统内的路径 */ - async uploadServe(path: string): Promise { + async uploadServe( + path: string + ): Promise<{ success: boolean; url?: string; errorMessage?: string }> { const execPromise = promisify(exec); console.log(this.settings.uploadCommand); const command = format(this.settings.uploadCommand, path); try { const { stdout } = await execPromise(command); const urlMatch = stdout.match(/\s+(https?:\/\/\S+)/); - return urlMatch ? urlMatch?.[1] : stdout; + if (urlMatch) { + return { + success: true, + url: urlMatch[1], + }; + } else { + return { + success: false, + errorMessage: stdout, + }; + } } catch (err) { console.error(`err: ${err}`); + new Notice(err.message); throw err; } } async loadSettings() { this.settings = Object.assign( - // {}, + {}, DEFAULT_SETTINGS, await this.loadData() ); @@ -204,22 +220,6 @@ export default class AttachmentUpload extends Plugin { onunload() {} } -class SampleModal extends Modal { - constructor(app: App) { - super(app); - } - - onOpen() { - const { contentEl } = this; - contentEl.setText("Woah!"); - } - - onClose() { - const { contentEl } = this; - contentEl.empty(); - } -} - class SettingTab extends PluginSettingTab { plugin: AttachmentUpload; @@ -233,22 +233,22 @@ class SettingTab extends PluginSettingTab { containerEl.empty(); containerEl.createEl("h1", { text: "上传命令" }); - new Setting(containerEl) - .setName("上传服务") - .setDesc("请选择") - .addDropdown((dropdown) => { - dropdown.addOptions({ + new Setting(containerEl).setName("上传服务").addDropdown((dropdown) => { + return dropdown + .addOptions({ uPic: "uPic", + Picsee: "Picsee", custom: "custom", - }); - dropdown.onChange(async (value) => { + }) + .setValue(this.plugin.settings.uploadService) + .onChange(async (value) => { this.plugin.settings.uploadService = value; this.display(); await this.plugin.saveSettings(); }); - dropdown.setValue(this.plugin.settings.uploadService); - // dropdown.selectEl.style.width = "100%"; - }); + + // dropdown.selectEl.style.width = "100%"; + }); new Setting(containerEl) .setName("执行命令") @@ -257,6 +257,7 @@ class SettingTab extends PluginSettingTab { ) .addTextArea((textArea) => { textArea + .setPlaceholder("请输入") .setValue( uploadCommandDict[this.plugin.settings.uploadService] ) @@ -269,17 +270,25 @@ class SettingTab extends PluginSettingTab { ); textArea.inputEl.style.height = "80px"; }); + new Setting(containerEl).setName("测试文件路径").addText((text) => { text.onChange(async (value) => { this.plugin.settings.testFilePath = value; }); - new Setting(containerEl).addButton((btn) => { btn.setButtonText("上传测试").onClick(async () => { - const uploadUrl = await this.plugin.uploadServe( + if (!this.plugin.settings.testFilePath) { + new Notice("请填写测试文件路径"); + return; + } + const uploadResult = await this.plugin.uploadServe( this.plugin.settings.testFilePath ); - new Notice(uploadUrl); + new Notice( + uploadResult.success + ? "上传成功\n" + : "上传失败\n" + uploadResult.errorMessage + ); }); }); });