mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2025-12-21 13:41:29 +00:00
Fixed:
- File tracking logic has been refined.
This commit is contained in:
292
src/main.ts
292
src/main.ts
@@ -41,7 +41,7 @@ setNoticeClass(Notice);
|
|||||||
const ICHeader = "i:";
|
const ICHeader = "i:";
|
||||||
const ICHeaderEnd = "i;";
|
const ICHeaderEnd = "i;";
|
||||||
const ICHeaderLength = ICHeader.length;
|
const ICHeaderLength = ICHeader.length;
|
||||||
|
const FileWatchEventQueueMax = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns is internal chunk of file
|
* returns is internal chunk of file
|
||||||
@@ -109,6 +109,19 @@ function recentlyTouched(file: TFile) {
|
|||||||
function clearTouched() {
|
function clearTouched() {
|
||||||
touchedFiles = [];
|
touchedFiles = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CacheData = string | ArrayBuffer;
|
||||||
|
type FileEventType = "CREATE" | "DELETE" | "CHANGED" | "RENAME";
|
||||||
|
type FileEventArgs = {
|
||||||
|
file: TAbstractFile;
|
||||||
|
cache?: CacheData;
|
||||||
|
oldPath?: string;
|
||||||
|
ctx?: any;
|
||||||
|
}
|
||||||
|
type FileEventItem = {
|
||||||
|
type: FileEventType,
|
||||||
|
args: FileEventArgs
|
||||||
|
}
|
||||||
export default class ObsidianLiveSyncPlugin extends Plugin {
|
export default class ObsidianLiveSyncPlugin extends Plugin {
|
||||||
settings: ObsidianLiveSyncSettings;
|
settings: ObsidianLiveSyncSettings;
|
||||||
localDatabase: LocalPouchDB;
|
localDatabase: LocalPouchDB;
|
||||||
@@ -118,6 +131,9 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
suspended: boolean;
|
suspended: boolean;
|
||||||
deviceAndVaultName: string;
|
deviceAndVaultName: string;
|
||||||
isMobile = false;
|
isMobile = false;
|
||||||
|
isReady = false;
|
||||||
|
|
||||||
|
watchedFileEventQueue = [] as FileEventItem[];
|
||||||
|
|
||||||
getVaultName(): string {
|
getVaultName(): string {
|
||||||
return this.app.vault.getName() + (this.settings?.additionalSuffixOfDatabaseName ? ("-" + this.settings.additionalSuffixOfDatabaseName) : "");
|
return this.app.vault.getName() + (this.settings?.additionalSuffixOfDatabaseName ? ("-" + this.settings.additionalSuffixOfDatabaseName) : "");
|
||||||
@@ -277,10 +293,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
this.refreshStatusText = this.refreshStatusText.bind(this);
|
this.refreshStatusText = this.refreshStatusText.bind(this);
|
||||||
|
|
||||||
this.statusBar2 = this.addStatusBarItem();
|
this.statusBar2 = this.addStatusBarItem();
|
||||||
// this.watchVaultChange = debounce(this.watchVaultChange.bind(this), delay, false);
|
|
||||||
// this.watchVaultDelete = debounce(this.watchVaultDelete.bind(this), delay, false);
|
|
||||||
// this.watchVaultRename = debounce(this.watchVaultRename.bind(this), delay, false);
|
|
||||||
|
|
||||||
this.watchVaultChange = this.watchVaultChange.bind(this);
|
this.watchVaultChange = this.watchVaultChange.bind(this);
|
||||||
this.watchVaultCreate = this.watchVaultCreate.bind(this);
|
this.watchVaultCreate = this.watchVaultCreate.bind(this);
|
||||||
this.watchVaultDelete = this.watchVaultDelete.bind(this);
|
this.watchVaultDelete = this.watchVaultDelete.bind(this);
|
||||||
@@ -298,6 +310,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
// this.registerWatchEvents();
|
// this.registerWatchEvents();
|
||||||
this.addSettingTab(new ObsidianLiveSyncSettingTab(this.app, this));
|
this.addSettingTab(new ObsidianLiveSyncSettingTab(this.app, this));
|
||||||
|
|
||||||
|
this.registerFileWatchEvents();
|
||||||
this.app.workspace.onLayoutReady(async () => {
|
this.app.workspace.onLayoutReady(async () => {
|
||||||
if (this.localDatabase.isReady)
|
if (this.localDatabase.isReady)
|
||||||
try {
|
try {
|
||||||
@@ -700,12 +713,14 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
|
|
||||||
gcTimerHandler: any = null;
|
gcTimerHandler: any = null;
|
||||||
|
|
||||||
|
registerFileWatchEvents() {
|
||||||
registerWatchEvents() {
|
|
||||||
this.registerEvent(this.app.vault.on("modify", this.watchVaultChange));
|
this.registerEvent(this.app.vault.on("modify", this.watchVaultChange));
|
||||||
this.registerEvent(this.app.vault.on("delete", this.watchVaultDelete));
|
this.registerEvent(this.app.vault.on("delete", this.watchVaultDelete));
|
||||||
this.registerEvent(this.app.vault.on("rename", this.watchVaultRename));
|
this.registerEvent(this.app.vault.on("rename", this.watchVaultRename));
|
||||||
this.registerEvent(this.app.vault.on("create", this.watchVaultCreate));
|
this.registerEvent(this.app.vault.on("create", this.watchVaultCreate));
|
||||||
|
}
|
||||||
|
|
||||||
|
registerWatchEvents() {
|
||||||
this.registerEvent(this.app.workspace.on("file-open", this.watchWorkspaceOpen));
|
this.registerEvent(this.app.workspace.on("file-open", this.watchWorkspaceOpen));
|
||||||
window.addEventListener("visibilitychange", this.watchWindowVisibility);
|
window.addEventListener("visibilitychange", this.watchWindowVisibility);
|
||||||
window.addEventListener("online", this.watchOnline);
|
window.addEventListener("online", this.watchOnline);
|
||||||
@@ -728,6 +743,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
|
|
||||||
async watchWindowVisibilityAsync() {
|
async watchWindowVisibilityAsync() {
|
||||||
if (this.settings.suspendFileWatching) return;
|
if (this.settings.suspendFileWatching) return;
|
||||||
|
if (!this.isReady) return;
|
||||||
// if (this.suspended) return;
|
// if (this.suspended) return;
|
||||||
const isHidden = document.hidden;
|
const isHidden = document.hidden;
|
||||||
await this.applyBatchChange();
|
await this.applyBatchChange();
|
||||||
@@ -752,12 +768,125 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cache file and waiting to can be proceed.
|
||||||
|
async appendWatchEvent(type: FileEventType, file: TAbstractFile, oldPath?: string, ctx?: any) {
|
||||||
|
// check really we can process.
|
||||||
|
if (!this.isTargetFile(file)) return;
|
||||||
|
if (this.settings.suspendFileWatching) return;
|
||||||
|
|
||||||
|
let cache: null | string | ArrayBuffer;
|
||||||
|
// new file or something changed, cache the changes.
|
||||||
|
if (file instanceof TFile && (type == "CREATE" || type == "CHANGED")) {
|
||||||
|
if (recentlyTouched(file)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isPlainText(file.name)) {
|
||||||
|
cache = await this.app.vault.readBinary(file);
|
||||||
|
} else {
|
||||||
|
// cache = await this.app.vault.read(file);
|
||||||
|
cache = await this.app.vault.cachedRead(file);
|
||||||
|
if (!cache) cache = await this.app.vault.read(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this.settings.batchSave) {
|
||||||
|
// if the latest event is the same type, omit that
|
||||||
|
// a.md MODIFY <- this should be cancelled when a.md MODIFIED
|
||||||
|
// b.md MODIFY <- this should be cancelled when b.md MODIFIED
|
||||||
|
// a.md MODIFY
|
||||||
|
// a.md CREATE
|
||||||
|
// :
|
||||||
|
let i = this.watchedFileEventQueue.length;
|
||||||
|
while (i >= 0) {
|
||||||
|
i--;
|
||||||
|
if (i < 0) break;
|
||||||
|
if (this.watchedFileEventQueue[i].args.file.path != file.path) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.watchedFileEventQueue[i].type != type) break;
|
||||||
|
this.watchedFileEventQueue.remove(this.watchedFileEventQueue[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.watchedFileEventQueue.push({
|
||||||
|
type,
|
||||||
|
args: {
|
||||||
|
file,
|
||||||
|
oldPath,
|
||||||
|
cache,
|
||||||
|
ctx
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.refreshStatusText();
|
||||||
|
if (this.isReady) {
|
||||||
|
await this.procFileEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
async procFileEvent(applyBatch?: boolean) {
|
||||||
|
if (!this.isReady) return;
|
||||||
|
if (this.settings.batchSave) {
|
||||||
|
if (!applyBatch && this.watchedFileEventQueue.length < FileWatchEventQueueMax) {
|
||||||
|
// Defer till applying batch save or queue has been grown enough.
|
||||||
|
// or 120 seconds after.
|
||||||
|
setTrigger("applyBatchAuto", 120000, () => {
|
||||||
|
this.procFileEvent(true);
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearTrigger("applyBatchAuto");
|
||||||
|
const ret = await runWithLock("procFiles", false, async () => {
|
||||||
|
const procs = [...this.watchedFileEventQueue];
|
||||||
|
this.watchedFileEventQueue = [];
|
||||||
|
for (const queue of procs) {
|
||||||
|
const file = queue.args.file;
|
||||||
|
const cache = queue.args.cache;
|
||||||
|
if ((queue.type == "CREATE" || queue.type == "CHANGED") && file instanceof TFile) {
|
||||||
|
await this.updateIntoDB(file, false, cache);
|
||||||
|
}
|
||||||
|
if (queue.type == "DELETE") {
|
||||||
|
if (file instanceof TFile) {
|
||||||
|
await this.deleteFromDB(file);
|
||||||
|
} else if (file instanceof TFolder) {
|
||||||
|
await this.deleteFolderOnDB(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (queue.type == "RENAME") {
|
||||||
|
await this.watchVaultRenameAsync(file, queue.args.oldPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.refreshStatusText();
|
||||||
|
})
|
||||||
|
this.refreshStatusText();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
watchVaultCreate(file: TAbstractFile, ctx?: any) {
|
||||||
|
this.appendWatchEvent("CREATE", file, null, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchVaultChange(file: TAbstractFile, ctx?: any) {
|
||||||
|
this.appendWatchEvent("CHANGED", file, null, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchVaultDelete(file: TAbstractFile, ctx?: any) {
|
||||||
|
this.appendWatchEvent("DELETE", file, null, ctx);
|
||||||
|
}
|
||||||
|
watchVaultRename(file: TAbstractFile, oldFile: string, ctx?: any) {
|
||||||
|
this.appendWatchEvent("RENAME", file, oldFile, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
watchWorkspaceOpen(file: TFile) {
|
watchWorkspaceOpen(file: TFile) {
|
||||||
if (this.settings.suspendFileWatching) return;
|
if (this.settings.suspendFileWatching) return;
|
||||||
|
if (!this.isReady) return;
|
||||||
this.watchWorkspaceOpenAsync(file);
|
this.watchWorkspaceOpenAsync(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
async watchWorkspaceOpenAsync(file: TFile) {
|
async watchWorkspaceOpenAsync(file: TFile) {
|
||||||
|
if (this.settings.suspendFileWatching) return;
|
||||||
|
if (!this.isReady) return;
|
||||||
await this.applyBatchChange();
|
await this.applyBatchChange();
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return;
|
return;
|
||||||
@@ -768,100 +897,8 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
await this.showIfConflicted(file);
|
await this.showIfConflicted(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
watchVaultCreate(file: TFile, ...args: any[]) {
|
|
||||||
if (!this.isTargetFile(file)) return;
|
|
||||||
if (this.settings.suspendFileWatching) return;
|
|
||||||
if (recentlyTouched(file)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.watchVaultChangeAsync(file, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
watchVaultChange(file: TAbstractFile, ...args: any[]) {
|
|
||||||
if (!this.isTargetFile(file)) return;
|
|
||||||
if (!(file instanceof TFile)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (recentlyTouched(file)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.settings.suspendFileWatching) return;
|
|
||||||
|
|
||||||
// If batchSave is enabled, queue all changes and do nothing.
|
|
||||||
if (this.settings.batchSave) {
|
|
||||||
~(async () => {
|
|
||||||
const meta = await this.localDatabase.getDBEntryMeta(file.path);
|
|
||||||
if (meta != false) {
|
|
||||||
const localMtime = ~~(file.stat.mtime / 1000);
|
|
||||||
const docMtime = ~~(meta.mtime / 1000);
|
|
||||||
if (localMtime !== docMtime) {
|
|
||||||
// Perhaps we have to modify (to using newer doc), but we don't be sure to every device's clock is adjusted.
|
|
||||||
this.batchFileChange = Array.from(new Set([...this.batchFileChange, file.path]));
|
|
||||||
this.refreshStatusText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.watchVaultChangeAsync(file, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
async applyBatchChange() {
|
async applyBatchChange() {
|
||||||
if (!this.settings.batchSave || this.batchFileChange.length == 0) {
|
await this.procFileEvent(true);
|
||||||
return;
|
|
||||||
}
|
|
||||||
return await runWithLock("batchSave", false, async () => {
|
|
||||||
const batchItems = JSON.parse(JSON.stringify(this.batchFileChange)) as string[];
|
|
||||||
this.batchFileChange = [];
|
|
||||||
const semaphore = Semaphore(3);
|
|
||||||
|
|
||||||
const batchProcesses = batchItems.map(e => (async (e) => {
|
|
||||||
const releaser = await semaphore.acquire(1, "batch");
|
|
||||||
try {
|
|
||||||
const f = this.app.vault.getAbstractFileByPath(normalizePath(e));
|
|
||||||
if (f && f instanceof TFile) {
|
|
||||||
await this.updateIntoDB(f);
|
|
||||||
Logger(`Batch save:${e}`);
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
|
||||||
Logger(`Batch save error:${e}`, LOG_LEVEL.NOTICE);
|
|
||||||
Logger(ex, LOG_LEVEL.VERBOSE);
|
|
||||||
} finally {
|
|
||||||
releaser();
|
|
||||||
}
|
|
||||||
})(e))
|
|
||||||
await Promise.all(batchProcesses);
|
|
||||||
|
|
||||||
this.refreshStatusText();
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
batchFileChange: string[] = [];
|
|
||||||
|
|
||||||
async watchVaultChangeAsync(file: TFile, ...args: any[]) {
|
|
||||||
if (file instanceof TFile) {
|
|
||||||
if (recentlyTouched(file)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.updateIntoDB(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watchVaultDelete(file: TAbstractFile) {
|
|
||||||
if (!this.isTargetFile(file)) return;
|
|
||||||
// When save is delayed, it should be cancelled.
|
|
||||||
this.batchFileChange = this.batchFileChange.filter((e) => e != file.path);
|
|
||||||
if (this.settings.suspendFileWatching) return;
|
|
||||||
this.watchVaultDeleteAsync(file).then(() => { });
|
|
||||||
}
|
|
||||||
|
|
||||||
async watchVaultDeleteAsync(file: TAbstractFile) {
|
|
||||||
if (file instanceof TFile) {
|
|
||||||
await this.deleteFromDB(file);
|
|
||||||
} else if (file instanceof TFolder) {
|
|
||||||
await this.deleteFolderOnDB(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GetAllFilesRecursively(file: TAbstractFile): TFile[] {
|
GetAllFilesRecursively(file: TAbstractFile): TFile[] {
|
||||||
@@ -879,12 +916,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watchVaultRename(file: TAbstractFile, oldFile: any) {
|
|
||||||
if (!this.isTargetFile(file)) return;
|
|
||||||
if (this.settings.suspendFileWatching) return;
|
|
||||||
this.watchVaultRenameAsync(file, oldFile).then(() => { });
|
|
||||||
}
|
|
||||||
|
|
||||||
getFilePath(file: TAbstractFile): string {
|
getFilePath(file: TAbstractFile): string {
|
||||||
if (file instanceof TFolder) {
|
if (file instanceof TFolder) {
|
||||||
if (file.isRoot()) return "";
|
if (file.isRoot()) return "";
|
||||||
@@ -897,7 +928,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
return this.getFilePath(file.parent) + "/" + file.name;
|
return this.getFilePath(file.parent) + "/" + file.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
async watchVaultRenameAsync(file: TAbstractFile, oldFile: any) {
|
async watchVaultRenameAsync(file: TAbstractFile, oldFile: any, cache?: CacheData) {
|
||||||
Logger(`${oldFile} renamed to ${file.path}`, LOG_LEVEL.VERBOSE);
|
Logger(`${oldFile} renamed to ${file.path}`, LOG_LEVEL.VERBOSE);
|
||||||
try {
|
try {
|
||||||
await this.applyBatchChange();
|
await this.applyBatchChange();
|
||||||
@@ -924,7 +955,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
} else if (file instanceof TFile) {
|
} else if (file instanceof TFile) {
|
||||||
try {
|
try {
|
||||||
Logger(`file save ${file.path} into db`);
|
Logger(`file save ${file.path} into db`);
|
||||||
await this.updateIntoDB(file);
|
await this.updateIntoDB(file, false, cache);
|
||||||
Logger(`deleted ${oldFile} from db`);
|
Logger(`deleted ${oldFile} from db`);
|
||||||
await this.deleteFromDBbyPath(oldFile);
|
await this.deleteFromDBbyPath(oldFile);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
@@ -1046,7 +1077,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
ctime: doc.ctime,
|
ctime: doc.ctime,
|
||||||
mtime: doc.mtime,
|
mtime: doc.mtime,
|
||||||
});
|
});
|
||||||
this.batchFileChange = this.batchFileChange.filter((e) => e != newFile.path);
|
// this.batchFileChange = this.batchFileChange.filter((e) => e != newFile.path);
|
||||||
Logger(msg + path);
|
Logger(msg + path);
|
||||||
touch(newFile);
|
touch(newFile);
|
||||||
this.app.vault.trigger("create", newFile);
|
this.app.vault.trigger("create", newFile);
|
||||||
@@ -1066,7 +1097,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
ctime: doc.ctime,
|
ctime: doc.ctime,
|
||||||
mtime: doc.mtime,
|
mtime: doc.mtime,
|
||||||
});
|
});
|
||||||
this.batchFileChange = this.batchFileChange.filter((e) => e != newFile.path);
|
// this.batchFileChange = this.batchFileChange.filter((e) => e != newFile.path);
|
||||||
Logger(msg + path);
|
Logger(msg + path);
|
||||||
touch(newFile);
|
touch(newFile);
|
||||||
this.app.vault.trigger("create", newFile);
|
this.app.vault.trigger("create", newFile);
|
||||||
@@ -1134,7 +1165,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
await this.ensureDirectory(path);
|
await this.ensureDirectory(path);
|
||||||
try {
|
try {
|
||||||
await this.app.vault.modifyBinary(file, bin, { ctime: doc.ctime, mtime: doc.mtime });
|
await this.app.vault.modifyBinary(file, bin, { ctime: doc.ctime, mtime: doc.mtime });
|
||||||
this.batchFileChange = this.batchFileChange.filter((e) => e != file.path);
|
// this.batchFileChange = this.batchFileChange.filter((e) => e != file.path);
|
||||||
Logger(msg + path);
|
Logger(msg + path);
|
||||||
const xf = this.app.vault.getAbstractFileByPath(file.path) as TFile;
|
const xf = this.app.vault.getAbstractFileByPath(file.path) as TFile;
|
||||||
touch(xf);
|
touch(xf);
|
||||||
@@ -1152,7 +1183,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
try {
|
try {
|
||||||
await this.app.vault.modify(file, doc.data, { ctime: doc.ctime, mtime: doc.mtime });
|
await this.app.vault.modify(file, doc.data, { ctime: doc.ctime, mtime: doc.mtime });
|
||||||
Logger(msg + path);
|
Logger(msg + path);
|
||||||
this.batchFileChange = this.batchFileChange.filter((e) => e != file.path);
|
// this.batchFileChange = this.batchFileChange.filter((e) => e != file.path);
|
||||||
const xf = this.app.vault.getAbstractFileByPath(file.path) as TFile;
|
const xf = this.app.vault.getAbstractFileByPath(file.path) as TFile;
|
||||||
touch(xf);
|
touch(xf);
|
||||||
this.app.vault.trigger("modify", xf);
|
this.app.vault.trigger("modify", xf);
|
||||||
@@ -1508,7 +1539,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
this.statusBar.title = this.localDatabase.syncStatus;
|
this.statusBar.title = this.localDatabase.syncStatus;
|
||||||
let waiting = "";
|
let waiting = "";
|
||||||
if (this.settings.batchSave) {
|
if (this.settings.batchSave) {
|
||||||
waiting = " " + this.batchFileChange.map((e) => "🛫").join("");
|
waiting = " " + this.watchedFileEventQueue.map((e) => "🛫").join("");
|
||||||
waiting = waiting.replace(/(🛫){10}/g, "🚀");
|
waiting = waiting.replace(/(🛫){10}/g, "🚀");
|
||||||
}
|
}
|
||||||
let queued = "";
|
let queued = "";
|
||||||
@@ -1581,17 +1612,23 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async initializeDatabase(showingNotice?: boolean) {
|
async initializeDatabase(showingNotice?: boolean) {
|
||||||
|
this.isReady = false;
|
||||||
if (await this.openDatabase()) {
|
if (await this.openDatabase()) {
|
||||||
if (this.localDatabase.isReady) {
|
if (this.localDatabase.isReady) {
|
||||||
await this.syncAllFiles(showingNotice);
|
await this.syncAllFiles(showingNotice);
|
||||||
}
|
}
|
||||||
|
this.isReady = true;
|
||||||
|
// run queued event once.
|
||||||
|
await this.procFileEvent(true);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
this.isReady = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async replicateAllToServer(showingNotice?: boolean) {
|
async replicateAllToServer(showingNotice?: boolean) {
|
||||||
|
if (!this.isReady) return false;
|
||||||
if (this.settings.autoSweepPlugins) {
|
if (this.settings.autoSweepPlugins) {
|
||||||
await this.sweepPlugin(showingNotice);
|
await this.sweepPlugin(showingNotice);
|
||||||
}
|
}
|
||||||
@@ -1754,23 +1791,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async renameFolder(folder: TFolder, oldFile: any) {
|
|
||||||
for (const v of folder.children) {
|
|
||||||
const entry = v as TFile & TFolder;
|
|
||||||
if (entry.children) {
|
|
||||||
await this.deleteFolderOnDB(entry);
|
|
||||||
if (this.settings.trashInsteadDelete) {
|
|
||||||
await this.app.vault.trash(entry, false);
|
|
||||||
} else {
|
|
||||||
await this.app.vault.delete(entry);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await this.deleteFromDB(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --> conflict resolving
|
// --> conflict resolving
|
||||||
async getConflictedDoc(path: string, rev: string): Promise<false | diff_result_leaf> {
|
async getConflictedDoc(path: string, rev: string): Promise<false | diff_result_leaf> {
|
||||||
try {
|
try {
|
||||||
@@ -2027,13 +2047,14 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateIntoDB(file: TFile, initialScan?: boolean) {
|
async updateIntoDB(file: TFile, initialScan?: boolean, cache?: CacheData) {
|
||||||
if (!this.isTargetFile(file)) return;
|
if (!this.isTargetFile(file)) return;
|
||||||
if (shouldBeIgnored(file.path)) {
|
if (shouldBeIgnored(file.path)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let content = "";
|
let content = "";
|
||||||
let datatype: "plain" | "newnote" = "newnote";
|
let datatype: "plain" | "newnote" = "newnote";
|
||||||
|
if (!cache) {
|
||||||
if (!isPlainText(file.name)) {
|
if (!isPlainText(file.name)) {
|
||||||
const contentBin = await this.app.vault.readBinary(file);
|
const contentBin = await this.app.vault.readBinary(file);
|
||||||
content = await arrayBufferToBase64(contentBin);
|
content = await arrayBufferToBase64(contentBin);
|
||||||
@@ -2042,6 +2063,15 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
|
|||||||
content = await this.app.vault.read(file);
|
content = await this.app.vault.read(file);
|
||||||
datatype = "plain";
|
datatype = "plain";
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (cache instanceof ArrayBuffer) {
|
||||||
|
content = await arrayBufferToBase64(cache);
|
||||||
|
datatype = "newnote"
|
||||||
|
} else {
|
||||||
|
content = cache;
|
||||||
|
datatype = "plain";
|
||||||
|
}
|
||||||
|
}
|
||||||
const fullPath = path2id(file.path);
|
const fullPath = path2id(file.path);
|
||||||
const d: LoadedEntry = {
|
const d: LoadedEntry = {
|
||||||
_id: fullPath,
|
_id: fullPath,
|
||||||
|
|||||||
Reference in New Issue
Block a user