mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-10 09:41:55 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e05f8771b9 | ||
|
|
65619c2478 | ||
|
|
1552fa9d9e | ||
|
|
767f12b52f | ||
|
|
4071ba120e | ||
|
|
2c0e3ba01c |
10
README.md
10
README.md
@@ -34,13 +34,15 @@ This plug-in might be useful for researchers, engineers, and developers with a n
|
|||||||
|
|
||||||
[](https://www.youtube.com/watch?v=7sa_I1832Xc)
|
[](https://www.youtube.com/watch?v=7sa_I1832Xc)
|
||||||
|
|
||||||
- [Setup CouchDB on fly.io](docs/setup_flyio.md)
|
1. [Setup CouchDB on fly.io](docs/setup_flyio.md)
|
||||||
|
2. Configure plug-in in [Quick Setup](docs/quick_setup.md)
|
||||||
|
|
||||||
### Manually Setup
|
### Manually Setup
|
||||||
|
|
||||||
1. [Setup CouchDB on fly.io](docs/setup_flyio.md)
|
1. Setup the server
|
||||||
2. [Setup your CouchDB](docs/setup_own_server.md)
|
1. [Setup CouchDB on fly.io](docs/setup_flyio.md)
|
||||||
3. [Configure plug-in](docs/quick_setup.md)
|
2. [Setup your CouchDB](docs/setup_own_server.md)
|
||||||
|
2. Configure plug-in in [Quick Setup](docs/quick_setup.md)
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> We are still able to use IBM Cloudant. However, it is not recommended for several reasons nowadays. Here is [Setup IBM Cloudant](docs/setup_cloudant.md)
|
> We are still able to use IBM Cloudant. However, it is not recommended for several reasons nowadays. Here is [Setup IBM Cloudant](docs/setup_cloudant.md)
|
||||||
|
|||||||
@@ -2,34 +2,51 @@
|
|||||||
|
|
||||||
[Japanese docs](./quick_setup_ja.md) - [Chinese docs](./quick_setup_cn.md).
|
[Japanese docs](./quick_setup_ja.md) - [Chinese docs](./quick_setup_cn.md).
|
||||||
|
|
||||||
The plugin has so many configuration options to deal with different circumstances. However, there are not so many settings that are actually used. Therefore, `The Setup wizard` has been implemented to simplify the initial setup.
|
The plugin has so many configuration options to deal with different circumstances. However, only a few settings are required in the normal cases. Therefore, `The Setup wizard` has been implemented to simplify the setup.
|
||||||
|
|
||||||
Note: Subsequent devices are recommended to be set up using the `Copy setup URI` and `Open setup URI`.
|
|
||||||
|
|
||||||
## The Setup wizard
|
|
||||||
Open the `🧙♂️ Setup wizard` in the settings dialogue. If the plugin has not been configured before, it should already be open.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Discard the existing configuration and set up
|
There are three methods to set up Self-hosted LiveSync.
|
||||||
If you have changed any settings, this button allows you to discard all changes before setting up.
|
|
||||||
|
|
||||||
- Do not discard the existing configuration and set up
|
1. [Using setup URIs](#1-using-setup-uris) *(Recommended)*
|
||||||
Simply reconfigure. Be careful. In wizard mode, you cannot see all configuration items, even if they have been configured.
|
2. [Minimal setup](#2-minimal-setup)
|
||||||
|
3. [Full manually setup the and Enable on this dialogue](#3-manually-setup)
|
||||||
|
|
||||||
Pressing `Next` on one of the above options will put the configuration dialog into wizard mode.
|
## At the first device
|
||||||
|
|
||||||
### Wizard mode
|
### 1. Using setup URIs
|
||||||
|
|
||||||
|
> [!TIP] What is the setup URI? Why is it required?
|
||||||
|
> The setup URI is the encrypted representation of Self-hosted LiveSync configuration as a URI. This starts `obsidian://setuplivesync?settings=`. This is encrypted with a passphrase, so that it can be shared relatively securely between devices. It is a bit long, but it is one line. This allows a series of settings to be set at once without any inconsistencies.
|
||||||
|
>
|
||||||
|
> If you have configured the remote database by [Automated setup on Fly.io](./setup_flyio.md#a-very-automated-setup) or [set up your server with the tool](./setup_own_server.md#1-generate-the-setup-uri-on-a-desktop-device-or-server), **you should have one of them**
|
||||||
|
|
||||||
|
In this procedure, [this video](https://youtu.be/7sa_I1832Xc?t=146) may help us.
|
||||||
|
|
||||||
|
1. Click `Use` button (Or launch `Use the copied setup URI` from Command palette).
|
||||||
|
2. Paste the Setup URI into the dialogue
|
||||||
|
3. Type the passphrase of the Setup URI
|
||||||
|
4. Answer `yes` for `Importing LiveSync's conf, OK?`.
|
||||||
|
5. Answer `Set it up as secondary or subsequent device` for `How would you like to set it up?`.
|
||||||
|
6. Initialisation will begin, please hold a while.
|
||||||
|
7. You will asked about the hidden file synchronisation, answer as you like.
|
||||||
|
1. If you are new to Self-hosted LiveSync, we can configure it later so leave it once.
|
||||||
|
8. Synchronisation has been started! `Reload app without saving` is recommended after the indicators of Self-hosted LiveSync disappear.
|
||||||
|
|
||||||
|
OK, we can proceed the [next step](#).
|
||||||
|
|
||||||
|
### 2. Minimal setup
|
||||||
|
|
||||||
|
If you do not have any setup URI, Press the `start` button. The setting dialogue turns into the wizard mode and will display only minimal items.
|
||||||
|
|
||||||
|
>[!TIP]
|
||||||
|
> We can generate the setup URI with the tool in any time. Please use [this tool](./setup_own_server.md#1-generate-the-setup-uri-on-a-desktop-device-or-server).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Let's see how to use it step-by-step.
|
#### Remote database configuration
|
||||||
|
|
||||||
## Remote Database configuration
|
1. Enter the information for the database we have set up.
|
||||||
|
|
||||||
### Remote database configuration
|
|
||||||
|
|
||||||
Enter the information for the database we have set up.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -37,13 +54,9 @@ Enter the information for the database we have set up.
|
|||||||
#### Test database connection and Check database configuration
|
#### Test database connection and Check database configuration
|
||||||
|
|
||||||
We can check the connectivity to the database, and the database settings.
|
We can check the connectivity to the database, and the database settings.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
#### Test Database Connection
|
#### Check and Fix database configuration
|
||||||
Check whether we can connect to the database. If it fails, there are several possible reasons, but first attempt the `Check database configuration` check to see if it fails there too.
|
|
||||||
|
|
||||||
#### Check database configuration
|
|
||||||
|
|
||||||
Check the database settings and fix any problems on the spot.
|
Check the database settings and fix any problems on the spot.
|
||||||
|
|
||||||
@@ -52,40 +65,43 @@ Check the database settings and fix any problems on the spot.
|
|||||||
This item may vary depending on the connection. In the above case, press all three Fix buttons.
|
This item may vary depending on the connection. In the above case, press all three Fix buttons.
|
||||||
If the Fix buttons disappear and all become check marks, we are done.
|
If the Fix buttons disappear and all become check marks, we are done.
|
||||||
|
|
||||||
|
#### Confidentiality configuration (Optional but very preferred)
|
||||||
### Confidentiality configuration
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Encrypt your database in case of unintended database exposure; enable End to End encryption and the contents of your notes will be encrypted at the moment it leaves the device. We strongly recommend enabling it. And `Path Obfuscation` also obfuscates filenames. Now stable and recommended.
|
Enable End-to-end encryption and the contents of your notes will be encrypted at the moment it leaves the device. We strongly recommend enabling it. And `Path Obfuscation` also obfuscates filenames. Now stable and recommended.
|
||||||
Encryption is based on 256-bit AES-GCM.
|
|
||||||
These setting can be disabled if you are inside a closed network and it is clear that you will not be accessed by third parties.
|
These setting can be disabled if you are inside a closed network and it is clear that you will not be accessed by third parties.
|
||||||
|
|
||||||

|
> [!TIP]
|
||||||
|
> Encryption is based on 256-bit AES-GCM.
|
||||||
|
|
||||||
#### Next
|
We should proceed to the Next step.
|
||||||
Go to the Sync Settings.
|
|
||||||
|
|
||||||
#### Discard existing database and proceed
|
#### Sync Settings
|
||||||
Discard the contents of the Remote database and go to the Sync Settings.
|
|
||||||
|
|
||||||
### Sync Settings
|
|
||||||
Finally, finish the wizard by selecting a preset for synchronisation.
|
Finally, finish the wizard by selecting a preset for synchronisation.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Select any synchronisation methods we want to use and `Apply` to initialise and build the local and remote databases as required. If `All done!` is displayed, we are done. Automatically, `Copy setup URI` will open and we will be asked for a passphrase to encrypt the `Setup URI`.
|
Select any synchronisation methods we want to use and `Apply`. If database initialisation is required, it will be performed at this time. When `All done!` is displayed, we are ready to synchronise.
|
||||||
|
|
||||||
|
The dialogue of `Copy settings as a new setup URI` will be open automatically. Please input a passphrase to encrypt the new `Setup URI`. (This passphrase is to encrypt the setup URI, not the vault).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Set the passphrase as you like.
|
The Setup URI will be copied to the clipboard, please make a note(Not in Obsidian) of this.
|
||||||
The Setup URI will be copied to the clipboard, which you can then transfer to the second and subsequent devices in some way.
|
|
||||||
|
|
||||||
# How to set up the second and subsequent units
|
>[!TIP]
|
||||||
After installing Self-hosted LiveSync on the first device, select `Open setup URI` from the command palette and enter the setup URI you transferred. Afterwards, enter your passphrase and a setup wizard will open.
|
We can copy this in any time by `Copy current settings as a new setup URI`.
|
||||||
Answer the following.
|
|
||||||
|
|
||||||
- `Yes` to `Importing LiveSync's conf, OK?`
|
### 3. Manually setup
|
||||||
- `Set it up as secondary or subsequent device` to `How would you like to set it up?`.
|
|
||||||
|
|
||||||
Then, The configuration will take effect and replication will start. Your files will be synchronised soon! You may need to close the settings dialog and reopen it to see the settings fields populated properly, but they will be set.
|
It is strongly recommended to perform a "minimal set-up" first and set up the other contents after making sure has been synchronised.
|
||||||
|
|
||||||
|
However, if you have some specific reasons to configure it manually, please click the `Enable` button of `Enable LiveSync on this device as the set-up was completed manually`.
|
||||||
|
And, please copy the setup URI by `Copy current settings as a new setup URI` and make a note(Not in Obsidian) of this.
|
||||||
|
|
||||||
|
## At the subsequent device
|
||||||
|
After installing Self-hosted LiveSync on the first device, we should have a setup URI. **The first choice is to use it**. Please share it with the device you want to setup.
|
||||||
|
|
||||||
|
It is completely same as [Using setup URIs on the first device](#1-using-setup-uris). Please refer it.
|
||||||
@@ -28,8 +28,10 @@ This is how to configure fly.io and CouchDB on it for Self-hosted LiveSync.
|
|||||||
2. Press the `Open in Colab` button.
|
2. Press the `Open in Colab` button.
|
||||||
3. Choose a region and run all blocks (Refer to video).
|
3. Choose a region and run all blocks (Refer to video).
|
||||||
1. If you do not have the account yet, the sign-up page will be shown, please follow the instructions. The [Official document is here](https://fly.io/docs/hands-on/sign-up/).
|
1. If you do not have the account yet, the sign-up page will be shown, please follow the instructions. The [Official document is here](https://fly.io/docs/hands-on/sign-up/).
|
||||||
4. Copy the Setup-URI and open it in the Obsidian.
|
4. Copy the Setup-URI and Use it in the Obsidian.
|
||||||
5. You have been synchronised. Open the Setup-URI in subsequent devices.
|
5. You have been synchronised. Use the Setup-URI in subsequent devices.
|
||||||
|
|
||||||
|
Steps 4 and 5 are detailed in the [Quick Setup](./quick_setup.md#1-using-setup-uris).
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Your automatically configured configurations will be shown on the result in the Colab note like below, and **it will not be saved**. Please make a note of it somewhere.
|
> Your automatically configured configurations will be shown on the result in the Colab note like below, and **it will not be saved**. Please make a note of it somewhere.
|
||||||
@@ -240,8 +242,8 @@ Note: Each of these should also be repeated until finished in 200.
|
|||||||
|
|
||||||
#### 6. Use it from Self-hosted LiveSync
|
#### 6. Use it from Self-hosted LiveSync
|
||||||
|
|
||||||
Now the CouchDB is ready to use from Self-hosted LiveSync. We can use `https://billowing-dawn-6619.fly.dev` in URI, `campanella` in `Username` and `dfusiuada9suy` in `Password` on Self-hosted LiveSync. `Database name` could be anything you want.
|
Now the CouchDB is ready to use from Self-hosted LiveSync. We can use `https://billowing-dawn-6619.fly.dev` in URI, `campanella` in `Username` and `dfusiuada9suy` in `Password` on Self-hosted LiveSync. The `Database name` could be anything you want.
|
||||||
`Enhance chunk size` could be up to around `100`.
|
Please refer to the [Minimal Setup of the Quick Setup](./quick_setup.md#2-minimal-setup).
|
||||||
|
|
||||||
## Delete the Instance
|
## Delete the Instance
|
||||||
|
|
||||||
|
|||||||
@@ -1,138 +1,126 @@
|
|||||||
# Setup a CouchDB server
|
# Setup a CouchDB server
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
- [Configure](#configure)
|
|
||||||
- [Run](#run)
|
- [Setup a CouchDB server](#setup-a-couchdb-server)
|
||||||
- [Docker CLI](#docker-cli)
|
- [Table of Contents](#table-of-contents)
|
||||||
- [Docker Compose](#docker-compose)
|
- [1. Prepare CouchDB](#1-prepare-couchdb)
|
||||||
- [Access from a mobile device](#access-from-a-mobile-device)
|
- [A. Using Docker container](#a-using-docker-container)
|
||||||
- [Testing from a mobile](#testing-from-a-mobile)
|
- [1. Prepare](#1-prepare)
|
||||||
- [Setting up your domain](#setting-up-your-domain)
|
- [2. Run docker container](#2-run-docker-container)
|
||||||
- [Reverse Proxies](#reverse-proxies)
|
- [B. Install CouchDB directly](#b-install-couchdb-directly)
|
||||||
- [Traefik](#traefik)
|
- [2. Run couchdb-init.sh for initialise](#2-run-couchdb-initsh-for-initialise)
|
||||||
|
- [3. Expose CouchDB to the Internet](#3-expose-couchdb-to-the-internet)
|
||||||
|
- [4. Client Setup](#4-client-setup)
|
||||||
|
- [1. Generate the setup URI on a desktop device or server](#1-generate-the-setup-uri-on-a-desktop-device-or-server)
|
||||||
|
- [2. Setup Self-hosted LiveSync to Obsidian](#2-setup-self-hosted-livesync-to-obsidian)
|
||||||
|
- [Manual setup information](#manual-setup-information)
|
||||||
|
- [Setting up your domain](#setting-up-your-domain)
|
||||||
|
- [Reverse Proxies](#reverse-proxies)
|
||||||
|
- [Traefik](#traefik)
|
||||||
---
|
---
|
||||||
|
|
||||||
## Configure
|
## 1. Prepare CouchDB
|
||||||
|
### A. Using Docker container
|
||||||
|
|
||||||
The easiest way to set up a CouchDB instance is using the official [docker image](https://hub.docker.com/_/couchdb).
|
#### 1. Prepare
|
||||||
|
```bash
|
||||||
|
|
||||||
Some initial configuration is required. Create a `local.ini` to use Self-hosted LiveSync as follows ([CouchDB has to be version 3.2 or higher](https://docs.couchdb.org/en/latest/config/http.html#chttpd/enable_cors), if lower `enable_cors = true` has to be under section `[httpd]` ):
|
# Prepare environment variables.
|
||||||
|
export hostname=localhost:5984
|
||||||
|
export username=goojdasjdas #Please change as you like.
|
||||||
|
export password=kpkdasdosakpdsa #Please change as you like
|
||||||
|
|
||||||
```ini
|
# Prepare directories which saving data and configurations.
|
||||||
[couchdb]
|
mkdir couchdb-data
|
||||||
single_node=true
|
mkdir couchdb-etc
|
||||||
max_document_size = 50000000
|
|
||||||
|
|
||||||
[chttpd]
|
|
||||||
require_valid_user = true
|
|
||||||
max_http_request_size = 4294967296
|
|
||||||
enable_cors = true
|
|
||||||
|
|
||||||
[chttpd_auth]
|
|
||||||
require_valid_user = true
|
|
||||||
authentication_redirect = /_utils/session.html
|
|
||||||
|
|
||||||
[httpd]
|
|
||||||
WWW-Authenticate = Basic realm="couchdb"
|
|
||||||
bind_address = 0.0.0.0
|
|
||||||
|
|
||||||
[cors]
|
|
||||||
origins = app://obsidian.md, capacitor://localhost, http://localhost
|
|
||||||
credentials = true
|
|
||||||
headers = accept, authorization, content-type, origin, referer
|
|
||||||
methods = GET,PUT,POST,HEAD,DELETE
|
|
||||||
max_age = 3600
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Run
|
#### 2. Run docker container
|
||||||
|
|
||||||
### Docker CLI
|
1. Boot Check.
|
||||||
|
```
|
||||||
|
$ docker run --name couchdb-for-ols --rm -it -e COUCHDB_USER=${username} -e COUCHDB_PASSWORD=${password} -v ${PWD}/couchdb-data:/opt/couchdb/data -v ${PWD}/couchdb-etc:/opt/couchdb/etc/local.d -p 5984:5984 couchdb
|
||||||
|
```
|
||||||
|
If your container has been exited, please check the permission of couchdb-data, and couchdb-etc.
|
||||||
|
Once CouchDB run, these directories will be owned by uid:`5984`. Please chown it for you again.
|
||||||
|
|
||||||
You can launch CouchDB using your `local.ini` like this:
|
2. Enable it in background
|
||||||
```
|
```
|
||||||
$ docker run --rm -it -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v /path/to/local.ini:/opt/couchdb/etc/local.ini -p 5984:5984 couchdb
|
$ docker run --name couchdb-for-ols -d --restart always -e COUCHDB_USER=${username} -e COUCHDB_PASSWORD=${password} -v ${PWD}/couchdb-data:/opt/couchdb/data -v ${PWD}/couchdb-etc:/opt/couchdb/etc/local.d -p 5984:5984 couchdb
|
||||||
```
|
```
|
||||||
*Remember to replace the path with the path to your local.ini*
|
### B. Install CouchDB directly
|
||||||
|
Please refer the [official document](https://docs.couchdb.org/en/stable/install/index.html). However, we do not have to configure it fully. Just administrator needs to be configured.
|
||||||
|
|
||||||
Run in detached mode:
|
## 2. Run couchdb-init.sh for initialise
|
||||||
```
|
```
|
||||||
$ docker run -d --restart always -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v /path/to/local.ini:/opt/couchdb/etc/local.ini -p 5984:5984 couchdb
|
$ curl -s https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/couchdb/couchdb-init.sh | bash
|
||||||
```
|
|
||||||
*Remember to replace the path with the path to your local.ini*
|
|
||||||
|
|
||||||
### Docker Compose
|
|
||||||
Create a directory, place your `local.ini` within it, and create a `docker-compose.yml` alongside it. Make sure to have write permissions for `local.ini` and the about to be created `data` folder after the container start. The directory structure should look similar to this:
|
|
||||||
```
|
|
||||||
obsidian-livesync
|
|
||||||
├── docker-compose.yml
|
|
||||||
└── local.ini
|
|
||||||
```
|
```
|
||||||
|
|
||||||
A good place to start for `docker-compose.yml`:
|
If it results like following:
|
||||||
```yaml
|
```
|
||||||
version: "2.1"
|
-- Configuring CouchDB by REST APIs... -->
|
||||||
services:
|
{"ok":true}
|
||||||
couchdb:
|
""
|
||||||
image: couchdb
|
""
|
||||||
container_name: obsidian-livesync
|
""
|
||||||
user: 1000:1000
|
""
|
||||||
environment:
|
""
|
||||||
- COUCHDB_USER=admin
|
""
|
||||||
- COUCHDB_PASSWORD=password
|
""
|
||||||
volumes:
|
""
|
||||||
- ./data:/opt/couchdb/data
|
""
|
||||||
- ./local.ini:/opt/couchdb/etc/local.ini
|
<-- Configuring CouchDB by REST APIs Done!
|
||||||
ports:
|
|
||||||
- 5984:5984
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
```
|
||||||
|
|
||||||
And finally launch the container
|
Your CouchDB has been initialised successfully. If you want this manually, please read the script.
|
||||||
|
|
||||||
|
## 3. Expose CouchDB to the Internet
|
||||||
|
|
||||||
|
- You can skip this instruction if you using only in intranet and only with desktop devices.
|
||||||
|
- For mobile devices, Obsidian requires a valid SSL certificate. Usually, it needs exposing the internet.
|
||||||
|
|
||||||
|
Whatever solutions we can use. For the simplicity, following sample uses Cloudflare Zero Trust for testing.
|
||||||
|
|
||||||
```
|
```
|
||||||
# -d will launch detached so the container runs in background
|
$ cloudflared tunnel --url http://localhost:5984
|
||||||
docker compose up -d
|
2024-02-14T10:35:25Z INF Thank you for trying Cloudflare Tunnel. Doing so, without a Cloudflare account, is a quick way to experiment and try it out. However, be aware that these account-less Tunnels have no uptime guarantee. If you intend to use Tunnels in production you should use a pre-created named tunnel by following: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps
|
||||||
|
2024-02-14T10:35:25Z INF Requesting new quick Tunnel on trycloudflare.com...
|
||||||
|
2024-02-14T10:35:26Z INF +--------------------------------------------------------------------------------------------+
|
||||||
|
2024-02-14T10:35:26Z INF | Your quick Tunnel has been created! Visit it at (it may take some time to be reachable): |
|
||||||
|
2024-02-14T10:35:26Z INF | https://tiles-photograph-routine-groundwater.trycloudflare.com |
|
||||||
|
2024-02-14T10:35:26Z INF +--------------------------------------------------------------------------------------------+
|
||||||
|
:
|
||||||
|
:
|
||||||
|
:
|
||||||
|
```
|
||||||
|
Now `https://tiles-photograph-routine-groundwater.trycloudflare.com` is our server. Make it into background once please.
|
||||||
|
|
||||||
|
|
||||||
|
## 4. Client Setup
|
||||||
|
> [!TIP]
|
||||||
|
> Now manually configuration is not recommended for some reasons. However, if you want to do so, please use `Setup wizard`. The recommended extra configurations will be also set.
|
||||||
|
|
||||||
|
### 1. Generate the setup URI on a desktop device or server
|
||||||
|
```bash
|
||||||
|
$ export hostname=https://tiles-photograph-routine-groundwater.trycloudflare.com #Point to your vault
|
||||||
|
$ export database=obsidiannotes #Please change as you like
|
||||||
|
$ export passphrase=dfsapkdjaskdjasdas #Please change as you like
|
||||||
|
$ deno run -A https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/flyio/generate_setupuri.ts
|
||||||
|
obsidian://setuplivesync?settings=%5B%22tm2DpsOE74nJAryprZO2M93wF%2Fvg.......4b26ed33230729%22%5D
|
||||||
```
|
```
|
||||||
|
|
||||||
## Access from a mobile device
|
### 2. Setup Self-hosted LiveSync to Obsidian
|
||||||
If you want to access Self-hosted LiveSync from mobile devices, you need a valid SSL certificate.
|
[This video](https://youtu.be/7sa_I1832Xc?t=146) may help us.
|
||||||
|
1. Install Self-hosted LiveSync
|
||||||
|
2. Choose `Use the copied setup URI` from the command palette and paste the setup URI. (obsidian://setuplivesync?settings=.....).
|
||||||
|
3. Type `welcome` for setup-uri passphrase.
|
||||||
|
4. Answer `yes` and `Set it up...`, and finish the first dialogue with `Keep them disabled`.
|
||||||
|
5. `Reload app without save` once.
|
||||||
|
|
||||||
### Testing from a mobile
|
---
|
||||||
In the testing phase, [localhost.run](https://localhost.run/) or something like services is very useful.
|
|
||||||
|
|
||||||
example using localhost.run:
|
## Manual setup information
|
||||||
```
|
|
||||||
$ ssh -R 80:localhost:5984 nokey@localhost.run
|
|
||||||
Warning: Permanently added the RSA host key for IP address '35.171.254.69' to the list of known hosts.
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
Welcome to localhost.run!
|
|
||||||
|
|
||||||
Follow your favourite reverse tunnel at [https://twitter.com/localhost_run].
|
|
||||||
|
|
||||||
**You need a SSH key to access this service.**
|
|
||||||
If you get a permission denied follow Gitlab's most excellent howto:
|
|
||||||
https://docs.gitlab.com/ee/ssh/
|
|
||||||
*Only rsa and ed25519 keys are supported*
|
|
||||||
|
|
||||||
To set up and manage custom domains go to https://admin.localhost.run/
|
|
||||||
|
|
||||||
More details on custom domains (and how to enable subdomains of your custom
|
|
||||||
domain) at https://localhost.run/docs/custom-domains
|
|
||||||
|
|
||||||
To explore using localhost.run visit the documentation site:
|
|
||||||
https://localhost.run/docs/
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
** your connection id is xxxxxxxxxxxxxxxxxxxxxxxxxxxx, please mention it if you send me a message about an issue. **
|
|
||||||
|
|
||||||
xxxxxxxx.localhost.run tunneled with tls termination, https://xxxxxxxx.localhost.run
|
|
||||||
Connection to localhost.run closed by remote host.
|
|
||||||
Connection to localhost.run closed.
|
|
||||||
```
|
|
||||||
|
|
||||||
https://xxxxxxxx.localhost.run is the temporary server address.
|
|
||||||
|
|
||||||
### Setting up your domain
|
### Setting up your domain
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<!-- -->
|
<!-- 2024-02-15 -->
|
||||||
# Tips and Troubleshooting
|
# Tips and Troubleshooting
|
||||||
|
|
||||||
- [Notable bugs and fixes](#notable-bugs-and-fixes)
|
- [Notable bugs and fixes](#notable-bugs-and-fixes)
|
||||||
|
- [FAQ](#faq)
|
||||||
- [Troubleshooting](#troubleshooting)
|
- [Troubleshooting](#troubleshooting)
|
||||||
- [Tips](#tips)
|
- [Tips](#tips)
|
||||||
<!-- - -->
|
<!-- - -->
|
||||||
@@ -11,7 +12,32 @@
|
|||||||
### Binary files get bigger on iOS
|
### Binary files get bigger on iOS
|
||||||
- Reported at: v0.20.x
|
- Reported at: v0.20.x
|
||||||
- Fixed at: v0.21.2 (Fixed but not reviewed)
|
- Fixed at: v0.21.2 (Fixed but not reviewed)
|
||||||
- Required action: larger files will not be fixed automatically.
|
- Required action: larger files will not be fixed automatically, please perform `Verify and repair all files`. If our local database and storage are not matched, we will be asked to apply which one.
|
||||||
|
|
||||||
|
### Some setting name has been changed
|
||||||
|
- Fixed at: v0.22.6
|
||||||
|
|
||||||
|
| Previous name | New name |
|
||||||
|
| ---------------------------- | ---------------------------------------- |
|
||||||
|
| Open setup URI | Use the copied setup URI |
|
||||||
|
| Copy setup URI | Copy current settings as a new setup URI |
|
||||||
|
| Setup Wizard | Minimal Setup |
|
||||||
|
| Check database configuration | Check and Fix database configuration |
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### Why `Use an old adapter for compatibility` is somehow enabled in my vault?
|
||||||
|
|
||||||
|
Because you are a compassionate and experienced user. Before v0.17.16, we used an old adapter for the local database. At that time, current default adapter has not been stable.
|
||||||
|
The new adapter has better performance and has a new feature like purging. Therefore, we should use new adapters and current default is so.
|
||||||
|
|
||||||
|
However, when switching from an old adapter to a new adapter, some converting or local database rebuilding is required, and it takes a few time. It was a long time ago now, but we once inconvenienced everyone in a hurry when we changed the format of our database.
|
||||||
|
For these reasons, this toggle is automatically on if we have upgraded from vault which using an old adapter.
|
||||||
|
|
||||||
|
When you rebuild everything or fetch from the remote again, you will be asked to switch this.
|
||||||
|
|
||||||
|
Therefore, experienced users (especially those stable enough not to have to rebuild the database) may have this toggle enabled in their Vault.
|
||||||
|
Please disable it when you have enough time.
|
||||||
|
|
||||||
<!-- Add here -->
|
<!-- Add here -->
|
||||||
|
|
||||||
@@ -20,6 +46,7 @@
|
|||||||
|
|
||||||
## Tips
|
## Tips
|
||||||
<!-- Add here -->
|
<!-- Add here -->
|
||||||
|
|
||||||
### Old tips
|
### Old tips
|
||||||
- If a folder becomes empty after a replication, it will be deleted by default. But you can toggle this behaviour. Check the [Settings](settings.md).
|
- If a folder becomes empty after a replication, it will be deleted by default. But you can toggle this behaviour. Check the [Settings](settings.md).
|
||||||
- LiveSync mode drains more batteries in mobile devices. Periodic sync with some automatic sync is recommended.
|
- LiveSync mode drains more batteries in mobile devices. Periodic sync with some automatic sync is recommended.
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "obsidian-livesync",
|
"id": "obsidian-livesync",
|
||||||
"name": "Self-hosted LiveSync",
|
"name": "Self-hosted LiveSync",
|
||||||
"version": "0.22.5",
|
"version": "0.22.6",
|
||||||
"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",
|
||||||
|
|||||||
32
package-lock.json
generated
32
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.22.5",
|
"version": "0.22.6",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.22.5",
|
"version": "0.22.6",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"diff-match-patch": "^1.0.5",
|
"diff-match-patch": "^1.0.5",
|
||||||
@@ -3077,9 +3077,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3376,9 +3376,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.27",
|
"version": "8.4.35",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
|
||||||
"integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
|
"integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3395,7 +3395,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
@@ -6817,9 +6817,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"natural-compare": {
|
"natural-compare": {
|
||||||
@@ -7026,12 +7026,12 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "8.4.27",
|
"version": "8.4.35",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
|
||||||
"integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
|
"integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.22.5",
|
"version": "0.22.6",
|
||||||
"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",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
|||||||
import { askSelectString, askYesNo, askString } from "./utils";
|
import { askSelectString, askYesNo, askString } from "./utils";
|
||||||
import { decrypt, encrypt } from "./lib/src/e2ee_v2";
|
import { decrypt, encrypt } from "./lib/src/e2ee_v2";
|
||||||
import { LiveSyncCommands } from "./LiveSyncCommands";
|
import { LiveSyncCommands } from "./LiveSyncCommands";
|
||||||
import { delay } from "./lib/src/utils";
|
import { delay, fireAndForget } from "./lib/src/utils";
|
||||||
import { confirmWithMessage } from "./dialogs";
|
import { confirmWithMessage } from "./dialogs";
|
||||||
import { Platform } from "./deps";
|
import { Platform } from "./deps";
|
||||||
import { fetchAllUsedChunks } from "./lib/src/utils_couchdb";
|
import { fetchAllUsedChunks } from "./lib/src/utils_couchdb";
|
||||||
@@ -17,25 +17,25 @@ export class SetupLiveSync extends LiveSyncCommands {
|
|||||||
|
|
||||||
this.plugin.addCommand({
|
this.plugin.addCommand({
|
||||||
id: "livesync-copysetupuri",
|
id: "livesync-copysetupuri",
|
||||||
name: "Copy the setup URI",
|
name: "Copy settings as a new setup URI",
|
||||||
callback: this.command_copySetupURI.bind(this),
|
callback: () => fireAndForget(this.command_copySetupURI()),
|
||||||
});
|
});
|
||||||
this.plugin.addCommand({
|
this.plugin.addCommand({
|
||||||
id: "livesync-copysetupuri-short",
|
id: "livesync-copysetupuri-short",
|
||||||
name: "Copy the setup URI (With customization sync)",
|
name: "Copy settings as a new setup URI (With customization sync)",
|
||||||
callback: this.command_copySetupURIWithSync.bind(this),
|
callback: () => fireAndForget(this.command_copySetupURIWithSync()),
|
||||||
});
|
});
|
||||||
|
|
||||||
this.plugin.addCommand({
|
this.plugin.addCommand({
|
||||||
id: "livesync-copysetupurifull",
|
id: "livesync-copysetupurifull",
|
||||||
name: "Copy the setup URI (Full)",
|
name: "Copy settings as a new setup URI (Full)",
|
||||||
callback: this.command_copySetupURIFull.bind(this),
|
callback: () => fireAndForget(this.command_copySetupURIFull()),
|
||||||
});
|
});
|
||||||
|
|
||||||
this.plugin.addCommand({
|
this.plugin.addCommand({
|
||||||
id: "livesync-opensetupuri",
|
id: "livesync-opensetupuri",
|
||||||
name: "Open the setup URI",
|
name: "Use the copied setup URI (Formerly Open setup URI)",
|
||||||
callback: this.command_openSetupURI.bind(this),
|
callback: () => fireAndForget(this.command_openSetupURI()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onInitializeDatabase(showNotice: boolean) { }
|
onInitializeDatabase(showNotice: boolean) { }
|
||||||
@@ -76,7 +76,7 @@ export class SetupLiveSync extends LiveSyncCommands {
|
|||||||
Logger("Setup URI copied to clipboard", LOG_LEVEL_NOTICE);
|
Logger("Setup URI copied to clipboard", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
async command_copySetupURIWithSync() {
|
async command_copySetupURIWithSync() {
|
||||||
this.command_copySetupURI(false);
|
await this.command_copySetupURI(false);
|
||||||
}
|
}
|
||||||
async command_openSetupURI() {
|
async command_openSetupURI() {
|
||||||
const setupURI = await askString(this.app, "Easy setup", "Set up URI", `${configURIBase}aaaaa`);
|
const setupURI = await askString(this.app, "Easy setup", "Set up URI", `${configURIBase}aaaaa`);
|
||||||
@@ -108,6 +108,7 @@ export class SetupLiveSync extends LiveSyncCommands {
|
|||||||
newSettingW.configPassphraseStore = "";
|
newSettingW.configPassphraseStore = "";
|
||||||
newSettingW.encryptedPassphrase = "";
|
newSettingW.encryptedPassphrase = "";
|
||||||
newSettingW.encryptedCouchDBConnection = "";
|
newSettingW.encryptedCouchDBConnection = "";
|
||||||
|
newSettingW.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}`
|
||||||
const setupJustImport = "Just import setting";
|
const setupJustImport = "Just import setting";
|
||||||
const setupAsNew = "Set it up as secondary or subsequent device";
|
const setupAsNew = "Set it up as secondary or subsequent device";
|
||||||
const setupAsMerge = "Secondary device but try keeping local changes";
|
const setupAsMerge = "Secondary device but try keeping local changes";
|
||||||
@@ -115,6 +116,7 @@ export class SetupLiveSync extends LiveSyncCommands {
|
|||||||
const setupManually = "Leave everything to me";
|
const setupManually = "Leave everything to me";
|
||||||
newSettingW.syncInternalFiles = false;
|
newSettingW.syncInternalFiles = false;
|
||||||
newSettingW.usePluginSync = false;
|
newSettingW.usePluginSync = false;
|
||||||
|
newSettingW.isConfigured = true;
|
||||||
// Migrate completely obsoleted configuration.
|
// Migrate completely obsoleted configuration.
|
||||||
if (!newSettingW.useIndexedDBAdapter) {
|
if (!newSettingW.useIndexedDBAdapter) {
|
||||||
newSettingW.useIndexedDBAdapter = true;
|
newSettingW.useIndexedDBAdapter = true;
|
||||||
@@ -333,10 +335,18 @@ Of course, we are able to disable these features.`
|
|||||||
|
|
||||||
const ret = await confirmWithMessage(this.plugin, "Database adapter", message, choices, CHOICE_YES, 10);
|
const ret = await confirmWithMessage(this.plugin, "Database adapter", message, choices, CHOICE_YES, 10);
|
||||||
if (ret == CHOICE_YES) {
|
if (ret == CHOICE_YES) {
|
||||||
this.plugin.settings.useIndexedDBAdapter = false;
|
this.plugin.settings.useIndexedDBAdapter = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async resetLocalDatabase() {
|
||||||
|
if (this.plugin.settings.isConfigured && this.plugin.settings.additionalSuffixOfDatabaseName == "") {
|
||||||
|
// Discard the non-suffixed database
|
||||||
|
await this.plugin.resetLocalDatabase();
|
||||||
|
}
|
||||||
|
this.plugin.settings.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}`
|
||||||
|
await this.plugin.resetLocalDatabase();
|
||||||
|
}
|
||||||
async fetchRemoteChunks() {
|
async fetchRemoteChunks() {
|
||||||
if (!this.plugin.settings.doNotSuspendOnFetching && this.plugin.settings.readChunksOnline) {
|
if (!this.plugin.settings.doNotSuspendOnFetching && this.plugin.settings.readChunksOnline) {
|
||||||
Logger(`Fetching chunks`, LOG_LEVEL_NOTICE);
|
Logger(`Fetching chunks`, LOG_LEVEL_NOTICE);
|
||||||
@@ -351,10 +361,11 @@ Of course, we are able to disable these features.`
|
|||||||
}
|
}
|
||||||
async fetchLocal() {
|
async fetchLocal() {
|
||||||
this.suspendExtraSync();
|
this.suspendExtraSync();
|
||||||
this.askUseNewAdapter();
|
await this.askUseNewAdapter();
|
||||||
|
this.plugin.settings.isConfigured = true;
|
||||||
await this.suspendReflectingDatabase();
|
await this.suspendReflectingDatabase();
|
||||||
await this.plugin.realizeSettingSyncMode();
|
await this.plugin.realizeSettingSyncMode();
|
||||||
await this.plugin.resetLocalDatabase();
|
await this.resetLocalDatabase();
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await this.plugin.markRemoteResolved();
|
await this.plugin.markRemoteResolved();
|
||||||
await this.plugin.openDatabase();
|
await this.plugin.openDatabase();
|
||||||
@@ -369,10 +380,11 @@ Of course, we are able to disable these features.`
|
|||||||
}
|
}
|
||||||
async fetchLocalWithKeepLocal() {
|
async fetchLocalWithKeepLocal() {
|
||||||
this.suspendExtraSync();
|
this.suspendExtraSync();
|
||||||
this.askUseNewAdapter();
|
await this.askUseNewAdapter();
|
||||||
|
this.plugin.settings.isConfigured = true;
|
||||||
await this.suspendReflectingDatabase();
|
await this.suspendReflectingDatabase();
|
||||||
await this.plugin.realizeSettingSyncMode();
|
await this.plugin.realizeSettingSyncMode();
|
||||||
await this.plugin.resetLocalDatabase();
|
await this.resetLocalDatabase();
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await this.plugin.initializeDatabase(true);
|
await this.plugin.initializeDatabase(true);
|
||||||
await this.plugin.markRemoteResolved();
|
await this.plugin.markRemoteResolved();
|
||||||
@@ -388,6 +400,7 @@ Of course, we are able to disable these features.`
|
|||||||
}
|
}
|
||||||
async rebuildRemote() {
|
async rebuildRemote() {
|
||||||
this.suspendExtraSync();
|
this.suspendExtraSync();
|
||||||
|
this.plugin.settings.isConfigured = true;
|
||||||
await this.plugin.realizeSettingSyncMode();
|
await this.plugin.realizeSettingSyncMode();
|
||||||
await this.plugin.markRemoteLocked();
|
await this.plugin.markRemoteLocked();
|
||||||
await this.plugin.tryResetRemoteDatabase();
|
await this.plugin.tryResetRemoteDatabase();
|
||||||
@@ -401,9 +414,10 @@ Of course, we are able to disable these features.`
|
|||||||
}
|
}
|
||||||
async rebuildEverything() {
|
async rebuildEverything() {
|
||||||
this.suspendExtraSync();
|
this.suspendExtraSync();
|
||||||
this.askUseNewAdapter();
|
await this.askUseNewAdapter();
|
||||||
|
this.plugin.settings.isConfigured = true;
|
||||||
await this.plugin.realizeSettingSyncMode();
|
await this.plugin.realizeSettingSyncMode();
|
||||||
await this.plugin.resetLocalDatabase();
|
await this.resetLocalDatabase();
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await this.plugin.initializeDatabase(true);
|
await this.plugin.initializeDatabase(true);
|
||||||
await this.plugin.markRemoteLocked();
|
await this.plugin.markRemoteLocked();
|
||||||
|
|||||||
@@ -26,6 +26,18 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
}
|
}
|
||||||
this.plugin.addLog(`Connected to ${db.info.db_name}`, LOG_LEVEL_NOTICE);
|
this.plugin.addLog(`Connected to ${db.info.db_name}`, LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
|
askReload() {
|
||||||
|
scheduleTask("configReload", 250, async () => {
|
||||||
|
if (await askYesNo(this.app, "Do you want to restart and reload Obsidian now?") == "yes") {
|
||||||
|
// @ts-ignore
|
||||||
|
this.app.commands.executeCommandById("app:reload")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
closeSetting() {
|
||||||
|
// @ts-ignore
|
||||||
|
this.plugin.app.setting.close()
|
||||||
|
}
|
||||||
display(): void {
|
display(): void {
|
||||||
const { containerEl } = this;
|
const { containerEl } = this;
|
||||||
let encrypt = this.plugin.settings.encrypt;
|
let encrypt = this.plugin.settings.encrypt;
|
||||||
@@ -136,29 +148,27 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
const setupWizardEl = containerEl.createDiv();
|
const setupWizardEl = containerEl.createDiv();
|
||||||
setupWizardEl.createEl("h3", { text: "Setup wizard" });
|
setupWizardEl.createEl("h3", { text: "Setup wizard" });
|
||||||
new Setting(setupWizardEl)
|
new Setting(setupWizardEl)
|
||||||
.setName("Discard the existing configuration and set up")
|
.setName("Use the copied setup URI")
|
||||||
|
.setDesc("To setup Self-hosted LiveSync, this method is the most preferred one.")
|
||||||
.addButton((text) => {
|
.addButton((text) => {
|
||||||
// eslint-disable-next-line require-await
|
text.setButtonText("Use").onClick(async () => {
|
||||||
text.setButtonText("Next").onClick(async () => {
|
this.closeSetting();
|
||||||
if (JSON.stringify(this.plugin.settings) != JSON.stringify(DEFAULT_SETTINGS)) {
|
await this.plugin.addOnSetup.command_openSetupURI();
|
||||||
this.plugin.replicator.closeReplication();
|
|
||||||
this.plugin.settings = { ...DEFAULT_SETTINGS };
|
|
||||||
this.plugin.saveSettings();
|
|
||||||
Logger("Configuration has been flushed, please open it again", LOG_LEVEL_NOTICE)
|
|
||||||
// @ts-ignore
|
|
||||||
this.plugin.app.setting.close()
|
|
||||||
} else {
|
|
||||||
containerEl.addClass("isWizard");
|
|
||||||
applyDisplayEnabled();
|
|
||||||
inWizard = true;
|
|
||||||
changeDisplay("0")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
if (this.plugin.settings.isConfigured) {
|
||||||
|
new Setting(setupWizardEl)
|
||||||
|
.setName("Copy current settings as a new setup URI")
|
||||||
|
.addButton((text) => {
|
||||||
|
text.setButtonText("Copy").onClick(async () => {
|
||||||
|
await this.plugin.addOnSetup.command_copySetupURI();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
new Setting(setupWizardEl)
|
new Setting(setupWizardEl)
|
||||||
.setName("Do not discard the existing configuration and set up again")
|
.setName("Minimal setup")
|
||||||
.addButton((text) => {
|
.addButton((text) => {
|
||||||
text.setButtonText("Next").onClick(async () => {
|
text.setButtonText("Start").onClick(async () => {
|
||||||
this.plugin.settings.liveSync = false;
|
this.plugin.settings.liveSync = false;
|
||||||
this.plugin.settings.periodicReplication = false;
|
this.plugin.settings.periodicReplication = false;
|
||||||
this.plugin.settings.syncOnSave = false;
|
this.plugin.settings.syncOnSave = false;
|
||||||
@@ -172,27 +182,34 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
applyDisplayEnabled();
|
applyDisplayEnabled();
|
||||||
inWizard = true;
|
inWizard = true;
|
||||||
changeDisplay("0")
|
changeDisplay("0")
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const infoWarnForSubsequent = setupWizardEl.createEl("div", { text: `To set up second or subsequent device, please use 'Copy setup URI' and 'Open setup URI'` });
|
if (!this.plugin.settings.isConfigured) {
|
||||||
infoWarnForSubsequent.addClass("op-warn-info");
|
new Setting(setupWizardEl)
|
||||||
new Setting(setupWizardEl)
|
.setName("Enable LiveSync on this device as the set-up was completed manually")
|
||||||
.setName("Copy setup URI")
|
.addButton((text) => {
|
||||||
.addButton((text) => {
|
text.setButtonText("Enable").onClick(async () => {
|
||||||
text.setButtonText("Copy setup URI").onClick(() => {
|
this.plugin.settings.isConfigured = true;
|
||||||
// @ts-ignore
|
await this.plugin.saveSettings();
|
||||||
this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-copysetupuri")
|
this.askReload();
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
.addButton((text) => {
|
if (this.plugin.settings.isConfigured) {
|
||||||
text.setButtonText("Open setup URI").onClick(() => {
|
new Setting(setupWizardEl)
|
||||||
// @ts-ignore
|
.setName("Discard exist settings and databases")
|
||||||
this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-opensetupuri")
|
.addButton((text) => {
|
||||||
|
text.setButtonText("Discard").onClick(async () => {
|
||||||
|
if (await askYesNo(this.plugin.app, "Do you really want to discard exist settings and databases?") == "yes") {
|
||||||
|
this.plugin.settings = { ...DEFAULT_SETTINGS };
|
||||||
|
await this.plugin.saveSettingData();
|
||||||
|
await this.plugin.resetLocalDatabase();
|
||||||
|
// await this.plugin.initializeDatabase();
|
||||||
|
this.askReload();
|
||||||
|
}
|
||||||
|
}).setWarning()
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
setupWizardEl.createEl("h3", { text: "Online Tips" });
|
setupWizardEl.createEl("h3", { text: "Online Tips" });
|
||||||
const repo = "vrtmrz/obsidian-livesync";
|
const repo = "vrtmrz/obsidian-livesync";
|
||||||
const topPath = "/docs/troubleshooting.md";
|
const topPath = "/docs/troubleshooting.md";
|
||||||
@@ -338,6 +355,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
|
|
||||||
new Setting(containerRemoteDatabaseEl)
|
new Setting(containerRemoteDatabaseEl)
|
||||||
.setName("Test Database Connection")
|
.setName("Test Database Connection")
|
||||||
|
.setClass("wizardHidden")
|
||||||
.setDesc("Open database connection. If the remote database is not found and you have the privilege to create a database, the database will be created.")
|
.setDesc("Open database connection. If the remote database is not found and you have the privilege to create a database, the database will be created.")
|
||||||
.addButton((button) =>
|
.addButton((button) =>
|
||||||
button
|
button
|
||||||
@@ -349,8 +367,8 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
);
|
);
|
||||||
|
|
||||||
new Setting(containerRemoteDatabaseEl)
|
new Setting(containerRemoteDatabaseEl)
|
||||||
.setName("Check database configuration")
|
.setName("Check and Fix database configuration")
|
||||||
// .setDesc("Open database connection. If the remote database is not found and you have the privilege to create a database, the database will be created.")
|
.setDesc("Check the database configuration, and fix if there are any problems.")
|
||||||
.addButton((button) =>
|
.addButton((button) =>
|
||||||
button
|
button
|
||||||
.setButtonText("Check")
|
.setButtonText("Check")
|
||||||
@@ -557,18 +575,18 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
passphraseSetting?.controlEl.toggleClass("sls-item-dirty", passphrase != this.plugin.settings.passphrase);
|
passphraseSetting?.controlEl.toggleClass("sls-item-dirty", passphrase != this.plugin.settings.passphrase);
|
||||||
dynamicIteration?.controlEl.toggleClass("sls-item-dirty", useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount);
|
dynamicIteration?.controlEl.toggleClass("sls-item-dirty", useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount);
|
||||||
usePathObfuscationEl?.controlEl.toggleClass("sls-item-dirty", usePathObfuscation != this.plugin.settings.usePathObfuscation);
|
usePathObfuscationEl?.controlEl.toggleClass("sls-item-dirty", usePathObfuscation != this.plugin.settings.usePathObfuscation);
|
||||||
if (encrypt != this.plugin.settings.encrypt ||
|
|
||||||
passphrase != this.plugin.settings.passphrase ||
|
|
||||||
useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount ||
|
|
||||||
usePathObfuscation != this.plugin.settings.usePathObfuscation) {
|
|
||||||
applyE2EButtons.settingEl.removeClass("sls-setting-hidden");
|
|
||||||
} else {
|
|
||||||
applyE2EButtons.settingEl.addClass("sls-setting-hidden");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
passphraseSetting.settingEl.addClass("sls-setting-hidden");
|
passphraseSetting.settingEl.addClass("sls-setting-hidden");
|
||||||
dynamicIteration.settingEl.addClass("sls-setting-hidden");
|
dynamicIteration.settingEl.addClass("sls-setting-hidden");
|
||||||
usePathObfuscationEl.settingEl.addClass("sls-setting-hidden");
|
usePathObfuscationEl.settingEl.addClass("sls-setting-hidden");
|
||||||
|
}
|
||||||
|
if (encrypt != this.plugin.settings.encrypt ||
|
||||||
|
passphrase != this.plugin.settings.passphrase ||
|
||||||
|
useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount ||
|
||||||
|
usePathObfuscation != this.plugin.settings.usePathObfuscation) {
|
||||||
|
applyE2EButtons.settingEl.removeClass("sls-setting-hidden");
|
||||||
|
} else {
|
||||||
applyE2EButtons.settingEl.addClass("sls-setting-hidden");
|
applyE2EButtons.settingEl.addClass("sls-setting-hidden");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -703,6 +721,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
this.plugin.settings.passphrase = passphrase;
|
this.plugin.settings.passphrase = passphrase;
|
||||||
this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount;
|
this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount;
|
||||||
this.plugin.settings.usePathObfuscation = usePathObfuscation;
|
this.plugin.settings.usePathObfuscation = usePathObfuscation;
|
||||||
|
this.plugin.settings.isConfigured = true;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
updateE2EControls();
|
updateE2EControls();
|
||||||
if (sendToServer) {
|
if (sendToServer) {
|
||||||
@@ -731,26 +750,23 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
this.plugin.settings.passphrase = passphrase;
|
this.plugin.settings.passphrase = passphrase;
|
||||||
this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount;
|
this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount;
|
||||||
this.plugin.settings.usePathObfuscation = usePathObfuscation;
|
this.plugin.settings.usePathObfuscation = usePathObfuscation;
|
||||||
|
this.plugin.settings.isConfigured = true;
|
||||||
Logger("All synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL_NOTICE)
|
Logger("All synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL_NOTICE)
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
updateE2EControls();
|
updateE2EControls();
|
||||||
applyDisplayEnabled();
|
applyDisplayEnabled();
|
||||||
// @ts-ignore
|
this.closeSetting();
|
||||||
this.plugin.app.setting.close();
|
|
||||||
await delay(2000);
|
await delay(2000);
|
||||||
await performRebuildDB(this.plugin, method);
|
await performRebuildDB(this.plugin, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let rebuildRemote = false;
|
|
||||||
|
|
||||||
new Setting(containerRemoteDatabaseEl)
|
new Setting(containerRemoteDatabaseEl)
|
||||||
.setName("")
|
|
||||||
.setClass("wizardOnly")
|
.setClass("wizardOnly")
|
||||||
.addButton((button) =>
|
.addButton((button) =>
|
||||||
button
|
button
|
||||||
.setButtonText("Next")
|
.setButtonText("Next")
|
||||||
.setClass("mod-cta")
|
.setCta()
|
||||||
.setDisabled(false)
|
.setDisabled(false)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
if (!this.plugin.settings.encrypt) {
|
if (!this.plugin.settings.encrypt) {
|
||||||
@@ -759,33 +775,13 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
if (isCloudantURI(this.plugin.settings.couchDB_URI)) {
|
if (isCloudantURI(this.plugin.settings.couchDB_URI)) {
|
||||||
this.plugin.settings.customChunkSize = 0;
|
this.plugin.settings.customChunkSize = 0;
|
||||||
} else {
|
} else {
|
||||||
this.plugin.settings.customChunkSize = 100;
|
this.plugin.settings.customChunkSize = 50;
|
||||||
}
|
}
|
||||||
rebuildRemote = false;
|
|
||||||
changeDisplay("30")
|
changeDisplay("30")
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
new Setting(containerRemoteDatabaseEl)
|
;
|
||||||
.setName("")
|
|
||||||
.setClass("wizardOnly")
|
|
||||||
.addButton((button) =>
|
|
||||||
button
|
|
||||||
.setButtonText("Discard existing database and proceed")
|
|
||||||
.setDisabled(false)
|
|
||||||
.setWarning()
|
|
||||||
.onClick(() => {
|
|
||||||
if (!this.plugin.settings.encrypt) {
|
|
||||||
this.plugin.settings.passphrase = "";
|
|
||||||
}
|
|
||||||
if (isCloudantURI(this.plugin.settings.couchDB_URI)) {
|
|
||||||
this.plugin.settings.customChunkSize = 0;
|
|
||||||
} else {
|
|
||||||
this.plugin.settings.customChunkSize = 100;
|
|
||||||
}
|
|
||||||
rebuildRemote = true;
|
|
||||||
changeDisplay("30")
|
|
||||||
})
|
|
||||||
);
|
|
||||||
addScreenElement("0", containerRemoteDatabaseEl);
|
addScreenElement("0", containerRemoteDatabaseEl);
|
||||||
|
|
||||||
const containerGeneralSettingsEl = containerEl.createDiv();
|
const containerGeneralSettingsEl = containerEl.createDiv();
|
||||||
@@ -1049,25 +1045,20 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
...presetAllDisabled
|
...presetAllDisabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
this.display();
|
this.display();
|
||||||
await this.plugin.realizeSettingSyncMode();
|
await this.plugin.realizeSettingSyncMode();
|
||||||
if (inWizard) {
|
if (inWizard) {
|
||||||
// @ts-ignore
|
this.closeSetting();
|
||||||
this.plugin.app.setting.close()
|
if (!this.plugin.settings.isConfigured) {
|
||||||
await this.plugin.resetLocalDatabase();
|
this.plugin.settings.isConfigured = true;
|
||||||
await this.plugin.initializeDatabase(true);
|
await this.plugin.saveSettings();
|
||||||
if (rebuildRemote) {
|
await rebuildDB("localOnly");
|
||||||
await this.plugin.markRemoteLocked();
|
Logger("All done! Please set up subsequent devices with 'Copy current settings as a new setup URI' and 'Use the copied setup URI'.", LOG_LEVEL_NOTICE);
|
||||||
await this.plugin.tryResetRemoteDatabase();
|
await this.plugin.addOnSetup.command_openSetupURI();
|
||||||
await this.plugin.markRemoteLocked();
|
} else {
|
||||||
await this.plugin.markRemoteResolved();
|
this.askReload();
|
||||||
}
|
}
|
||||||
await this.plugin.replicate(true);
|
|
||||||
|
|
||||||
Logger("All done! Please set up subsequent devices with 'Copy setup URI' and 'Open setup URI'.", LOG_LEVEL_NOTICE);
|
|
||||||
// @ts-ignore
|
|
||||||
this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-copysetupuri")
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -1286,24 +1277,21 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
|||||||
.addButton((button) => {
|
.addButton((button) => {
|
||||||
button.setButtonText("Merge")
|
button.setButtonText("Merge")
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
// @ts-ignore
|
this.closeSetting()
|
||||||
this.plugin.app.setting.close()
|
|
||||||
await this.plugin.addOnSetup.configureHiddenFileSync("MERGE");
|
await this.plugin.addOnSetup.configureHiddenFileSync("MERGE");
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.addButton((button) => {
|
.addButton((button) => {
|
||||||
button.setButtonText("Fetch")
|
button.setButtonText("Fetch")
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
// @ts-ignore
|
this.closeSetting()
|
||||||
this.plugin.app.setting.close()
|
|
||||||
await this.plugin.addOnSetup.configureHiddenFileSync("FETCH");
|
await this.plugin.addOnSetup.configureHiddenFileSync("FETCH");
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.addButton((button) => {
|
.addButton((button) => {
|
||||||
button.setButtonText("Overwrite")
|
button.setButtonText("Overwrite")
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
// @ts-ignore
|
this.closeSetting()
|
||||||
this.plugin.app.setting.close()
|
|
||||||
await this.plugin.addOnSetup.configureHiddenFileSync("OVERWRITE");
|
await this.plugin.addOnSetup.configureHiddenFileSync("OVERWRITE");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -1694,6 +1682,18 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
c.addClass("op-warn");
|
c.addClass("op-warn");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new Setting(containerHatchEl)
|
||||||
|
.setName("Back to non-configured")
|
||||||
|
.addButton((button) =>
|
||||||
|
button
|
||||||
|
.setButtonText("Back")
|
||||||
|
.setDisabled(false)
|
||||||
|
.onClick(async () => {
|
||||||
|
this.plugin.settings.isConfigured = false;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
this.askReload();
|
||||||
|
}));
|
||||||
const hatchWarn = containerHatchEl.createEl("div", { text: `To stop the boot up sequence for fixing problems on databases, you can put redflag.md on top of your vault (Rebooting obsidian is required).` });
|
const hatchWarn = containerHatchEl.createEl("div", { text: `To stop the boot up sequence for fixing problems on databases, you can put redflag.md on top of your vault (Rebooting obsidian is required).` });
|
||||||
hatchWarn.addClass("op-warn-info");
|
hatchWarn.addClass("op-warn-info");
|
||||||
|
|
||||||
@@ -1844,12 +1844,7 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
toggle.setValue(this.plugin.settings.suspendFileWatching).onChange(async (value) => {
|
toggle.setValue(this.plugin.settings.suspendFileWatching).onChange(async (value) => {
|
||||||
this.plugin.settings.suspendFileWatching = value;
|
this.plugin.settings.suspendFileWatching = value;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
scheduleTask("configReload", 250, async () => {
|
this.askReload();
|
||||||
if (await askYesNo(this.app, "Do you want to restart and reload Obsidian now?") == "yes") {
|
|
||||||
// @ts-ignore
|
|
||||||
this.app.commands.executeCommandById("app:reload")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
new Setting(containerHatchEl)
|
new Setting(containerHatchEl)
|
||||||
@@ -1859,12 +1854,7 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
toggle.setValue(this.plugin.settings.suspendParseReplicationResult).onChange(async (value) => {
|
toggle.setValue(this.plugin.settings.suspendParseReplicationResult).onChange(async (value) => {
|
||||||
this.plugin.settings.suspendParseReplicationResult = value;
|
this.plugin.settings.suspendParseReplicationResult = value;
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
scheduleTask("configReload", 250, async () => {
|
this.askReload();
|
||||||
if (await askYesNo(this.app, "Do you want to restart and reload Obsidian now?") == "yes") {
|
|
||||||
// @ts-ignore
|
|
||||||
this.app.commands.executeCommandById("app:reload")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
new Setting(containerHatchEl)
|
new Setting(containerHatchEl)
|
||||||
@@ -1949,7 +1939,7 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
let newDatabaseName = this.plugin.settings.additionalSuffixOfDatabaseName + "";
|
let newDatabaseName = this.plugin.settings.additionalSuffixOfDatabaseName + "";
|
||||||
new Setting(containerHatchEl)
|
new Setting(containerHatchEl)
|
||||||
.setName("Database suffix")
|
.setName("Database suffix")
|
||||||
.setDesc("LiveSync could not treat multiple vaults which have same name, please add some suffix from here.")
|
.setDesc("LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.")
|
||||||
.addText((text) => {
|
.addText((text) => {
|
||||||
text.setPlaceholder("")
|
text.setPlaceholder("")
|
||||||
.setValue(newDatabaseName)
|
.setValue(newDatabaseName)
|
||||||
@@ -2163,8 +2153,7 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
.setDisabled(false)
|
.setDisabled(false)
|
||||||
.setWarning()
|
.setWarning()
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
// @ts-ignore
|
this.closeSetting()
|
||||||
this.plugin.app.setting.close()
|
|
||||||
await this.plugin.dbGC();
|
await this.plugin.dbGC();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -2186,7 +2175,7 @@ ${stringifyYaml(pluginConfig)}`;
|
|||||||
applyDisplayEnabled();
|
applyDisplayEnabled();
|
||||||
if (this.selectedScreen == "") {
|
if (this.selectedScreen == "") {
|
||||||
if (lastVersion != this.plugin.settings.lastReadUpdates) {
|
if (lastVersion != this.plugin.settings.lastReadUpdates) {
|
||||||
if (JSON.stringify(this.plugin.settings) != JSON.stringify(DEFAULT_SETTINGS)) {
|
if (this.plugin.settings.isConfigured) {
|
||||||
changeDisplay("100");
|
changeDisplay("100");
|
||||||
} else {
|
} else {
|
||||||
changeDisplay("110")
|
changeDisplay("110")
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
}
|
}
|
||||||
// Cache file and waiting to can be proceed.
|
// Cache file and waiting to can be proceed.
|
||||||
async appendWatchEvent(params: { type: FileEventType, file: TAbstractFile | InternalFileInfo, oldPath?: string }[], ctx?: any) {
|
async appendWatchEvent(params: { type: FileEventType, file: TAbstractFile | InternalFileInfo, oldPath?: string }[], ctx?: any) {
|
||||||
|
if (!this.plugin.settings.isConfigured) return;
|
||||||
|
if (this.plugin.settings.suspendFileWatching) return;
|
||||||
for (const param of params) {
|
for (const param of params) {
|
||||||
if (shouldBeIgnored(param.file.path)) {
|
if (shouldBeIgnored(param.file.path)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -106,7 +108,6 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
}
|
}
|
||||||
if (file instanceof TFolder) continue;
|
if (file instanceof TFolder) continue;
|
||||||
if (!await this.plugin.isTargetFile(file.path)) continue;
|
if (!await this.plugin.isTargetFile(file.path)) continue;
|
||||||
if (this.plugin.settings.suspendFileWatching) continue;
|
|
||||||
|
|
||||||
let cache: null | string | ArrayBuffer;
|
let cache: null | string | ArrayBuffer;
|
||||||
// new file or something changed, cache the changes.
|
// new file or something changed, cache the changes.
|
||||||
|
|||||||
2
src/lib
2
src/lib
Submodule src/lib updated: 71d28f285d...46256dba3a
89
src/main.ts
89
src/main.ts
@@ -76,7 +76,13 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
replicator!: LiveSyncDBReplicator;
|
replicator!: LiveSyncDBReplicator;
|
||||||
|
|
||||||
statusBar?: HTMLElement;
|
statusBar?: HTMLElement;
|
||||||
suspended = false;
|
_suspended = false;
|
||||||
|
get suspended() {
|
||||||
|
return this._suspended || !this.settings?.isConfigured;
|
||||||
|
}
|
||||||
|
set suspended(value: boolean) {
|
||||||
|
this._suspended = value;
|
||||||
|
}
|
||||||
deviceAndVaultName = "";
|
deviceAndVaultName = "";
|
||||||
isMobile = false;
|
isMobile = false;
|
||||||
isReady = false;
|
isReady = false;
|
||||||
@@ -403,7 +409,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
if (notes.length == 0) {
|
if (notes.length == 0) {
|
||||||
Logger("There are no old documents");
|
Logger("There are no old documents");
|
||||||
Logger(`Checking expired file history done`);
|
Logger(`Checking expired file history done`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const v of notes) {
|
for (const v of notes) {
|
||||||
@@ -420,6 +425,43 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
Logger(`Something went wrong! The local database is not ready`, LOG_LEVEL_NOTICE);
|
Logger(`Something went wrong! The local database is not ready`, LOG_LEVEL_NOTICE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!this.settings.isConfigured) {
|
||||||
|
const message = `Hello and welcome to Self-hosted LiveSync.
|
||||||
|
|
||||||
|
Your device seems to **not be configured yet**. Please finish the setup and synchronise your vaults!
|
||||||
|
|
||||||
|
Click anywhere to stop counting down.
|
||||||
|
|
||||||
|
## At the first device
|
||||||
|
- With Setup URI -> Use \`Use the copied setup URI\`.
|
||||||
|
If you have configured it automatically, you should have one.
|
||||||
|
- Without Setup URI -> Use \`Setup wizard\` in setting dialogue. **\`Minimal setup\` is recommended**.
|
||||||
|
- What is the Setup URI? -> Do not worry! We have [some docs](https://github.com/vrtmrz/obsidian-livesync/blob/main/README.md#how-to-use) now. Please refer to them once.
|
||||||
|
|
||||||
|
## At the subsequent device
|
||||||
|
- With Setup URI -> Use \`Use the copied setup URI\`.
|
||||||
|
If you do not have it yet, you can copy it on the first device.
|
||||||
|
- Without Setup URI -> Use \`Setup wizard\` in setting dialogue, but **strongly recommends using setup URI**.
|
||||||
|
`
|
||||||
|
const OPEN_SETUP = "Open setting dialog";
|
||||||
|
const USE_SETUP = "Use the copied setup URI";
|
||||||
|
const DISMISS = "Dismiss";
|
||||||
|
|
||||||
|
const ret = await confirmWithMessage(this, "Welcome to Self-hosted LiveSync", message, [USE_SETUP, OPEN_SETUP, DISMISS], DISMISS, 40);
|
||||||
|
if (ret === OPEN_SETUP) {
|
||||||
|
try {
|
||||||
|
//@ts-ignore: undocumented api
|
||||||
|
this.app.setting.open();
|
||||||
|
//@ts-ignore: undocumented api
|
||||||
|
this.app.setting.openTabById("obsidian-livesync");
|
||||||
|
} catch (ex) {
|
||||||
|
Logger("Something went wrong on opening setting dialog, please open it manually", LOG_LEVEL_NOTICE);
|
||||||
|
}
|
||||||
|
} else if (ret == USE_SETUP) {
|
||||||
|
fireAndForget(this.addOnSetup.command_openSetupURI());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this.isRedFlagRaised() || this.isRedFlag2Raised() || this.isRedFlag3Raised()) {
|
if (this.isRedFlagRaised() || this.isRedFlag2Raised() || this.isRedFlag3Raised()) {
|
||||||
@@ -736,7 +778,7 @@ Note: We can always able to read V1 format. It will be progressively converted.
|
|||||||
this.statusBar = this.addStatusBarItem();
|
this.statusBar = this.addStatusBarItem();
|
||||||
this.statusBar.addClass("syncstatusbar");
|
this.statusBar.addClass("syncstatusbar");
|
||||||
const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1000);
|
const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1000);
|
||||||
if (lastVersion > this.settings.lastReadUpdates) {
|
if (lastVersion > this.settings.lastReadUpdates && this.settings.isConfigured) {
|
||||||
Logger("Self-hosted LiveSync has undergone a major upgrade. Please open the setting dialog, and check the information pane.", LOG_LEVEL_NOTICE);
|
Logger("Self-hosted LiveSync has undergone a major upgrade. Please open the setting dialog, and check the information pane.", LOG_LEVEL_NOTICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -877,6 +919,16 @@ Note: We can always able to read V1 format. It will be progressively converted.
|
|||||||
|
|
||||||
async loadSettings() {
|
async loadSettings() {
|
||||||
const settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()) as ObsidianLiveSyncSettings;
|
const settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()) as ObsidianLiveSyncSettings;
|
||||||
|
|
||||||
|
if (typeof settings.isConfigured == "undefined") {
|
||||||
|
// If migrated, mark true
|
||||||
|
if (JSON.stringify(settings) !== JSON.stringify(DEFAULT_SETTINGS)) {
|
||||||
|
settings.isConfigured = true;
|
||||||
|
} else {
|
||||||
|
settings.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}`
|
||||||
|
settings.isConfigured = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
const passphrase = await this.getPassphrase(settings);
|
const passphrase = await this.getPassphrase(settings);
|
||||||
if (passphrase === false) {
|
if (passphrase === false) {
|
||||||
Logger("Could not determine passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL_URGENT);
|
Logger("Could not determine passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL_URGENT);
|
||||||
@@ -1193,8 +1245,8 @@ We can perform a command in this file.
|
|||||||
|
|
||||||
async watchWindowVisibilityAsync() {
|
async watchWindowVisibilityAsync() {
|
||||||
if (this.settings.suspendFileWatching) return;
|
if (this.settings.suspendFileWatching) return;
|
||||||
|
if (!this.settings.isConfigured) return;
|
||||||
if (!this.isReady) return;
|
if (!this.isReady) return;
|
||||||
// if (this.suspended) return;
|
|
||||||
const isHidden = document.hidden;
|
const isHidden = document.hidden;
|
||||||
await this.applyBatchChange();
|
await this.applyBatchChange();
|
||||||
if (isHidden) {
|
if (isHidden) {
|
||||||
@@ -1307,6 +1359,7 @@ We can perform a command in this file.
|
|||||||
|
|
||||||
watchWorkspaceOpen(file: TFile | null) {
|
watchWorkspaceOpen(file: TFile | null) {
|
||||||
if (this.settings.suspendFileWatching) return;
|
if (this.settings.suspendFileWatching) return;
|
||||||
|
if (!this.settings.isConfigured) return;
|
||||||
if (!this.isReady) return;
|
if (!this.isReady) return;
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
scheduleTask("watch-workspace-open", 500, () => fireAndForget(() => this.watchWorkspaceOpenAsync(file)));
|
scheduleTask("watch-workspace-open", 500, () => fireAndForget(() => this.watchWorkspaceOpenAsync(file)));
|
||||||
@@ -1314,6 +1367,7 @@ We can perform a command in this file.
|
|||||||
|
|
||||||
async watchWorkspaceOpenAsync(file: TFile) {
|
async watchWorkspaceOpenAsync(file: TFile) {
|
||||||
if (this.settings.suspendFileWatching) return;
|
if (this.settings.suspendFileWatching) return;
|
||||||
|
if (!this.settings.isConfigured) return;
|
||||||
if (!this.isReady) return;
|
if (!this.isReady) return;
|
||||||
await this.applyBatchChange();
|
await this.applyBatchChange();
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
@@ -1579,17 +1633,18 @@ We can perform a command in this file.
|
|||||||
localStorage.setItem(lsKey, saveData);
|
localStorage.setItem(lsKey, saveData);
|
||||||
}
|
}
|
||||||
async loadQueuedFiles() {
|
async loadQueuedFiles() {
|
||||||
if (!this.settings.suspendParseReplicationResult) {
|
if (this.settings.suspendParseReplicationResult) return;
|
||||||
const lsKey = "obsidian-livesync-queuefiles-" + this.getVaultName();
|
if (!this.settings.isConfigured) return;
|
||||||
const ids = [...new Set(JSON.parse(localStorage.getItem(lsKey) || "[]"))] as string[];
|
const lsKey = "obsidian-livesync-queuefiles-" + this.getVaultName();
|
||||||
const batchSize = 100;
|
const ids = [...new Set(JSON.parse(localStorage.getItem(lsKey) || "[]"))] as string[];
|
||||||
const chunkedIds = arrayToChunkedArray(ids, batchSize);
|
const batchSize = 100;
|
||||||
for await (const idsBatch of chunkedIds) {
|
const chunkedIds = arrayToChunkedArray(ids, batchSize);
|
||||||
const ret = await this.localDatabase.allDocsRaw<EntryDoc>({ keys: idsBatch, include_docs: true, limit: 100 });
|
for await (const idsBatch of chunkedIds) {
|
||||||
this.replicationResultProcessor.enqueueAll(ret.rows.map(doc => doc.doc));
|
const ret = await this.localDatabase.allDocsRaw<EntryDoc>({ keys: idsBatch, include_docs: true, limit: 100 });
|
||||||
await this.replicationResultProcessor.waitForPipeline();
|
this.replicationResultProcessor.enqueueAll(ret.rows.map(doc => doc.doc));
|
||||||
}
|
await this.replicationResultProcessor.waitForPipeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
databaseQueueCount = reactiveSource(0);
|
databaseQueueCount = reactiveSource(0);
|
||||||
@@ -1953,6 +2008,12 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
|
|
||||||
async syncAllFiles(showingNotice?: boolean) {
|
async syncAllFiles(showingNotice?: boolean) {
|
||||||
// synchronize all files between database and storage.
|
// synchronize all files between database and storage.
|
||||||
|
if (!this.settings.isConfigured) {
|
||||||
|
if (showingNotice) {
|
||||||
|
Logger("LiveSync is not configured yet. Synchronising between the storage and the local database is now prevented.", LOG_LEVEL_NOTICE, "syncAll");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
let initialScan = false;
|
let initialScan = false;
|
||||||
if (showingNotice) {
|
if (showingNotice) {
|
||||||
Logger("Initializing", LOG_LEVEL_NOTICE, "syncAll");
|
Logger("Initializing", LOG_LEVEL_NOTICE, "syncAll");
|
||||||
|
|||||||
19
updates.md
19
updates.md
@@ -10,6 +10,25 @@ Note: we got a very performance improvement.
|
|||||||
Note at 0.22.2: **Now, to rescue mobile devices, Maximum file size is set to 50 by default**. Please configure the limit as you need. If you do not want to limit the sizes, set zero manually, please.
|
Note at 0.22.2: **Now, to rescue mobile devices, Maximum file size is set to 50 by default**. Please configure the limit as you need. If you do not want to limit the sizes, set zero manually, please.
|
||||||
|
|
||||||
#### Version history
|
#### Version history
|
||||||
|
- 0.22.6
|
||||||
|
- Fixed:
|
||||||
|
- Fixed a problem with synchronisation taking a long time to start in some cases.
|
||||||
|
- The first synchronisation after update might take a bit longer.
|
||||||
|
- Now we can disable E2EE encryption.
|
||||||
|
- Improved:
|
||||||
|
- `Setup Wizard` is now more clear.
|
||||||
|
- `Minimal Setup` is now more simple.
|
||||||
|
- Self-hosted LiveSync now be able to use even if there are vaults with the same name.
|
||||||
|
- Database suffix will automatically added.
|
||||||
|
- Now Self-hosted LiveSync waits until set-up is complete.
|
||||||
|
- Show reload prompts when possibly recommended while settings.
|
||||||
|
- New feature:
|
||||||
|
- A guidance dialogue prompting for settings will be shown after the installation.
|
||||||
|
- Changed
|
||||||
|
- `Open setup URI` is now `Use the copied setup URI`
|
||||||
|
- `Copy setup URI` is now `Copy current settings as a new setup URI`
|
||||||
|
- `Setup Wizard` is now `Minimal Setup`
|
||||||
|
- `Check database configuration` is now `Check and Fix database configuration`
|
||||||
- 0.22.5
|
- 0.22.5
|
||||||
- Fixed:
|
- Fixed:
|
||||||
- Some description of settings have been refined
|
- Some description of settings have been refined
|
||||||
|
|||||||
Reference in New Issue
Block a user