diff --git a/manifest.json b/manifest.json index 55df52e..cc65e25 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "istart-note-ai", "name": "IStart-Note-AI", - "version": "1.7.0", + "version": "1.7.1", "minAppVersion": "1.4.0", "description": "Generate structured knowledge notes from questions and selected text using DeepSeek AI, with automatic concept pages, bidirectional links, and a question graph.", "author": "Yan", diff --git a/package.json b/package.json index f33a2e7..1c6def9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "istart-note-ai", - "version": "1.7.0", + "version": "1.7.1", "description": "IStart-Note-AI: DeepSeek-powered knowledge graph plugin for Obsidian", "main": "main.js", "scripts": { diff --git a/src/features/sync/BaiduSyncService.ts b/src/features/sync/BaiduSyncService.ts index 8d3ec29..987cb1e 100644 --- a/src/features/sync/BaiduSyncService.ts +++ b/src/features/sync/BaiduSyncService.ts @@ -139,6 +139,14 @@ export class BaiduSyncService { result.skipped = plans.length - uploadPlans.length; await this.saveMeta(meta); + + // 备份插件本身 + if (this.config.backupPlugin) { + const pluginResult = await this.backupPlugin(); + result.uploaded += pluginResult.uploaded; + result.failed += pluginResult.failed; + } + return result; } @@ -387,6 +395,72 @@ export class BaiduSyncService { return false; } + /** + * 备份插件本身(main.js, manifest.json, styles.css, data.json)到百度云。 + * 文件存储在 {remotePath}/_plugin/ 目录下。 + */ + async backupPlugin(): Promise<{ uploaded: number; failed: number }> { + if (!this.config.backupPlugin) return { uploaded: 0, failed: 0 }; + + const pluginDir = ".obsidian/plugins/istart-note-ai"; + const filesToBackup = ["main.js", "manifest.json", "styles.css", "data.json"]; + const remotePluginDir = `${this.config.remotePath}/_plugin`.replace(/\/+/g, "/"); + + await this.client.mkdir(remotePluginDir); + + let uploaded = 0; + let failed = 0; + + for (const fileName of filesToBackup) { + const localPath = `${pluginDir}/${fileName}`; + try { + const exists = await this.app.vault.adapter.exists(localPath); + if (!exists) continue; + + const content = await this.app.vault.adapter.readBinary(localPath); + const remotePath = `${remotePluginDir}/${fileName}`; + const ok = await this.client.uploadFile(content, remotePath); + if (ok) uploaded++; + else failed++; + } catch { + // 文件不存在或读取失败,跳过 + } + } + + return { uploaded, failed }; + } + + /** + * 从百度云恢复插件文件到本地。 + */ + async restorePlugin(): Promise<{ downloaded: number; failed: number }> { + const remotePluginDir = `${this.config.remotePath}/_plugin`.replace(/\/+/g, "/"); + const pluginDir = ".obsidian/plugins/istart-note-ai"; + + // 确保本地插件目录存在 + const dirExists = await this.app.vault.adapter.exists(pluginDir); + if (!dirExists) await this.app.vault.adapter.mkdir(pluginDir); + + const remoteFiles = await this.client.listFiles(remotePluginDir); + let downloaded = 0; + let failed = 0; + + for (const entry of remoteFiles) { + if (entry.isdir) continue; + try { + const content = await this.client.downloadFile(entry.path); + if (!content) { failed++; continue; } + const localPath = `${pluginDir}/${entry.server_filename}`; + await this.app.vault.adapter.writeBinary(localPath, content); + downloaded++; + } catch { + failed++; + } + } + + return { downloaded, failed }; + } + private async writeLocalFile(localPath: string, content: ArrayBuffer) { const dir = localPath.substring(0, localPath.lastIndexOf("/")); if (dir) { diff --git a/src/settings/SettingsTab.ts b/src/settings/SettingsTab.ts index 64b4a0a..ccd4638 100644 --- a/src/settings/SettingsTab.ts +++ b/src/settings/SettingsTab.ts @@ -190,6 +190,16 @@ export class DeepSeekSettingsTab extends PluginSettingTab { }) ); + new Setting(containerEl) + .setName("备份插件本身") + .setDesc("备份时包含插件文件(main.js、配置等),方便换设备恢复") + .addToggle((t) => + t.setValue(this.plugin.settings.baiduSync.backupPlugin).onChange(async (v) => { + this.plugin.settings.baiduSync.backupPlugin = v; + await this.plugin.saveSettings(); + }) + ); + new Setting(containerEl) .setName("忽略规则") .setDesc("正则表达式,匹配的文件路径将被跳过") diff --git a/src/types.ts b/src/types.ts index ad812d1..489c3fb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,6 +19,7 @@ export interface BaiduSyncConfig { tokenExpiresAt: string; // ISO 时间字符串 remotePath: string; // 远端备份根目录,如 /apps/istart-note-ai autoBackup: boolean; // 每次生成笔记后自动备份 + backupPlugin: boolean; // 备份时包含插件本身 ignorePattern: string; // 忽略规则(正则) fileSizeLimitMB: number; // 单文件大小限制 } @@ -32,6 +33,7 @@ export const DEFAULT_BAIDU_SYNC_CONFIG: BaiduSyncConfig = { tokenExpiresAt: "", remotePath: "/apps/istart-note-ai", autoBackup: false, + backupPlugin: false, ignorePattern: "", fileSizeLimitMB: 100, }; diff --git a/versions.json b/versions.json index eec70cc..a141138 100644 --- a/versions.json +++ b/versions.json @@ -10,5 +10,6 @@ "1.5.7": "1.4.0", "1.6.0": "1.4.0", "1.6.1": "1.4.0", - "1.7.0": "1.4.0" + "1.7.0": "1.4.0", + "1.7.1": "1.4.0" }