mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-03-10 20:08:48 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
630889680e | ||
|
|
e46714e0f9 | ||
|
|
86d5582f37 | ||
|
|
697ee1855b |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-livesync",
|
||||
"name": "Self-hosted LiveSync",
|
||||
"version": "0.23.18",
|
||||
"version": "0.23.20",
|
||||
"minAppVersion": "0.9.12",
|
||||
"description": "Community implementation of self-hosted livesync. Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
||||
"author": "vorotamoroz",
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.23.18",
|
||||
"version": "0.23.20",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.23.18",
|
||||
"version": "0.23.20",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.614.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.23.18",
|
||||
"version": "0.23.20",
|
||||
"description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
||||
"main": "main.js",
|
||||
"type": "module",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { writable } from 'svelte/store';
|
||||
import { Notice, type PluginManifest, parseYaml, normalizePath, type ListedFiles, diff_match_patch } from "../deps.ts";
|
||||
|
||||
import type { EntryDoc, LoadedEntry, InternalFileEntry, FilePathWithPrefix, FilePath, AnyEntry, SavingEntry, diff_result } from "../lib/src/common/types.ts";
|
||||
import { CANCELLED, LEAVE_TO_SUBSEQUENT, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, MODE_SELECTIVE, MODE_SHINY } from "../lib/src/common/types.ts";
|
||||
import { CANCELLED, LEAVE_TO_SUBSEQUENT, LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, MODE_SELECTIVE, MODE_SHINY } from "../lib/src/common/types.ts";
|
||||
import { ICXHeader, PERIODIC_PLUGIN_SWEEP, } from "../common/types.ts";
|
||||
import { createBlob, createSavingEntryFromLoadedEntry, createTextBlob, delay, fireAndForget, getDocData, getDocDataAsArray, isDocContentSame, isLoadedEntry, isObjectDifferent } from "../lib/src/common/utils.ts";
|
||||
import { Logger } from "../lib/src/common/logger.ts";
|
||||
@@ -11,7 +11,7 @@ import { arrayBufferToBase64, decodeBinary, readString } from 'src/lib/src/strin
|
||||
import { serialized, shareRunningResult } from "../lib/src/concurrency/lock.ts";
|
||||
import { LiveSyncCommands } from "./LiveSyncCommands.ts";
|
||||
import { stripAllPrefixes } from "../lib/src/string_and_binary/path.ts";
|
||||
import { PeriodicProcessor, disposeMemoObject, memoIfNotExist, memoObject, retrieveMemoObject, scheduleTask } from "../common/utils.ts";
|
||||
import { EVEN, PeriodicProcessor, disposeMemoObject, isMarkedAsSameChanges, markChangesAreSame, memoIfNotExist, memoObject, retrieveMemoObject, scheduleTask } from "../common/utils.ts";
|
||||
import { PluginDialogModal } from "../common/dialogs.ts";
|
||||
import { JsonResolveModal } from "../ui/JsonResolveModal.ts";
|
||||
import { QueueProcessor } from '../lib/src/concurrency/processor.ts';
|
||||
@@ -272,8 +272,10 @@ export class PluginDataExDisplayV2 {
|
||||
this.confKey = `${categoryToFolder(this.category, this.term)}${this.name}`;
|
||||
this.applyLoadedManifest();
|
||||
}
|
||||
setFile(file: LoadedEntryPluginDataExFile) {
|
||||
if (this.files.find(e => e.filename == file.filename)) {
|
||||
async setFile(file: LoadedEntryPluginDataExFile) {
|
||||
const old = this.files.find(e => e.filename == file.filename);
|
||||
if (old) {
|
||||
if (old.mtime == file.mtime && await isDocContentSame(old.data, file.data)) return;
|
||||
this.files = this.files.filter(e => e.filename != file.filename);
|
||||
}
|
||||
this.files.push(file);
|
||||
@@ -319,6 +321,7 @@ export type PluginDataEx = {
|
||||
version?: string,
|
||||
mtime: number,
|
||||
};
|
||||
|
||||
export class ConfigSync extends LiveSyncCommands {
|
||||
constructor(plugin: ObsidianLiveSyncPlugin) {
|
||||
super(plugin);
|
||||
@@ -637,7 +640,7 @@ export class ConfigSync extends LiveSyncCommands {
|
||||
if (!entry) return;
|
||||
const file = await this.createPluginDataExFileV2(unifiedFilenameWithKey);
|
||||
if (file) {
|
||||
entry.setFile(file);
|
||||
await entry.setFile(file);
|
||||
} else {
|
||||
entry.deleteFile(unifiedFilenameWithKey);
|
||||
if (entry.files.length == 0) {
|
||||
@@ -841,22 +844,46 @@ export class ConfigSync extends LiveSyncCommands {
|
||||
Logger(`Applying ${filename} of ${data.displayName || data.name}..`);
|
||||
const path = `${baseDir}/${filename}` as FilePath;
|
||||
await this.vaultAccess.ensureDirectory(path);
|
||||
// If the content has applied, modified time will be updated to the current time.
|
||||
await this.vaultAccess.adapterWrite(path, content);
|
||||
await this.storeCustomisationFileV2(path, this.plugin.deviceAndVaultName);
|
||||
|
||||
} else {
|
||||
const files = data.files;
|
||||
for (const f of files) {
|
||||
// If files have applied, modified time will be updated to the current time.
|
||||
const stat = { mtime: f.mtime, ctime: f.ctime };
|
||||
const path = `${baseDir}/${f.filename}` as FilePath;
|
||||
Logger(`Applying ${f.filename} of ${data.displayName || data.name}..`);
|
||||
// const contentEach = createBlob(f.data);
|
||||
this.vaultAccess.ensureDirectory(path);
|
||||
|
||||
if (f.datatype == "newnote") {
|
||||
let oldData;
|
||||
try {
|
||||
oldData = await this.vaultAccess.adapterReadBinary(path);
|
||||
} catch (ex) {
|
||||
oldData = new ArrayBuffer(0);
|
||||
}
|
||||
const content = base64ToArrayBuffer(f.data);
|
||||
await this.vaultAccess.adapterWrite(path, content);
|
||||
if (await isDocContentSame(oldData, content)) {
|
||||
Logger(`The file ${f.filename} is already up-to-date`, LOG_LEVEL_VERBOSE);
|
||||
continue;
|
||||
}
|
||||
await this.vaultAccess.adapterWrite(path, content, stat);
|
||||
} else {
|
||||
let oldData;
|
||||
try {
|
||||
oldData = await this.vaultAccess.adapterRead(path);
|
||||
} catch (ex) {
|
||||
oldData = "";
|
||||
}
|
||||
const content = getDocData(f.data);
|
||||
await this.vaultAccess.adapterWrite(path, content);
|
||||
if (await isDocContentSame(oldData, content)) {
|
||||
Logger(`The file ${f.filename} is already up-to-date`, LOG_LEVEL_VERBOSE);
|
||||
continue;
|
||||
}
|
||||
await this.vaultAccess.adapterWrite(path, content, stat);
|
||||
}
|
||||
Logger(`Applied ${f.filename} of ${data.displayName || data.name}..`);
|
||||
await this.storeCustomisationFileV2(path, this.plugin.deviceAndVaultName);
|
||||
@@ -1063,7 +1090,7 @@ export class ConfigSync extends LiveSyncCommands {
|
||||
}
|
||||
|
||||
|
||||
async storeCustomisationFileV2(path: FilePath, term: string, saveRelatives = false) {
|
||||
async storeCustomisationFileV2(path: FilePath, term: string, force = false) {
|
||||
const vf = this.filenameWithUnifiedKey(path, term);
|
||||
return await serialized(`plugin-${vf}`, async () => {
|
||||
const prefixedFileName = vf;
|
||||
@@ -1095,8 +1122,21 @@ export class ConfigSync extends LiveSyncCommands {
|
||||
eden: {}
|
||||
};
|
||||
} else {
|
||||
if (old.mtime == mtime) {
|
||||
// Logger(`STORAGE --> DB:${prefixedFileName}: (config) Skipped (Same time)`, LOG_LEVEL_VERBOSE);
|
||||
if (isMarkedAsSameChanges(prefixedFileName, [old.mtime, mtime + 1]) == EVEN) {
|
||||
Logger(`STORAGE --> DB:${prefixedFileName}: (config) Skipped (Already checked the same)`, LOG_LEVEL_DEBUG);
|
||||
return;
|
||||
}
|
||||
const docXDoc = await this.localDatabase.getDBEntryFromMeta(old, {}, false, false);
|
||||
if (docXDoc == false) {
|
||||
throw "Could not load the document";
|
||||
}
|
||||
const dataSrc = getDocData(docXDoc.data);
|
||||
const dataStart = dataSrc.indexOf(DUMMY_END);
|
||||
const oldContent = dataSrc.substring(dataStart + DUMMY_END.length);
|
||||
const oldContentArray = base64ToArrayBuffer(oldContent);
|
||||
if (await isDocContentSame(oldContentArray, content)) {
|
||||
Logger(`STORAGE --> DB:${prefixedFileName}: (config) Skipped (the same content)`, LOG_LEVEL_VERBOSE);
|
||||
markChangesAreSame(prefixedFileName, old.mtime, mtime + 1);
|
||||
return true;
|
||||
}
|
||||
saveData =
|
||||
|
||||
@@ -663,10 +663,13 @@ And if your actual storage size exceeds the threshold after the setup, you may w
|
||||
const ret = await confirmWithMessage(this, "Remote storage size threshold", message, [ANSWER_0, ANSWER_800, ANSWER_2000], ANSWER_800, 40);
|
||||
if (ret == ANSWER_0) {
|
||||
this.settings.notifyThresholdOfRemoteStorageSize = 0;
|
||||
await this.saveSettings();
|
||||
} else if (ret == ANSWER_800) {
|
||||
this.settings.notifyThresholdOfRemoteStorageSize = 800;
|
||||
await this.saveSettings();
|
||||
} else {
|
||||
this.settings.notifyThresholdOfRemoteStorageSize = 2000;
|
||||
await this.saveSettings();
|
||||
}
|
||||
}
|
||||
if (this.settings.notifyThresholdOfRemoteStorageSize > 0) {
|
||||
@@ -686,7 +689,8 @@ If you have enough space on the remote storage, you can enlarge the threshold. O
|
||||
|
||||
However, **Please make sure that all devices have been synchronised**. \n
|
||||
\n`;
|
||||
const ANSWER_ENLARGE_LIMIT = "Enlarge the limit";
|
||||
const newMax = ~~(estimatedSize / 1024 / 1024) + 100;
|
||||
const ANSWER_ENLARGE_LIMIT = `Enlarge to ${newMax}MB`;
|
||||
const ANSWER_REBUILD = "Rebuild now";
|
||||
const ANSWER_IGNORE = "Dismiss";
|
||||
const ret = await confirmWithMessage(this, "Remote storage size exceeded", message, [ANSWER_ENLARGE_LIMIT, ANSWER_REBUILD, ANSWER_IGNORE,], ANSWER_IGNORE, 20);
|
||||
@@ -708,7 +712,7 @@ However, **Please make sure that all devices have been synchronised**. \n
|
||||
// Dismiss or Close the dialog
|
||||
}
|
||||
|
||||
Logger(`Remote storage size: ${sizeToHumanReadable(estimatedSize)} exceeded ${sizeToHumanReadable(this.settings.notifyThresholdOfRemoteStorageSize)} `, LOG_LEVEL_INFO);
|
||||
Logger(`Remote storage size: ${sizeToHumanReadable(estimatedSize)} exceeded ${sizeToHumanReadable(this.settings.notifyThresholdOfRemoteStorageSize * 1024 * 1024)} `, LOG_LEVEL_INFO);
|
||||
} else {
|
||||
Logger(`Remote storage size: ${sizeToHumanReadable(estimatedSize)}`, LOG_LEVEL_INFO);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
canApply = true;
|
||||
} else {
|
||||
const dtDiff = (local?.mtime ?? 0) - (remote?.mtime ?? 0);
|
||||
const diff = timeDeltaToHumanReadable(Math.abs(dtDiff / 1000));
|
||||
const diff = timeDeltaToHumanReadable(Math.abs(dtDiff));
|
||||
if (dtDiff / 1000 < -10) {
|
||||
// freshness = "✓ Newer";
|
||||
freshness = `Newer (${diff})`;
|
||||
|
||||
30
updates.md
30
updates.md
@@ -18,6 +18,16 @@ I have a lot of respect for that plugin, even though it is sometimes treated as
|
||||
Hooray for open source, and generous licences, and the sharing of knowledge by experts.
|
||||
|
||||
#### Version history
|
||||
- 0.23.20:
|
||||
- Fixed:
|
||||
- Customisation Sync now checks the difference while storing or applying the configuration.
|
||||
- No longer storing the same configuration multiple times.
|
||||
- Time difference in the dialogue has been fixed.
|
||||
- Remote Storage Limit Notification dialogue has been fixed, now the chosen value is saved.
|
||||
- Improved:
|
||||
- The Enlarging button on the enlarging threshold dialogue now displays the new value.
|
||||
- 0.23.19:
|
||||
- Not released.
|
||||
- 0.23.18:
|
||||
- New feature:
|
||||
- Per-file-saved customization sync has been shipped.
|
||||
@@ -47,25 +57,5 @@ Hooray for open source, and generous licences, and the sharing of knowledge by e
|
||||
- We can get a notification about the storage usage of the remote database.
|
||||
- Default: We will be asked.
|
||||
- If the remote storage usage approaches the configured value, we will be asked whether we want to Rebuild or increase the limit.
|
||||
- 0.23.16:
|
||||
- Maintenance Update:
|
||||
- Library refining (Phase 1 - step 2). There are no significant changes on the user side.
|
||||
- Including the following fixes of potentially problems:
|
||||
- the problem which the path had been obfuscating twice has been resolved.
|
||||
- Note: Potential problems of the library; which has not happened in Self-hosted LiveSync for some reasons.
|
||||
- 0.23.15:
|
||||
- Maintenance Update:
|
||||
- Library refining (Phase 1). There are no significant changes on the user side.
|
||||
- 0.23.14:
|
||||
- Fixed:
|
||||
- No longer batch-saving ignores editor inputs.
|
||||
- The file-watching and serialisation processes have been changed to the one which is similar to previous implementations.
|
||||
- We can configure the settings (Especially about text-boxes) even if we have configured the device name.
|
||||
- Improved:
|
||||
- We can configure the delay of batch-saving.
|
||||
- Default: 5 seconds, the same as the previous hard-coded value. (Note: also, the previous behaviour was not correct).
|
||||
- Also, we can configure the limit of delaying batch-saving.
|
||||
- The performance of showing status indicators has been improved.
|
||||
|
||||
|
||||
Older notes is in [updates_old.md](https://github.com/vrtmrz/obsidian-livesync/blob/main/updates_old.md).
|
||||
@@ -18,6 +18,25 @@ I have a lot of respect for that plugin, even though it is sometimes treated as
|
||||
Hooray for open source, and generous licences, and the sharing of knowledge by experts.
|
||||
|
||||
#### Version history
|
||||
- 0.23.16:
|
||||
- Maintenance Update:
|
||||
- Library refining (Phase 1 - step 2). There are no significant changes on the user side.
|
||||
- Including the following fixes of potentially problems:
|
||||
- the problem which the path had been obfuscating twice has been resolved.
|
||||
- Note: Potential problems of the library; which has not happened in Self-hosted LiveSync for some reasons.
|
||||
- 0.23.15:
|
||||
- Maintenance Update:
|
||||
- Library refining (Phase 1). There are no significant changes on the user side.
|
||||
- 0.23.14:
|
||||
- Fixed:
|
||||
- No longer batch-saving ignores editor inputs.
|
||||
- The file-watching and serialisation processes have been changed to the one which is similar to previous implementations.
|
||||
- We can configure the settings (Especially about text-boxes) even if we have configured the device name.
|
||||
- Improved:
|
||||
- We can configure the delay of batch-saving.
|
||||
- Default: 5 seconds, the same as the previous hard-coded value. (Note: also, the previous behaviour was not correct).
|
||||
- Also, we can configure the limit of delaying batch-saving.
|
||||
- The performance of showing status indicators has been improved.
|
||||
- 0.23.13:
|
||||
- Fixed:
|
||||
- No longer files have been trimmed even delimiters have been continuous.
|
||||
|
||||
Reference in New Issue
Block a user