mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-21 14:51:34 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4202161e8 | ||
|
|
2a2b39009c | ||
|
|
bf3a6e7570 | ||
|
|
069b8513d1 | ||
|
|
128b1843df | ||
|
|
fd722b1fe5 | ||
|
|
0bf087dba0 | ||
|
|
3a4b59b998 | ||
|
|
8fc9d51c45 |
34
docs/adding_translations.md
Normal file
34
docs/adding_translations.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# How to add translations
|
||||||
|
|
||||||
|
## Getting ready
|
||||||
|
|
||||||
|
1. Clone this repository recursively.
|
||||||
|
```sh
|
||||||
|
git clone --recursive https://github.com/vrtmrz/obsidian-livesync
|
||||||
|
```
|
||||||
|
2. Make `ls-debug` folder under your vault's `.obsidian` folder (as like `.../dev/.obsidian/ls-debug`).
|
||||||
|
|
||||||
|
## Add translations for already defined terms
|
||||||
|
|
||||||
|
1. Install dependencies, and build the plug-in as dev. build.
|
||||||
|
```sh
|
||||||
|
cd obsidian-livesync
|
||||||
|
npm i -D
|
||||||
|
npm run buildDev
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Copy the `main.js` to `.obsidian/plugins/obsidian-livesync` folder of your vault, and run Obsidian-Self-hosted LiveSync.
|
||||||
|
3. You will get the `missing-translation-yyyy-mm-dd.jsonl`, please fill in new translations.
|
||||||
|
4. Build the plug-in again, and confirm that displayed things were expected.
|
||||||
|
5. Merge them into `rosetta.ts`, and make the PR to `https://github.com/vrtmrz/livesync-commonlib`.
|
||||||
|
|
||||||
|
## Make messages to be translated
|
||||||
|
|
||||||
|
1. Find the message that you want to be translated.
|
||||||
|
2. Change the literal to a tagged template literal using `$f`, like below.
|
||||||
|
```diff
|
||||||
|
- Logger("Could not determine passphrase to save data.json! You probably make the configuration sure again!", LOG_LEVEL_URGENT);
|
||||||
|
+ Logger($f`Could not determine passphrase to save data.json! You probably make the configuration sure again!`, LOG_LEVEL_URGENT);
|
||||||
|
```
|
||||||
|
3. Make the PR to `https://github.com/vrtmrz/obsidian-livesync`.
|
||||||
|
4. Follow the steps of "Add translations for already defined terms" to add the translations.
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
- [Why are the logs volatile and ephemeral?](#why-are-the-logs-volatile-and-ephemeral)
|
- [Why are the logs volatile and ephemeral?](#why-are-the-logs-volatile-and-ephemeral)
|
||||||
- [Some network logs are not written into the file.](#some-network-logs-are-not-written-into-the-file)
|
- [Some network logs are not written into the file.](#some-network-logs-are-not-written-into-the-file)
|
||||||
- [If a file were deleted or trimmed, the capacity of the database should be reduced, right?](#if-a-file-were-deleted-or-trimmed-the-capacity-of-the-database-should-be-reduced-right)
|
- [If a file were deleted or trimmed, the capacity of the database should be reduced, right?](#if-a-file-were-deleted-or-trimmed-the-capacity-of-the-database-should-be-reduced-right)
|
||||||
|
- [How can I use the DevTools?](#how-can-i-use-the-devtools)
|
||||||
|
- [Checking the network log](#checking-the-network-log)
|
||||||
- [Troubleshooting](#troubleshooting)
|
- [Troubleshooting](#troubleshooting)
|
||||||
- [On the mobile device, cannot synchronise on the local network!](#on-the-mobile-device-cannot-synchronise-on-the-local-network)
|
- [On the mobile device, cannot synchronise on the local network!](#on-the-mobile-device-cannot-synchronise-on-the-local-network)
|
||||||
- [I think that something bad happening on the vault...](#i-think-that-something-bad-happening-on-the-vault)
|
- [I think that something bad happening on the vault...](#i-think-that-something-bad-happening-on-the-vault)
|
||||||
@@ -77,7 +79,7 @@ However, the logs would not be kept so long and cleared when restarted. If you w
|
|||||||
To avoid unexpected exposure to our confidential things.
|
To avoid unexpected exposure to our confidential things.
|
||||||
|
|
||||||
### Some network logs are not written into the file.
|
### Some network logs are not written into the file.
|
||||||
Especially the CORS error will be reported as a general error to the plug-in for security reasons. So we cannot detect and log it.
|
Especially the CORS error will be reported as a general error to the plug-in for security reasons. So we cannot detect and log it. We are only able to investigate them by [Checking the network log](#checking-the-network-log).
|
||||||
|
|
||||||
### If a file were deleted or trimmed, the capacity of the database should be reduced, right?
|
### If a file were deleted or trimmed, the capacity of the database should be reduced, right?
|
||||||
No, even though if files were deleted, chunks were not deleted.
|
No, even though if files were deleted, chunks were not deleted.
|
||||||
@@ -87,7 +89,15 @@ And one more thing, we can handle the conflicts on any device even though it has
|
|||||||
|
|
||||||
To shrink the database size, `Rebuild everything` only reliably and effectively. But do not worry, if we have synchronised well. We have the actual and real files. Only it takes a bit of time and traffics.
|
To shrink the database size, `Rebuild everything` only reliably and effectively. But do not worry, if we have synchronised well. We have the actual and real files. Only it takes a bit of time and traffics.
|
||||||
|
|
||||||
<!-- Add here -->
|
### How can I use the DevTools?
|
||||||
|
|
||||||
|
#### Checking the network log
|
||||||
|
1. Open the network pane.
|
||||||
|
2. Find the requests marked in red.
|
||||||
|

|
||||||
|
3. Capture the `Headers`, `Payload`, and, `Response`. **Please be sure to keep important information confidential**. If the `Response` contains secrets, you can omitted that.
|
||||||
|
Note: Headers contains a some credentials. **The path of the request URL, Remote Address, authority, and authorization must be concealed.**
|
||||||
|

|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
<!-- Add here -->
|
<!-- Add here -->
|
||||||
|
|||||||
@@ -14,21 +14,24 @@ if you want to view the source, please visit the github repository of this plugi
|
|||||||
*/
|
*/
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
const prod = process.argv[2] === "production";
|
const prod = process.argv[2] === "production";
|
||||||
const keepTest = !prod;
|
const dev = process.argv[2] === "dev";
|
||||||
|
|
||||||
|
const keepTest = !prod || dev;
|
||||||
|
|
||||||
const terserOpt = {
|
const terserOpt = {
|
||||||
sourceMap: (!prod ? {
|
sourceMap: !prod
|
||||||
url: "inline"
|
? {
|
||||||
} : {}),
|
url: "inline",
|
||||||
|
}
|
||||||
|
: {},
|
||||||
format: {
|
format: {
|
||||||
indent_level: 2,
|
indent_level: 2,
|
||||||
beautify: true,
|
beautify: true,
|
||||||
comments: "some",
|
comments: "some",
|
||||||
ecma: 2018,
|
ecma: 2018,
|
||||||
preamble: banner,
|
preamble: banner,
|
||||||
webkit: true
|
webkit: true,
|
||||||
},
|
},
|
||||||
parse: {
|
parse: {
|
||||||
// parse options
|
// parse options
|
||||||
@@ -53,16 +56,6 @@ const terserOpt = {
|
|||||||
ecma: 2018,
|
ecma: 2018,
|
||||||
unused: true,
|
unused: true,
|
||||||
},
|
},
|
||||||
// mangle: {
|
|
||||||
// // mangle options
|
|
||||||
// keep_classnames: true,
|
|
||||||
// keep_fnames: true,
|
|
||||||
|
|
||||||
// properties: {
|
|
||||||
// // mangle property options
|
|
||||||
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
|
|
||||||
ecma: 2018, // specify one of: 5, 2015, 2016, etc.
|
ecma: 2018, // specify one of: 5, 2015, 2016, etc.
|
||||||
enclose: false, // or specify true, or "args:values"
|
enclose: false, // or specify true, or "args:values"
|
||||||
@@ -72,41 +65,41 @@ const terserOpt = {
|
|||||||
module: false,
|
module: false,
|
||||||
// nameCache: null, // or specify a name cache object
|
// nameCache: null, // or specify a name cache object
|
||||||
safari10: false,
|
safari10: false,
|
||||||
toplevel: false
|
toplevel: false,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const manifestJson = JSON.parse(fs.readFileSync("./manifest.json") + "");
|
const manifestJson = JSON.parse(fs.readFileSync("./manifest.json") + "");
|
||||||
const packageJson = JSON.parse(fs.readFileSync("./package.json") + "");
|
const packageJson = JSON.parse(fs.readFileSync("./package.json") + "");
|
||||||
const updateInfo = JSON.stringify(fs.readFileSync("./updates.md") + "");
|
const updateInfo = JSON.stringify(fs.readFileSync("./updates.md") + "");
|
||||||
|
|
||||||
/** @type esbuild.Plugin[] */
|
/** @type esbuild.Plugin[] */
|
||||||
const plugins = [{
|
const plugins = [
|
||||||
name: 'my-plugin',
|
{
|
||||||
setup(build) {
|
name: "my-plugin",
|
||||||
let count = 0;
|
setup(build) {
|
||||||
build.onEnd(async result => {
|
let count = 0;
|
||||||
if (count++ === 0) {
|
build.onEnd(async (result) => {
|
||||||
console.log('first build:', result);
|
if (count++ === 0) {
|
||||||
|
console.log("first build:", result);
|
||||||
} else {
|
} else {
|
||||||
console.log('subsequent build:');
|
console.log("subsequent build:");
|
||||||
}
|
|
||||||
if (prod) {
|
|
||||||
console.log("Performing terser");
|
|
||||||
const src = fs.readFileSync("./main_org.js").toString();
|
|
||||||
// @ts-ignore
|
|
||||||
const ret = await minify(src, terserOpt);
|
|
||||||
if (ret && ret.code) {
|
|
||||||
fs.writeFileSync("./main.js", ret.code);
|
|
||||||
}
|
}
|
||||||
console.log("Finished terser");
|
if (prod) {
|
||||||
} else {
|
console.log("Performing terser");
|
||||||
fs.copyFileSync("./main_org.js", "./main.js");
|
const src = fs.readFileSync("./main_org.js").toString();
|
||||||
}
|
// @ts-ignore
|
||||||
});
|
const ret = await minify(src, terserOpt);
|
||||||
|
if (ret && ret.code) {
|
||||||
|
fs.writeFileSync("./main.js", ret.code);
|
||||||
|
}
|
||||||
|
console.log("Finished terser");
|
||||||
|
} else {
|
||||||
|
fs.copyFileSync("./main_org.js", "./main.js");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}];
|
];
|
||||||
|
|
||||||
const context = await esbuild.context({
|
const context = await esbuild.context({
|
||||||
banner: {
|
banner: {
|
||||||
@@ -115,26 +108,12 @@ const context = await esbuild.context({
|
|||||||
entryPoints: ["src/main.ts"],
|
entryPoints: ["src/main.ts"],
|
||||||
bundle: true,
|
bundle: true,
|
||||||
define: {
|
define: {
|
||||||
"MANIFEST_VERSION": `"${manifestJson.version}"`,
|
MANIFEST_VERSION: `"${manifestJson.version}"`,
|
||||||
"PACKAGE_VERSION": `"${packageJson.version}"`,
|
PACKAGE_VERSION: `"${packageJson.version}"`,
|
||||||
"UPDATE_INFO": `${updateInfo}`,
|
UPDATE_INFO: `${updateInfo}`,
|
||||||
"global": "window",
|
global: "window",
|
||||||
},
|
},
|
||||||
external: [
|
external: ["obsidian", "electron", "crypto", "@codemirror/autocomplete", "@codemirror/collab", "@codemirror/commands", "@codemirror/language", "@codemirror/lint", "@codemirror/search", "@codemirror/state", "@codemirror/view", "@lezer/common", "@lezer/highlight", "@lezer/lr"],
|
||||||
"obsidian",
|
|
||||||
"electron",
|
|
||||||
"crypto",
|
|
||||||
"@codemirror/autocomplete",
|
|
||||||
"@codemirror/collab",
|
|
||||||
"@codemirror/commands",
|
|
||||||
"@codemirror/language",
|
|
||||||
"@codemirror/lint",
|
|
||||||
"@codemirror/search",
|
|
||||||
"@codemirror/state",
|
|
||||||
"@codemirror/view",
|
|
||||||
"@lezer/common",
|
|
||||||
"@lezer/highlight",
|
|
||||||
"@lezer/lr"],
|
|
||||||
// minifyWhitespace: true,
|
// minifyWhitespace: true,
|
||||||
format: "cjs",
|
format: "cjs",
|
||||||
target: "es2018",
|
target: "es2018",
|
||||||
@@ -155,11 +134,11 @@ const context = await esbuild.context({
|
|||||||
preprocess: sveltePreprocess(),
|
preprocess: sveltePreprocess(),
|
||||||
compilerOptions: { css: "injected", preserveComments: false },
|
compilerOptions: { css: "injected", preserveComments: false },
|
||||||
}),
|
}),
|
||||||
...plugins
|
...plugins,
|
||||||
],
|
],
|
||||||
})
|
});
|
||||||
|
|
||||||
if (prod) {
|
if (prod || dev) {
|
||||||
await context.rebuild();
|
await context.rebuild();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
BIN
images/devtools1.png
Normal file
BIN
images/devtools1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
images/devtools2.png
Normal file
BIN
images/devtools2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "obsidian-livesync",
|
"id": "obsidian-livesync",
|
||||||
"name": "Self-hosted LiveSync",
|
"name": "Self-hosted LiveSync",
|
||||||
"version": "0.23.8",
|
"version": "0.23.11",
|
||||||
"minAppVersion": "0.9.12",
|
"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.",
|
"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",
|
"author": "vorotamoroz",
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.23.8",
|
"version": "0.23.11",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.23.8",
|
"version": "0.23.11",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.556.0",
|
"@aws-sdk/client-s3": "^3.556.0",
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.23.8",
|
"version": "0.23.11",
|
||||||
"description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
"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",
|
"main": "main.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node esbuild.config.mjs",
|
"dev": "node esbuild.config.mjs",
|
||||||
"build": "node esbuild.config.mjs production",
|
"build": "node esbuild.config.mjs production",
|
||||||
|
"buildDev": "node esbuild.config.mjs dev",
|
||||||
"lint": "eslint src"
|
"lint": "eslint src"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Notice, type PluginManifest, parseYaml, normalizePath, type ListedFiles
|
|||||||
import type { EntryDoc, LoadedEntry, InternalFileEntry, FilePathWithPrefix, FilePath, DocumentID, AnyEntry, SavingEntry } from "../lib/src/common/types.ts";
|
import type { EntryDoc, LoadedEntry, InternalFileEntry, FilePathWithPrefix, FilePath, DocumentID, AnyEntry, SavingEntry } from "../lib/src/common/types.ts";
|
||||||
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, MODE_SELECTIVE } from "../lib/src/common/types.ts";
|
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, MODE_SELECTIVE } from "../lib/src/common/types.ts";
|
||||||
import { ICXHeader, PERIODIC_PLUGIN_SWEEP, } from "../common/types.ts";
|
import { ICXHeader, PERIODIC_PLUGIN_SWEEP, } from "../common/types.ts";
|
||||||
import { createSavingEntryFromLoadedEntry, createTextBlob, delay, fireAndForget, getDocDataAsArray, isDocContentSame, throttle } from "../lib/src/common/utils.ts";
|
import { createSavingEntryFromLoadedEntry, createTextBlob, delay, fireAndForget, getDocDataAsArray, isDocContentSame } from "../lib/src/common/utils.ts";
|
||||||
import { Logger } from "../lib/src/common/logger.ts";
|
import { Logger } from "../lib/src/common/logger.ts";
|
||||||
import { readString, decodeBinary, arrayBufferToBase64, digestHash } from "../lib/src/string_and_binary/strbin.ts";
|
import { readString, decodeBinary, arrayBufferToBase64, digestHash } from "../lib/src/string_and_binary/strbin.ts";
|
||||||
import { serialized, shareRunningResult } from "../lib/src/concurrency/lock.ts";
|
import { serialized, shareRunningResult } from "../lib/src/concurrency/lock.ts";
|
||||||
@@ -19,7 +19,6 @@ import type ObsidianLiveSyncPlugin from '../main.ts';
|
|||||||
|
|
||||||
const d = "\u200b";
|
const d = "\u200b";
|
||||||
const d2 = "\n";
|
const d2 = "\n";
|
||||||
const delimiters = /(?<=[\n|\u200b])/g;
|
|
||||||
|
|
||||||
|
|
||||||
function serialize(data: PluginDataEx): string {
|
function serialize(data: PluginDataEx): string {
|
||||||
@@ -42,8 +41,45 @@ function serialize(data: PluginDataEx): string {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function splitWithDelimiters(sources: string[]): string[] {
|
||||||
|
const result: string[] = [];
|
||||||
|
for (const str of sources) {
|
||||||
|
let startIndex = 0;
|
||||||
|
const maxLen = str.length;
|
||||||
|
let i = -1;
|
||||||
|
let i1;
|
||||||
|
let i2;
|
||||||
|
do {
|
||||||
|
i1 = str.indexOf(d, startIndex);
|
||||||
|
i2 = str.indexOf(d2, startIndex);
|
||||||
|
if (i1 == -1 && i2 == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i1 == -1) {
|
||||||
|
i = i2;
|
||||||
|
} else if (i2 == -1) {
|
||||||
|
i = i1;
|
||||||
|
} else {
|
||||||
|
i = i1 < i2 ? i1 : i2;
|
||||||
|
}
|
||||||
|
result.push(str.slice(startIndex, i + 1));
|
||||||
|
startIndex = i + 1;
|
||||||
|
} while (i < maxLen);
|
||||||
|
if (startIndex < maxLen) {
|
||||||
|
result.push(str.slice(startIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To keep compatibilities
|
||||||
|
if (sources[sources.length - 1] == "") {
|
||||||
|
result.push("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
function getTokenizer(source: string[]) {
|
function getTokenizer(source: string[]) {
|
||||||
const sources = source.flatMap(e => e.split(delimiters))
|
const sources = splitWithDelimiters(source);
|
||||||
sources[0] = sources[0].substring(1);
|
sources[0] = sources[0].substring(1);
|
||||||
let pos = 0;
|
let pos = 0;
|
||||||
let lineRunOut = false;
|
let lineRunOut = false;
|
||||||
@@ -318,8 +354,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
createMissingConfigurationEntry = throttle(() => this._createMissingConfigurationEntry(), 1000);
|
async createMissingConfigurationEntry() {
|
||||||
_createMissingConfigurationEntry() {
|
|
||||||
let saveRequired = false;
|
let saveRequired = false;
|
||||||
for (const v of this.pluginList) {
|
for (const v of this.pluginList) {
|
||||||
const key = `${v.category}/${v.name}`;
|
const key = `${v.category}/${v.name}`;
|
||||||
@@ -337,7 +372,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (saveRequired) {
|
if (saveRequired) {
|
||||||
this.plugin.saveSettingData();
|
await this.plugin.saveSettingData();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -365,7 +400,11 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}, { suspended: false, batchSize: 1, concurrentLimit: 10, delay: 100, yieldThreshold: 10, maintainDelay: false, totalRemainingReactiveSource: pluginScanningCount }).startPipeline().root.onUpdateProgress(() => {
|
}, { suspended: false, batchSize: 1, concurrentLimit: 10, delay: 100, yieldThreshold: 10, maintainDelay: false, totalRemainingReactiveSource: pluginScanningCount }).startPipeline().root.onUpdateProgress(() => {
|
||||||
this.createMissingConfigurationEntry();
|
scheduleTask("checkMissingConfigurations", 250, async () => {
|
||||||
|
if (this.pluginScanProcessor.isIdle()) {
|
||||||
|
await this.createMissingConfigurationEntry();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -654,7 +693,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
for (const target of fileTargets) {
|
for (const target of fileTargets) {
|
||||||
const data = await this.makeEntryFromFile(target);
|
const data = await this.makeEntryFromFile(target);
|
||||||
if (data == false) {
|
if (data == false) {
|
||||||
// Logger(`Config: skipped: ${target} `, LOG_LEVEL_VERBOSE);
|
Logger(`Config: skipped (Possibly is not exist): ${target} `, LOG_LEVEL_VERBOSE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (data.version) {
|
if (data.version) {
|
||||||
@@ -703,13 +742,15 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
const oldC = await this.localDatabase.getDBEntryFromMeta(old, {}, false, false);
|
const oldC = await this.localDatabase.getDBEntryFromMeta(old, {}, false, false);
|
||||||
if (oldC) {
|
if (oldC) {
|
||||||
const d = await deserialize(getDocDataAsArray(oldC.data), {}) as PluginDataEx;
|
const d = await deserialize(getDocDataAsArray(oldC.data), {}) as PluginDataEx;
|
||||||
const diffs = (d.files.map(previous => ({ prev: previous, curr: dt.files.find(e => e.filename == previous.filename) })).map(async e => {
|
if (d.files.length == dt.files.length) {
|
||||||
try { return await isDocContentSame(e.curr?.data ?? [], e.prev.data) } catch (_) { return false }
|
const diffs = (d.files.map(previous => ({ prev: previous, curr: dt.files.find(e => e.filename == previous.filename) })).map(async e => {
|
||||||
}))
|
try { return await isDocContentSame(e.curr?.data ?? [], e.prev.data) } catch (_) { return false }
|
||||||
const isSame = (await Promise.all(diffs)).every(e => e == true);
|
}))
|
||||||
if (isSame) {
|
const isSame = (await Promise.all(diffs)).every(e => e == true);
|
||||||
Logger(`STORAGE --> DB:${prefixedFileName}: (config) Skipped (Same content)`, LOG_LEVEL_VERBOSE);
|
if (isSame) {
|
||||||
return true;
|
Logger(`STORAGE --> DB:${prefixedFileName}: (config) Skipped (Same content)`, LOG_LEVEL_VERBOSE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
saveData =
|
saveData =
|
||||||
@@ -757,9 +798,11 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
this.recentProcessedInternalFiles = [key, ...this.recentProcessedInternalFiles].slice(0, 100);
|
this.recentProcessedInternalFiles = [key, ...this.recentProcessedInternalFiles].slice(0, 100);
|
||||||
|
// To prevent saving half-collected file sets.
|
||||||
this.storeCustomizationFiles(path).then(() => {/* Fire and forget */ });
|
const keySchedule = this.filenameToUnifiedKey(path);
|
||||||
|
scheduleTask(keySchedule, 100, async () => {
|
||||||
|
await this.storeCustomizationFiles(path);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
src/lib
2
src/lib
Submodule src/lib updated: ed85f79cf7...9825b64d17
29
src/main.ts
29
src/main.ts
@@ -878,6 +878,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
|
|||||||
async onload() {
|
async onload() {
|
||||||
logStore.pipeTo(new QueueProcessor(logs => logs.forEach(e => this.addLog(e.message, e.level, e.key)), { suspended: false, batchSize: 20, concurrentLimit: 1, delay: 0 })).startPipeline();
|
logStore.pipeTo(new QueueProcessor(logs => logs.forEach(e => this.addLog(e.message, e.level, e.key)), { suspended: false, batchSize: 20, concurrentLimit: 1, delay: 0 })).startPipeline();
|
||||||
Logger("loading plugin");
|
Logger("loading plugin");
|
||||||
|
__onMissingTranslation(() => { });
|
||||||
// eslint-disable-next-line no-unused-labels
|
// eslint-disable-next-line no-unused-labels
|
||||||
DEV: {
|
DEV: {
|
||||||
__onMissingTranslation((key) => {
|
__onMissingTranslation((key) => {
|
||||||
@@ -1137,12 +1138,14 @@ Note: We can always able to read V1 format. It will be progressively converted.
|
|||||||
this.settingTab.requestReload()
|
this.settingTab.requestReload()
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveSettingData() {
|
saveDeviceAndVaultName() {
|
||||||
const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.getVaultName();
|
const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.getVaultName();
|
||||||
|
|
||||||
localStorage.setItem(lsKey, this.deviceAndVaultName || "");
|
localStorage.setItem(lsKey, this.deviceAndVaultName || "");
|
||||||
|
}
|
||||||
|
async saveSettingData() {
|
||||||
|
this.saveDeviceAndVaultName();
|
||||||
const settings = { ...this.settings };
|
const settings = { ...this.settings };
|
||||||
|
settings.deviceAndVaultName = "";
|
||||||
if (this.usedPassphrase == "" && !await this.getPassphrase(settings)) {
|
if (this.usedPassphrase == "" && !await this.getPassphrase(settings)) {
|
||||||
Logger("Could not determine passphrase for saving data.json! Our data.json have insecure items!", LOG_LEVEL_NOTICE);
|
Logger("Could not determine passphrase for saving data.json! Our data.json have insecure items!", LOG_LEVEL_NOTICE);
|
||||||
} else {
|
} else {
|
||||||
@@ -1439,7 +1442,7 @@ We can perform a command in this file.
|
|||||||
this.replicator.openReplication(this.settings, true, false, false);
|
this.replicator.openReplication(this.settings, true, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.settings.syncOnStart) {
|
if (!this.settings.liveSync && this.settings.syncOnStart) {
|
||||||
this.replicator.openReplication(this.settings, false, false, false);
|
this.replicator.openReplication(this.settings, false, false, false);
|
||||||
}
|
}
|
||||||
this.periodicSyncProcessor.enable(this.settings.periodicReplication ? this.settings.periodicReplicationInterval * 1000 : 0);
|
this.periodicSyncProcessor.enable(this.settings.periodicReplication ? this.settings.periodicReplicationInterval * 1000 : 0);
|
||||||
@@ -3060,28 +3063,28 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
const ret = await this.localDatabase.putDBEntry(d);
|
const ret = await this.localDatabase.putDBEntry(d);
|
||||||
if (ret !== false) {
|
if (ret !== false) {
|
||||||
Logger(msg + fullPath);
|
Logger(msg + fullPath);
|
||||||
if (this.settings.syncOnSave && !this.suspended) {
|
this.scheduleReplicateIfSyncOnSave();
|
||||||
scheduleTask("perform-replicate-after-save", 250, () => this.replicate());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret != false;
|
return ret != false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scheduleReplicateIfSyncOnSave() {
|
||||||
|
if (this.settings.syncOnSave && !this.suspended) {
|
||||||
|
scheduleTask("perform-replicate-after-save", 250, () => this.replicate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async deleteFromDB(file: TFile) {
|
async deleteFromDB(file: TFile) {
|
||||||
if (!await this.isTargetFile(file)) return;
|
if (!await this.isTargetFile(file)) return;
|
||||||
const fullPath = getPathFromTFile(file);
|
const fullPath = getPathFromTFile(file);
|
||||||
Logger(`deleteDB By path:${fullPath}`);
|
Logger(`deleteDB By path:${fullPath}`);
|
||||||
await this.deleteFromDBbyPath(fullPath);
|
await this.deleteFromDBbyPath(fullPath);
|
||||||
if (this.settings.syncOnSave && !this.suspended) {
|
this.scheduleReplicateIfSyncOnSave();
|
||||||
await this.replicate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteFromDBbyPath(fullPath: FilePath) {
|
async deleteFromDBbyPath(fullPath: FilePath) {
|
||||||
await this.localDatabase.deleteDBEntry(fullPath);
|
await this.localDatabase.deleteDBEntry(fullPath);
|
||||||
if (this.settings.syncOnSave && !this.suspended) {
|
this.scheduleReplicateIfSyncOnSave();
|
||||||
await this.replicate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async resetLocalDatabase() {
|
async resetLocalDatabase() {
|
||||||
|
|||||||
@@ -437,12 +437,18 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
localStorage.setItem("ls-setting-passphrase", this.editingSettings?.[key] ?? "");
|
localStorage.setItem("ls-setting-passphrase", this.editingSettings?.[key] ?? "");
|
||||||
return await Promise.resolve();
|
return await Promise.resolve();
|
||||||
}
|
}
|
||||||
|
if (key == "deviceAndVaultName") {
|
||||||
|
this.plugin.deviceAndVaultName = this.editingSettings?.[key];
|
||||||
|
this.plugin.saveDeviceAndVaultName();
|
||||||
|
return await Promise.resolve();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Apply and save setting to the plug-in.
|
* Apply and save setting to the plug-in.
|
||||||
* @param keys setting keys for applying
|
* @param keys setting keys for applying
|
||||||
*/
|
*/
|
||||||
async saveSettings(keys: (AllSettingItemKey)[]) {
|
async saveSettings(keys: (AllSettingItemKey)[]) {
|
||||||
|
let hasChanged = false;
|
||||||
const appliedKeys = [] as AllSettingItemKey[];
|
const appliedKeys = [] as AllSettingItemKey[];
|
||||||
for (const k of keys) {
|
for (const k of keys) {
|
||||||
if (!this.isDirty(k)) continue;
|
if (!this.isDirty(k)) continue;
|
||||||
@@ -457,9 +463,12 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
this.plugin.settings[k] = this.editingSettings[k];
|
this.plugin.settings[k] = this.editingSettings[k];
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
this.initialSettings[k] = this.plugin.settings[k];
|
this.initialSettings[k] = this.plugin.settings[k];
|
||||||
|
hasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.plugin.saveSettings();
|
if (hasChanged) {
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
// if (runOnSaved) {
|
// if (runOnSaved) {
|
||||||
const handlers =
|
const handlers =
|
||||||
@@ -498,6 +507,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
const ret = { ...OnDialogSettingsDefault };
|
const ret = { ...OnDialogSettingsDefault };
|
||||||
ret.configPassphrase = localStorage.getItem("ls-setting-passphrase") || "";
|
ret.configPassphrase = localStorage.getItem("ls-setting-passphrase") || "";
|
||||||
ret.preset = ""
|
ret.preset = ""
|
||||||
|
ret.deviceAndVaultName = this.plugin.deviceAndVaultName;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
computeAllLocalSettings(): Partial<OnDialogSettings> {
|
computeAllLocalSettings(): Partial<OnDialogSettings> {
|
||||||
@@ -510,12 +520,12 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
/**
|
/**
|
||||||
* Reread all settings and request invalidate
|
* Reread all settings and request invalidate
|
||||||
*/
|
*/
|
||||||
reloadAllSettings() {
|
reloadAllSettings(skipUpdate: boolean = false) {
|
||||||
const localSetting = this.reloadAllLocalSettings();
|
const localSetting = this.reloadAllLocalSettings();
|
||||||
this._editingSettings = { ...this.plugin.settings, ...localSetting };
|
this._editingSettings = { ...this.plugin.settings, ...localSetting };
|
||||||
this._editingSettings = { ...this.editingSettings, ...this.computeAllLocalSettings() };
|
this._editingSettings = { ...this.editingSettings, ...this.computeAllLocalSettings() };
|
||||||
this.initialSettings = { ...this.editingSettings, };
|
this.initialSettings = { ...this.editingSettings, };
|
||||||
this.requestUpdate();
|
if (!skipUpdate) this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -658,9 +668,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Logger(`reread: all! hidden`, LOG_LEVEL_VERBOSE)
|
this.reloadAllSettings(true);
|
||||||
this.reloadAllSettings();
|
|
||||||
this.display();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -760,7 +768,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
|
|
||||||
addScreenElement("100", containerInformationEl);
|
addScreenElement("100", containerInformationEl);
|
||||||
const isAnySyncEnabled = (): boolean => {
|
const isAnySyncEnabled = (): boolean => {
|
||||||
if (this.isConfiguredAs("isConfigured", false)) return true;
|
if (this.isConfiguredAs("isConfigured", false)) return false;
|
||||||
if (this.isConfiguredAs("liveSync", true)) return true;
|
if (this.isConfiguredAs("liveSync", true)) return true;
|
||||||
if (this.isConfiguredAs("periodicReplication", true)) return true;
|
if (this.isConfiguredAs("periodicReplication", true)) return true;
|
||||||
if (this.isConfiguredAs("syncOnFileOpen", true)) return true;
|
if (this.isConfiguredAs("syncOnFileOpen", true)) return true;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export type OnDialogSettings = {
|
|||||||
preset: "" | "PERIODIC" | "LIVESYNC" | "DISABLE",
|
preset: "" | "PERIODIC" | "LIVESYNC" | "DISABLE",
|
||||||
syncMode: "ONEVENTS" | "PERIODIC" | "LIVESYNC"
|
syncMode: "ONEVENTS" | "PERIODIC" | "LIVESYNC"
|
||||||
dummy: number,
|
dummy: number,
|
||||||
|
deviceAndVaultName: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OnDialogSettingsDefault: OnDialogSettings = {
|
export const OnDialogSettingsDefault: OnDialogSettings = {
|
||||||
@@ -13,6 +14,7 @@ export const OnDialogSettingsDefault: OnDialogSettings = {
|
|||||||
preset: "",
|
preset: "",
|
||||||
syncMode: "ONEVENTS",
|
syncMode: "ONEVENTS",
|
||||||
dummy: 0,
|
dummy: 0,
|
||||||
|
deviceAndVaultName: "",
|
||||||
}
|
}
|
||||||
export const AllSettingDefault =
|
export const AllSettingDefault =
|
||||||
{ ...DEFAULT_SETTINGS, ...OnDialogSettingsDefault }
|
{ ...DEFAULT_SETTINGS, ...OnDialogSettingsDefault }
|
||||||
|
|||||||
32
updates.md
32
updates.md
@@ -18,6 +18,22 @@ 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.
|
Hooray for open source, and generous licences, and the sharing of knowledge by experts.
|
||||||
|
|
||||||
#### Version history
|
#### Version history
|
||||||
|
- 0.23.11:
|
||||||
|
- Fixed:
|
||||||
|
- Now we *surely* can set the device name and enable customised synchronisation.
|
||||||
|
- Unnecessary dialogue update processes have been eliminated.
|
||||||
|
- Customisation sync no longer stores half-collected files.
|
||||||
|
- No longer hangs up when removing or renaming files with the `Sync on Save` toggle enabled.
|
||||||
|
- Improved:
|
||||||
|
- Customisation sync now performs data deserialization more smoothly.
|
||||||
|
- New translations have been merged.
|
||||||
|
- 0.23.10
|
||||||
|
- Fixed:
|
||||||
|
- No longer configurations have been locked in the minimal setup.
|
||||||
|
- 0.23.9
|
||||||
|
- Fixed:
|
||||||
|
- No longer unexpected parallel replication is performed.
|
||||||
|
- Now we can set the device name and enable customised synchronisation again.
|
||||||
- 0.23.8
|
- 0.23.8
|
||||||
- New feature:
|
- New feature:
|
||||||
- Now we are ready for i18n.
|
- Now we are ready for i18n.
|
||||||
@@ -45,21 +61,5 @@ Hooray for open source, and generous licences, and the sharing of knowledge by e
|
|||||||
- Some trivial issues have been fixed.
|
- Some trivial issues have been fixed.
|
||||||
- New feature:
|
- New feature:
|
||||||
- Reloading Obsidian can be scheduled until that file and database operations are stable.
|
- Reloading Obsidian can be scheduled until that file and database operations are stable.
|
||||||
- 0.23.6:
|
|
||||||
- Fixed:
|
|
||||||
- Now the remote chunks could be decrypted even if we are using `Incubate chunks in Document`. (The note of 0.23.6 has been fixed).
|
|
||||||
- Chunk retrieving with `Incubate chunks in document` got more efficiently.
|
|
||||||
- No longer task processor misses the completed tasks.
|
|
||||||
- Replication is no longer started automatically during changes in window visibility (e.g., task switching on the desktop) when off-focused.
|
|
||||||
- 0.23.5:
|
|
||||||
- New feature:
|
|
||||||
- Now we can check configuration mismatching between clients before synchronisation.
|
|
||||||
- Default: enabled / Preferred: enabled / We can disable this by the `Do not check configuration mismatch before replication` toggle in the `Hatch` pane.
|
|
||||||
- It detects configuration mismatches and prevents synchronisation failures and wasted storage.
|
|
||||||
- Now we can perform remote database compaction from the `Maintenance` pane.
|
|
||||||
- Fixed:
|
|
||||||
- We can detect the bucket could not be reachable.
|
|
||||||
- Note:
|
|
||||||
- Known inexplicable behaviour: Recently, (Maybe while enabling `Incubate chunks in Document` and `Fetch chunks on demand` or some more toggles), our customisation sync data is sometimes corrupted. It will be addressed by the next release.
|
|
||||||
|
|
||||||
Older notes is in [updates_old.md](https://github.com/vrtmrz/obsidian-livesync/blob/main/updates_old.md).
|
Older notes is in [updates_old.md](https://github.com/vrtmrz/obsidian-livesync/blob/main/updates_old.md).
|
||||||
@@ -18,6 +18,22 @@ 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.
|
Hooray for open source, and generous licences, and the sharing of knowledge by experts.
|
||||||
|
|
||||||
#### Version history
|
#### Version history
|
||||||
|
- 0.23.6:
|
||||||
|
- Fixed:
|
||||||
|
- Now the remote chunks could be decrypted even if we are using `Incubate chunks in Document`. (The note of 0.23.6 has been fixed).
|
||||||
|
- Chunk retrieving with `Incubate chunks in document` got more efficiently.
|
||||||
|
- No longer task processor misses the completed tasks.
|
||||||
|
- Replication is no longer started automatically during changes in window visibility (e.g., task switching on the desktop) when off-focused.
|
||||||
|
- 0.23.5:
|
||||||
|
- New feature:
|
||||||
|
- Now we can check configuration mismatching between clients before synchronisation.
|
||||||
|
- Default: enabled / Preferred: enabled / We can disable this by the `Do not check configuration mismatch before replication` toggle in the `Hatch` pane.
|
||||||
|
- It detects configuration mismatches and prevents synchronisation failures and wasted storage.
|
||||||
|
- Now we can perform remote database compaction from the `Maintenance` pane.
|
||||||
|
- Fixed:
|
||||||
|
- We can detect the bucket could not be reachable.
|
||||||
|
- Note:
|
||||||
|
- Known inexplicable behaviour: Recently, (Maybe while enabling `Incubate chunks in Document` and `Fetch chunks on demand` or some more toggles), our customisation sync data is sometimes corrupted. It will be addressed by the next release.
|
||||||
- 0.23.4
|
- 0.23.4
|
||||||
- Fixed:
|
- Fixed:
|
||||||
- No longer experimental configuration is shown on the Minimal Setup.
|
- No longer experimental configuration is shown on the Minimal Setup.
|
||||||
|
|||||||
Reference in New Issue
Block a user