mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-02-03 02:47:12 +00:00
Fixed
- Vault History can show the correct information of match-or-not for each file and database even if it is a binary file.
- `Sync settings via markdown` is now hidden during the setup wizard.
- Verify and Fix will ignore the hidden files if the hidden file sync is disabled.
New feature
- Now we can fetch the tweaks from the remote database while the setting dialogue and wizard are processing.
Improved
- More things are moved to the modules.
- Includes the Main codebase. Now `main.ts` is almost stub.
- EventHub is now more robust and typesafe.
This commit is contained in:
@@ -543,7 +543,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
||||
|
||||
|
||||
filenameToUnifiedKey(path: string, termOverRide?: string) {
|
||||
const term = termOverRide || this.plugin.deviceAndVaultName;
|
||||
const term = termOverRide || this.plugin.$$getDeviceAndVaultName();
|
||||
const category = this.getFileCategory(path);
|
||||
const name = (category == "CONFIG" || category == "SNIPPET") ?
|
||||
(path.split("/").slice(-1)[0]) :
|
||||
@@ -554,7 +554,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
||||
}
|
||||
|
||||
filenameWithUnifiedKey(path: string, termOverRide?: string) {
|
||||
const term = termOverRide || this.plugin.deviceAndVaultName;
|
||||
const term = termOverRide || this.plugin.$$getDeviceAndVaultName();
|
||||
const category = this.getFileCategory(path);
|
||||
const name = (category == "CONFIG" || category == "SNIPPET") ?
|
||||
(path.split("/").slice(-1)[0]) : path.split("/").slice(-2)[0];
|
||||
@@ -563,7 +563,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
||||
}
|
||||
|
||||
unifiedKeyPrefixOfTerminal(termOverRide?: string) {
|
||||
const term = termOverRide || this.plugin.deviceAndVaultName;
|
||||
const term = termOverRide || this.plugin.$$getDeviceAndVaultName();
|
||||
return `${ICXHeader}${term}/` as FilePathWithPrefix;
|
||||
}
|
||||
|
||||
@@ -870,7 +870,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
||||
await this.plugin.storageAccess.ensureDir(path);
|
||||
// If the content has applied, modified time will be updated to the current time.
|
||||
await this.plugin.storageAccess.writeHiddenFileAuto(path, content);
|
||||
await this.storeCustomisationFileV2(path, this.plugin.deviceAndVaultName);
|
||||
await this.storeCustomisationFileV2(path, this.plugin.$$getDeviceAndVaultName());
|
||||
|
||||
} else {
|
||||
const files = data.files;
|
||||
@@ -914,7 +914,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
||||
await this.plugin.storageAccess.writeHiddenFileAuto(path, content, stat);
|
||||
}
|
||||
this._log(`Applied ${f.filename} of ${data.displayName || data.name}..`);
|
||||
await this.storeCustomisationFileV2(path, this.plugin.deviceAndVaultName);
|
||||
await this.storeCustomisationFileV2(path, this.plugin.$$getDeviceAndVaultName());
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
@@ -1189,7 +1189,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
||||
})
|
||||
}
|
||||
async storeCustomizationFiles(path: FilePath, termOverRide?: string) {
|
||||
const term = termOverRide || this.plugin.deviceAndVaultName;
|
||||
const term = termOverRide || this.plugin.$$getDeviceAndVaultName();
|
||||
if (term == "") {
|
||||
this._log("We have to configure the device name", LOG_LEVEL_NOTICE);
|
||||
return;
|
||||
@@ -1362,7 +1362,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
||||
await shareRunningResult("scanAllConfigFiles", async () => {
|
||||
const logLevel = showMessage ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO;
|
||||
this._log("Scanning customizing files.", logLevel, "scan-all-config");
|
||||
const term = this.plugin.deviceAndVaultName;
|
||||
const term = this.plugin.$$getDeviceAndVaultName();
|
||||
if (term == "") {
|
||||
this._log("We have to configure the device name", LOG_LEVEL_NOTICE);
|
||||
return;
|
||||
@@ -1505,7 +1505,10 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
||||
choices.push(CHOICE_DISABLE);
|
||||
choices.push(CHOICE_DISMISS);
|
||||
|
||||
const ret = await this.plugin.confirm.confirmWithMessage("Customisation sync", message, choices, CHOICE_DISMISS, 40);
|
||||
const ret = await this.plugin.confirm.askSelectStringDialogue(message, choices, {
|
||||
defaultAction: CHOICE_DISMISS, timeout: 40,
|
||||
title: "Customisation sync"
|
||||
});
|
||||
if (ret == CHOICE_CUSTOMIZE) {
|
||||
await this.configureHiddenFileSync("CUSTOMIZE");
|
||||
} else if (ret == CHOICE_DISABLE) {
|
||||
@@ -1544,7 +1547,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
||||
}
|
||||
|
||||
if (mode == "CUSTOMIZE") {
|
||||
if (!this.plugin.deviceAndVaultName) {
|
||||
if (!this.plugin.$$getDeviceAndVaultName()) {
|
||||
let name = await this.plugin.confirm.askString("Device name", "Please set this device name", `desktop`);
|
||||
if (!name) {
|
||||
if (Platform.isAndroidApp) {
|
||||
@@ -1568,7 +1571,7 @@ export class ConfigSync extends LiveSyncCommands implements IObsidianModule {
|
||||
}
|
||||
name = name + Math.random().toString(36).slice(-4);
|
||||
}
|
||||
this.plugin.deviceAndVaultName = name;
|
||||
this.plugin.$$setDeviceAndVaultName(name);
|
||||
}
|
||||
this.plugin.settings.usePluginSync = true;
|
||||
this.plugin.settings.useAdvancedMode = true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { ConfigSync, PluginDataExDisplayV2, type IPluginDataExDisplay } from "./CmdConfigSync.ts";
|
||||
import { ConfigSync, PluginDataExDisplayV2, type IPluginDataExDisplay, type PluginDataExFile } from "./CmdConfigSync.ts";
|
||||
import { Logger } from "../../lib/src/common/logger";
|
||||
import { type FilePath, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "../../lib/src/common/types";
|
||||
import { getDocData, timeDeltaToHumanReadable, unique } from "../../lib/src/common/utils";
|
||||
@@ -287,9 +287,17 @@
|
||||
menu.addItem((item) => item.setTitle("Compare file").setIsLabel(true));
|
||||
menu.addSeparator();
|
||||
const files = unique(local.files.map((e) => e.filename).concat(selectedItem.files.map((e) => e.filename)));
|
||||
const convDate = (dt: PluginDataExFile | undefined) => {
|
||||
if (!dt) return "(Missing)";
|
||||
const d = new Date(dt.mtime);
|
||||
return d.toLocaleString();
|
||||
};
|
||||
for (const filename of files) {
|
||||
menu.addItem((item) => {
|
||||
item.setTitle(filename).onClick((e) => compareItems(local, selectedItem, filename));
|
||||
const localFile = local.files.find((e) => e.filename == filename);
|
||||
const remoteFile = selectedItem.files.find((e) => e.filename == filename);
|
||||
const title = `${filename} (${convDate(localFile)} <--> ${convDate(remoteFile)})`;
|
||||
item.setTitle(title).onClick((e) => compareItems(local, selectedItem, filename));
|
||||
});
|
||||
}
|
||||
menu.showAtMouseEvent(evt);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
export let plugin: ObsidianLiveSyncPlugin;
|
||||
|
||||
$: hideNotApplicable = false;
|
||||
$: thisTerm = plugin.deviceAndVaultName;
|
||||
$: thisTerm = plugin.$$getDeviceAndVaultName();
|
||||
|
||||
const addOn = plugin.getAddOn(ConfigSync.name) as ConfigSync;
|
||||
if (!addOn) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { normalizePath, type PluginManifest, type ListedFiles } from "../../deps.ts";
|
||||
import { type EntryDoc, type LoadedEntry, type InternalFileEntry, type FilePathWithPrefix, type FilePath, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, MODE_SELECTIVE, MODE_PAUSED, type SavingEntry, type DocumentID, type UXStat, MODE_AUTOMATIC } from "../../lib/src/common/types.ts";
|
||||
import { type EntryDoc, type LoadedEntry, type InternalFileEntry, type FilePathWithPrefix, type FilePath, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, MODE_SELECTIVE, MODE_PAUSED, type SavingEntry, type DocumentID, type UXStat, MODE_AUTOMATIC, type FilePathWithPrefixLC } from "../../lib/src/common/types.ts";
|
||||
import { type InternalFileInfo, ICHeader, ICHeaderEnd } from "../../common/types.ts";
|
||||
import { readAsBlob, isDocContentSame, sendSignal, readContent, createBlob, fireAndForget } from "../../lib/src/common/utils.ts";
|
||||
import { BASE_IS_NEW, compareMTime, EVEN, getPath, isInternalMetadata, isMarkedAsSameChanges, markChangesAreSame, PeriodicProcessor, TARGET_IS_NEW } from "../../common/utils.ts";
|
||||
@@ -10,6 +10,7 @@ import { addPrefix, stripAllPrefixes } from "../../lib/src/string_and_binary/pat
|
||||
import { QueueProcessor } from "../../lib/src/concurrency/processor.ts";
|
||||
import { hiddenFilesEventCount, hiddenFilesProcessingCount } from "../../lib/src/mock_and_interop/stores.ts";
|
||||
import type { IObsidianModule } from "../../modules/AbstractObsidianModule.ts";
|
||||
import { EVENT_SETTING_SAVED, eventHub } from "../../common/events.ts";
|
||||
|
||||
export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule {
|
||||
|
||||
@@ -36,8 +37,13 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
||||
void this.syncInternalFilesAndDatabase("safe", true);
|
||||
},
|
||||
});
|
||||
eventHub.onEvent(EVENT_SETTING_SAVED, () => {
|
||||
this.updateSettingCache();
|
||||
});
|
||||
|
||||
}
|
||||
async $everyOnDatabaseInitialized(showNotice: boolean) {
|
||||
this.knownChanges = await this.plugin.kvDB.get("knownChanges") ?? {};
|
||||
if (this._isThisModuleEnabled()) {
|
||||
try {
|
||||
this._log("Synchronizing hidden files...");
|
||||
@@ -58,12 +64,26 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
||||
}
|
||||
|
||||
$everyOnloadAfterLoadSettings(): Promise<boolean> {
|
||||
this.updateSettingCache();
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
updateSettingCache() {
|
||||
const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns
|
||||
.replace(/\n| /g, "")
|
||||
.split(",").filter(e => e).map(e => new RegExp(e, "i"));
|
||||
this.ignorePatterns = ignorePatterns;
|
||||
return Promise.resolve(true);
|
||||
this.shouldSkipFile = [] as FilePathWithPrefixLC[];
|
||||
// Exclude files handled by customization sync
|
||||
const configDir = normalizePath(this.app.vault.configDir);
|
||||
const shouldSKip = !this.settings.usePluginSync ? [] :
|
||||
Object.values(this.settings.pluginSyncExtendedSetting).
|
||||
filter(e => e.mode == MODE_SELECTIVE || e.mode == MODE_PAUSED).
|
||||
map(e => e.files).flat().map(e => `${configDir}/${e}`.toLowerCase());
|
||||
this.shouldSkipFile = shouldSKip as FilePathWithPrefixLC[];
|
||||
this._log(`Hidden file will skip ${this.shouldSkipFile.length} files`, LOG_LEVEL_INFO);
|
||||
|
||||
}
|
||||
shouldSkipFile = [] as FilePathWithPrefixLC[];
|
||||
|
||||
async $everyOnResumeProcess(): Promise<boolean> {
|
||||
this.periodicInternalFileScanProcessor?.disable();
|
||||
@@ -80,7 +100,7 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
||||
this.periodicInternalFileScanProcessor?.disable();
|
||||
if (this._isMainSuspended())
|
||||
return Promise.resolve(true);
|
||||
if (!this.plugin.isReady)
|
||||
if (!this.plugin.$$isReady())
|
||||
return Promise.resolve(true);
|
||||
this.periodicInternalFileScanProcessor.enable(this._isThisModuleEnabled() && this.settings.syncInternalFilesInterval ? (this.settings.syncInternalFilesInterval * 1000) : 0);
|
||||
const ignorePatterns = this.settings.syncInternalFilesIgnorePatterns
|
||||
@@ -110,13 +130,7 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
||||
if (this._isMainSuspended()) return false;
|
||||
if (!this._isThisModuleEnabled()) return false;
|
||||
|
||||
// Exclude files handled by customization sync
|
||||
const configDir = normalizePath(this.app.vault.configDir);
|
||||
const synchronisedInConfigSync = !this.settings.usePluginSync ? [] :
|
||||
Object.values(this.settings.pluginSyncExtendedSetting).
|
||||
filter(e => e.mode == MODE_SELECTIVE || e.mode == MODE_PAUSED).
|
||||
map(e => e.files).flat().map(e => `${configDir}/${e}`.toLowerCase());
|
||||
if (synchronisedInConfigSync.some(e => e.startsWith(path.toLowerCase()))) {
|
||||
if (this.shouldSkipFile.some(e => e.startsWith(path.toLowerCase()))) {
|
||||
this._log(`Hidden file skipped: ${path} is synchronized in customization sync.`, LOG_LEVEL_VERBOSE);
|
||||
return false;
|
||||
}
|
||||
@@ -504,7 +518,7 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
||||
|
||||
// If something changes left, notify for reloading Obsidian.
|
||||
if (updatedCount != 0) {
|
||||
if (!this.plugin.isReloadingScheduled) {
|
||||
if (!this.plugin.$$isReloadingScheduled()) {
|
||||
this.plugin.confirm.askInPopup(`updated-any-hidden`, `Hidden files have been synchronised, Press {HERE} to schedule a reload of Obsidian, or press elsewhere to dismiss this message.`, (anchor) => {
|
||||
anchor.text = "HERE";
|
||||
anchor.addEventListener("click", () => {
|
||||
@@ -676,12 +690,16 @@ export class HiddenFileSync extends LiveSyncCommands implements IObsidianModule
|
||||
this._log(`STORAGE <x- DB: ${displayFileName}: deleted (hidden) Deleted on DB, but the file is already not found on storage.`);
|
||||
} else {
|
||||
this._log(`STORAGE <x- DB: ${displayFileName}: deleted (hidden).`);
|
||||
await this.plugin.storageAccess.removeHidden(storageFilePath);
|
||||
try {
|
||||
await this.plugin.storageAccess.triggerHiddenFile(storageFilePath);
|
||||
} catch (ex) {
|
||||
this._log("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL_VERBOSE);
|
||||
this._log(ex, LOG_LEVEL_VERBOSE);
|
||||
if (await this.plugin.storageAccess.removeHidden(storageFilePath)) {
|
||||
try {
|
||||
await this.plugin.storageAccess.triggerHiddenFile(storageFilePath);
|
||||
} catch (ex) {
|
||||
this._log("Failed to call internal API(reconcileInternalFile)", LOG_LEVEL_VERBOSE);
|
||||
this._log(ex, LOG_LEVEL_VERBOSE);
|
||||
}
|
||||
} else {
|
||||
this._log(`STORAGE <x- DB: ${storageFilePath}: deleted (hidden) Failed`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -33,13 +33,13 @@ export abstract class LiveSyncCommands {
|
||||
abstract onload(): void | Promise<void>;
|
||||
|
||||
_isMainReady() {
|
||||
return this.plugin._isMainReady();
|
||||
return this.plugin.$$isReady();
|
||||
}
|
||||
_isMainSuspended() {
|
||||
return this.plugin._isMainSuspended();
|
||||
return this.plugin.$$isSuspended();
|
||||
}
|
||||
_isDatabaseReady() {
|
||||
return this.plugin._isDatabaseReady();
|
||||
return this.plugin.$$isDatabaseReady();
|
||||
}
|
||||
|
||||
_log = (msg: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key?: string) => {
|
||||
@@ -49,4 +49,5 @@ export abstract class LiveSyncCommands {
|
||||
// console.log(msg);
|
||||
Logger(msg, level, key);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user