diff --git a/manifest.json b/manifest.json index 9aaf447..28ee2c6 100644 --- a/manifest.json +++ b/manifest.json @@ -1,8 +1,8 @@ { "id": "remotely-save", "name": "Remotely Save", - "version": "0.3.2", - "minAppVersion": "0.12.15", + "version": "0.3.3", + "minAppVersion": "0.13.21", "description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.", "author": "fyears", "authorUrl": "https://github.com/fyears", diff --git a/package.json b/package.json index 90fdad3..1bd62e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "remotely-save", - "version": "0.3.2", + "version": "0.3.3", "description": "This is yet another sync plugin for Obsidian app.", "scripts": { "dev2": "node esbuild.config.mjs", @@ -70,7 +70,7 @@ "loglevel": "^1.8.0", "mime-types": "^2.1.33", "nanoid": "^3.1.30", - "obsidian": "^0.12.0", + "obsidian": "^0.13.26", "path-browserify": "^1.0.1", "process": "^0.11.10", "qrcode": "^1.5.0", diff --git a/src/baseTypes.ts b/src/baseTypes.ts index c108ae9..6d25d82 100644 --- a/src/baseTypes.ts +++ b/src/baseTypes.ts @@ -113,3 +113,5 @@ export interface FileOrFolderMixedState { syncDone?: "done"; remoteEncryptedKey?: string; } + +export const API_VER_STAT_FOLDER = "0.13.27"; diff --git a/src/main.ts b/src/main.ts index 6a02f17..0d2dc70 100644 --- a/src/main.ts +++ b/src/main.ts @@ -199,6 +199,7 @@ export default class RemotelySavePlugin extends Plugin { origMetadataOnRemote.deletions, localHistory, client.serviceType, + this.app.vault, this.settings.password ); log.info(plan.mixedStates); // for debugging diff --git a/src/sync.ts b/src/sync.ts index b4081e0..219f54d 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -1,9 +1,16 @@ -import { TAbstractFile, TFile, TFolder, Vault } from "obsidian"; -import type { +import { + TAbstractFile, + TFile, + TFolder, + Vault, + requireApiVersion, +} from "obsidian"; +import { RemoteItem, SUPPORTED_SERVICES_TYPE, DecisionType, FileOrFolderMixedState, + API_VER_STAT_FOLDER, } from "./baseTypes"; import { decryptBase32ToString, @@ -505,9 +512,10 @@ const assignOperationToFileInplace = ( throw Error(`no decision for ${JSON.stringify(r)}`); }; -const assignOperationToFolderInplace = ( +const assignOperationToFolderInplace = async ( origRecord: FileOrFolderMixedState, keptFolder: Set, + vault: Vault, password: string = "" ) => { let r = origRecord; @@ -523,10 +531,42 @@ const assignOperationToFolderInplace = ( if (r.deltimeLocal !== undefined || r.deltimeRemote !== undefined) { // it has some deletion "commands" - if ( - r.deltimeLocal !== undefined && - r.deltimeLocal >= (r.deltimeRemote !== undefined ? r.deltimeRemote : -1) - ) { + + const deltimeLocal = r.deltimeLocal !== undefined ? r.deltimeLocal : -1; + const deltimeRemote = + r.deltimeRemote !== undefined ? r.deltimeRemote : -1; + + // if it was created after deletion, we should keep it as is + if (requireApiVersion(API_VER_STAT_FOLDER)) { + if (r.existLocal) { + try { + const { ctime, mtime } = await vault.adapter.stat(r.key); + const cmtime = Math.max(ctime, mtime); + if ( + cmtime > 0 && + cmtime >= deltimeLocal && + cmtime >= deltimeRemote + ) { + keptFolder.add(getParentFolder(r.key)); + if (r.existLocal && r.existRemote) { + r.decision = "skipFolder"; + r.decisionBranch = 14; + } else if (r.existLocal || r.existRemote) { + r.decision = "createFolder"; + r.decisionBranch = 15; + } else { + throw Error( + `Error: Folder ${r.key} doesn't exist locally and remotely but is marked must be kept. Abort.` + ); + } + } + } catch (error) { + // pass + } + } + } + + if (deltimeLocal > 0 && deltimeLocal > deltimeRemote) { r.decision = "uploadLocalDelHistToRemoteFolder"; r.decisionBranch = 8; } else { @@ -585,6 +625,7 @@ export const getSyncPlan = async ( remoteDeleteHistory: DeletionOnRemote[], localDeleteHistory: FileFolderHistoryRecord[], remoteType: SUPPORTED_SERVICES_TYPE, + vault: Vault, password: string = "" ) => { const mixedStates = await ensembleMixedStates( @@ -609,7 +650,7 @@ export const getSyncPlan = async ( // decide some folders // because the keys are sorted by length // so all the children must have been shown up before in the iteration - assignOperationToFolderInplace(val, keptFolder, password); + await assignOperationToFolderInplace(val, keptFolder, vault, password); } else { // get all operations of files // and at the same time get some helper info for folders diff --git a/versions.json b/versions.json index 028676a..dcdd64b 100644 --- a/versions.json +++ b/versions.json @@ -1,3 +1,4 @@ { - "0.3.2": "0.12.15" + "0.3.2": "0.12.15", + "0.3.3": "0.13.21" }