Compare commits
No commits in common. "master" and "0.5.21" have entirely different histories.
6
.github/workflows/auto-build.yml
vendored
6
.github/workflows/auto-build.yml
vendored
@ -39,13 +39,13 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codes
|
- name: Checkout codes
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Checkout LFS file list
|
- name: Checkout LFS file list
|
||||||
run: git lfs ls-files --long | cut -d ' ' -f1 | sort > .lfs-assets-id
|
run: git lfs ls-files --long | cut -d ' ' -f1 | sort > .lfs-assets-id
|
||||||
- name: LFS Cache
|
- name: LFS Cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: .git/lfs/objects
|
path: .git/lfs/objects
|
||||||
key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}
|
key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}
|
||||||
@ -60,7 +60,7 @@ jobs:
|
|||||||
- run: npm install
|
- run: npm install
|
||||||
- run: npm test
|
- run: npm test
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: my-dist
|
name: my-dist
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
52
.github/workflows/release.yml
vendored
52
.github/workflows/release.yml
vendored
@ -42,13 +42,13 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout codes
|
- name: Checkout codes
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Checkout LFS file list
|
- name: Checkout LFS file list
|
||||||
run: git lfs ls-files --long | cut -d ' ' -f1 | sort > .lfs-assets-id
|
run: git lfs ls-files --long | cut -d ' ' -f1 | sort > .lfs-assets-id
|
||||||
- name: LFS Cache
|
- name: LFS Cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: .git/lfs/objects
|
path: .git/lfs/objects
|
||||||
key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}
|
key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}
|
||||||
@ -63,14 +63,44 @@ jobs:
|
|||||||
- run: npm install
|
- run: npm install
|
||||||
- run: npm test
|
- run: npm test
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- name: Create Release And Upload
|
- name: Create Release
|
||||||
uses: softprops/action-gh-release@v2
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
VERSION: ${{ github.ref }}
|
||||||
with:
|
with:
|
||||||
files: |
|
tag_name: ${{ github.ref }}
|
||||||
main.js
|
release_name: ${{ github.ref }}
|
||||||
manifest.json
|
|
||||||
styles.css
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: true
|
||||||
make_latest: true
|
- name: Upload main.js
|
||||||
|
id: upload-main
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./main.js
|
||||||
|
asset_name: main.js
|
||||||
|
asset_content_type: text/javascript
|
||||||
|
- name: Upload manifest.json
|
||||||
|
id: upload-manifest
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./manifest.json
|
||||||
|
asset_name: manifest.json
|
||||||
|
asset_content_type: application/json
|
||||||
|
- name: Upload styles.css
|
||||||
|
id: upload-styles
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./styles.css
|
||||||
|
asset_name: styles.css
|
||||||
|
asset_content_type: text/css
|
||||||
|
|||||||
@ -122,7 +122,6 @@ Additionally, the plugin author may occasionally visit Obsidian official forum a
|
|||||||
- [Open Media Vault](./docs/remote_services/webdav_openmediavault/README.md)
|
- [Open Media Vault](./docs/remote_services/webdav_openmediavault/README.md)
|
||||||
- [Nginx (`ngx_http_dav_module`, `nginx-dav-ext-module`, with Docker)](./docs/remote_services/webdav_nginx/README.md)
|
- [Nginx (`ngx_http_dav_module`, `nginx-dav-ext-module`, with Docker)](./docs/remote_services/webdav_nginx/README.md)
|
||||||
- [Apache (with Docker)](./docs/remote_services/webdav_apache/README.md)
|
- [Apache (with Docker)](./docs/remote_services/webdav_apache/README.md)
|
||||||
- [Caddy with `http.handlers.webdav` module](./docs/remote_services/webdav_caddy/README.md)
|
|
||||||
- Very old version of Obsidian needs [configuring CORS](./docs/remote_services/webdav_general/webav_cors.md).
|
- Very old version of Obsidian needs [configuring CORS](./docs/remote_services/webdav_general/webav_cors.md).
|
||||||
- Your data would be synced to a `${vaultName}` sub folder on your webdav server.
|
- Your data would be synced to a `${vaultName}` sub folder on your webdav server.
|
||||||
- Password-based end-to-end encryption is also supported. But please be aware that **the vault name itself is not encrypted**.
|
- Password-based end-to-end encryption is also supported. But please be aware that **the vault name itself is not encrypted**.
|
||||||
|
|||||||
@ -122,7 +122,6 @@
|
|||||||
- [Open Media Vault](./docs/remote_services/webdav_openmediavault/README.md)
|
- [Open Media Vault](./docs/remote_services/webdav_openmediavault/README.md)
|
||||||
- [Nginx (`ngx_http_dav_module`, `nginx-dav-ext-module`, with Docker)](./docs/remote_services/webdav_nginx/README.md)
|
- [Nginx (`ngx_http_dav_module`, `nginx-dav-ext-module`, with Docker)](./docs/remote_services/webdav_nginx/README.md)
|
||||||
- [Apache (with Docker)](./docs/remote_services/webdav_apache/README.md)
|
- [Apache (with Docker)](./docs/remote_services/webdav_apache/README.md)
|
||||||
- [Caddy with `http.handlers.webdav` module](./docs/remote_services/webdav_caddy/README.md)
|
|
||||||
- 非常旧版本的Obsidian需要[配置 CORS](./docs/remote_services/webdav_general/webav_cors.md)。
|
- 非常旧版本的Obsidian需要[配置 CORS](./docs/remote_services/webdav_general/webav_cors.md)。
|
||||||
- 你的数据会同步到你的webdav服务器上的 `${vaultName}` 子文件夹。
|
- 你的数据会同步到你的webdav服务器上的 `${vaultName}` 子文件夹。
|
||||||
- 基于密码的端到端加密也是可以的。但请注意,**vault 名称本身未加密**。
|
- 基于密码的端到端加密也是可以的。但请注意,**vault 名称本身未加密**。
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
# Caddy with `http.handlers.webdav` module
|
|
||||||
|
|
||||||
> modified from the instruction from @cyruz-git in https://github.com/remotely-save/remotely-save/issues/825
|
|
||||||
|
|
||||||
## Link
|
|
||||||
|
|
||||||
<https://caddyserver.com/download?package=github.com%2Fmholt%2Fcaddy-webdav>
|
|
||||||
|
|
||||||
## Steps
|
|
||||||
|
|
||||||
1. Download caddy with webdav module from <https://caddyserver.com/download?package=github.com%2Fmholt%2Fcaddy-webdav>. Or you can install Caddy then install the plugins.
|
|
||||||
2. Create a folder for storing webdav server files. Like `/usr/local/mywebdav`.
|
|
||||||
3. Create a `Caddyfile` (yeah the file name itself is `Caddyfile`.) like this:
|
|
||||||
```caddy
|
|
||||||
:8080 {
|
|
||||||
route /dav/* {
|
|
||||||
root /usr/local/mywebdav
|
|
||||||
basicauth {
|
|
||||||
# Username "Bob", password "hiccup"
|
|
||||||
Bob $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG
|
|
||||||
}
|
|
||||||
uri strip_prefix /dav
|
|
||||||
webdav
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
The password hash is generated like [this](https://caddyserver.com/docs/caddyfile/directives/basic_auth).
|
|
||||||
4. In Remotely Save, setup:
|
|
||||||
* address `http://localhost:8080/dav/`
|
|
||||||
* username `Bob`
|
|
||||||
* password `hiccup`
|
|
||||||
* auth type: `basic`
|
|
||||||
5. Check the connection and sync!
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "remotely-save",
|
"id": "remotely-save",
|
||||||
"name": "Remotely Save",
|
"name": "Remotely Save",
|
||||||
"version": "0.5.25",
|
"version": "0.5.21",
|
||||||
"minAppVersion": "0.13.21",
|
"minAppVersion": "0.13.21",
|
||||||
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
|
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
|
||||||
"author": "fyears",
|
"author": "fyears",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "remotely-save",
|
"id": "remotely-save",
|
||||||
"name": "Remotely Save",
|
"name": "Remotely Save",
|
||||||
"version": "0.5.25",
|
"version": "0.5.21",
|
||||||
"minAppVersion": "0.13.21",
|
"minAppVersion": "0.13.21",
|
||||||
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
|
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
|
||||||
"author": "fyears",
|
"author": "fyears",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "remotely-save",
|
"name": "remotely-save",
|
||||||
"version": "0.5.25",
|
"version": "0.5.21",
|
||||||
"description": "This is yet another sync plugin for Obsidian app.",
|
"description": "This is yet another sync plugin for Obsidian app.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev2": "node esbuild.config.mjs --watch",
|
"dev2": "node esbuild.config.mjs --watch",
|
||||||
|
|||||||
@ -268,7 +268,7 @@
|
|||||||
"settings_azureblobstorage_parts": "Parts Concurrency",
|
"settings_azureblobstorage_parts": "Parts Concurrency",
|
||||||
"settings_azureblobstorage_parts_desc": "Large files are split into small parts to upload. How many parts do you want to upload in parallel at most?",
|
"settings_azureblobstorage_parts_desc": "Large files are split into small parts to upload. How many parts do you want to upload in parallel at most?",
|
||||||
"settings_azureblobstorage_generatefolderobject": "Generate Folder Object Or Not",
|
"settings_azureblobstorage_generatefolderobject": "Generate Folder Object Or Not",
|
||||||
"settings_azureblobstorage_generatefolderobject_desc": "Azure Blob Storage doesn't have \"real\" folder. If you set \"Generate\" here, the plugin will upload a zero-byte object ending with \"/\" to represent the folder. By default, the plugin skips generating folder object.",
|
"settings_azureblobstorage_generatefolderobject_desc": "Azure Blob Storage doesn't have \"real\" folder. If you set \"Generate\" here, the plugin will upload a zero-byte object endding with \"/\" to represent the folder. By default, the plugin skips generating folder object.",
|
||||||
"settings_azureblobstorage_generatefolderobject_notgenerate": "Not generate (default)",
|
"settings_azureblobstorage_generatefolderobject_notgenerate": "Not generate (default)",
|
||||||
"settings_azureblobstorage_generatefolderobject_generate": "Generate",
|
"settings_azureblobstorage_generatefolderobject_generate": "Generate",
|
||||||
"settings_azureblobstorage_connect_succ": "Great! We can connect to Azure Blob Storage!",
|
"settings_azureblobstorage_connect_succ": "Great! We can connect to Azure Blob Storage!",
|
||||||
|
|||||||
@ -95,10 +95,6 @@ class GoogleDriveAuthModal extends Modal {
|
|||||||
k.expires_in * 1000;
|
k.expires_in * 1000;
|
||||||
this.plugin.settings.googledrive.accessTokenExpiresAtTimeMs =
|
this.plugin.settings.googledrive.accessTokenExpiresAtTimeMs =
|
||||||
ts + k.expires_in * 1000 - 60 * 2 * 1000;
|
ts + k.expires_in * 1000 - 60 * 2 * 1000;
|
||||||
|
|
||||||
// manually set it expired after 60 days;
|
|
||||||
this.plugin.settings.googledrive.credentialsShouldBeDeletedAtTimeMs =
|
|
||||||
Date.now() + 1000 * 60 * 60 * 24 * 59;
|
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
|
|
||||||
// try to remove data in clipboard
|
// try to remove data in clipboard
|
||||||
|
|||||||
106
pro/src/sync.ts
106
pro/src/sync.ts
@ -202,37 +202,15 @@ export const checkIsSkipItemOrNotByName = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (syncConfigDir && isInsideObsFolder(key, configDir)) {
|
||||||
// sync config, not sync bookmarks: sync config and **force syncing bookmarks as well**
|
|
||||||
// not sync config, sync bookmarks: sync bookmars, not other config
|
|
||||||
// not sync config, not sync bookmarks: not sync config
|
|
||||||
if (finalIsIgnored === undefined) {
|
if (finalIsIgnored === undefined) {
|
||||||
if (syncConfigDir) {
|
|
||||||
if (isInsideObsFolder(key, configDir)) {
|
|
||||||
// force sync everything
|
|
||||||
finalIsIgnored = false;
|
finalIsIgnored = false;
|
||||||
} else {
|
|
||||||
// not config files, do not judge now, do nothing
|
|
||||||
}
|
}
|
||||||
} else if (syncBookmarks) {
|
}
|
||||||
// not sync config, sync bookmarks
|
|
||||||
if (isBookmarksFile(key, configDir)) {
|
if (syncBookmarks && isBookmarksFile(key, configDir)) {
|
||||||
// sync everything of bookmarks
|
if (finalIsIgnored === undefined) {
|
||||||
finalIsIgnored = false;
|
finalIsIgnored = false;
|
||||||
} else if (isInsideObsFolder(key, configDir)) {
|
|
||||||
// not sync any other thing in config
|
|
||||||
finalIsIgnored = true;
|
|
||||||
} else {
|
|
||||||
// not config files, do not judge now, do nothing
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// not sync config, and not sync bookmarks
|
|
||||||
if (isInsideObsFolder(key, configDir)) {
|
|
||||||
// not sync any thing in config
|
|
||||||
finalIsIgnored = true;
|
|
||||||
} else {
|
|
||||||
// not config files, do not judge now, do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,9 +256,17 @@ export const checkIsSkipItemOrNotByName = (
|
|||||||
* | yes, also apply to children | explictly ignored | yes | yes | yes |
|
* | yes, also apply to children | explictly ignored | yes | yes | yes |
|
||||||
*/
|
*/
|
||||||
export const getSkipItemsByList = (
|
export const getSkipItemsByList = (
|
||||||
skipOrNotResults: Record<string, IsSkipResult>
|
skipOrNotResults: Record<string, IsSkipResult>,
|
||||||
|
ignorePaths: string[],
|
||||||
|
onlyAllowPaths: string[]
|
||||||
): string[] => {
|
): string[] => {
|
||||||
const allPotentialKeys = Object.keys(skipOrNotResults);
|
const allPotentialKeys = Object.keys(skipOrNotResults);
|
||||||
|
if (
|
||||||
|
allPotentialKeys.length === 0 ||
|
||||||
|
(ignorePaths.length === 0 && onlyAllowPaths.length === 0)
|
||||||
|
) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
// from short(shadow) to long(deep) , ascending
|
// from short(shadow) to long(deep) , ascending
|
||||||
const sortedKeys = allPotentialKeys.sort((k1, k2) => k1.length - k2.length);
|
const sortedKeys = allPotentialKeys.sort((k1, k2) => k1.length - k2.length);
|
||||||
@ -305,14 +291,7 @@ export const getSkipItemsByList = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we deal with explictly allow list secondly, apply them to PARENTS if possible
|
// we deal with explictly allow list secondly, apply them to PARENTS if possible
|
||||||
let enableAllowMode = false;
|
const enableAllowMode = skipOrNotResults[allPotentialKeys[0]].enableAllowMode;
|
||||||
if (
|
|
||||||
allPotentialKeys.length > 0 &&
|
|
||||||
allPotentialKeys[0] !== undefined &&
|
|
||||||
skipOrNotResults[allPotentialKeys[0]] !== undefined
|
|
||||||
) {
|
|
||||||
enableAllowMode = skipOrNotResults[allPotentialKeys[0]].enableAllowMode;
|
|
||||||
}
|
|
||||||
if (enableAllowMode) {
|
if (enableAllowMode) {
|
||||||
for (let index = 0; index < sortedKeys.length; index++) {
|
for (let index = 0; index < sortedKeys.length; index++) {
|
||||||
// reverse order, long(deep) to short(shadow), ascending
|
// reverse order, long(deep) to short(shadow), ascending
|
||||||
@ -350,7 +329,6 @@ export const getSkipItemsByList = (
|
|||||||
result.push(key);
|
result.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.debug(`finalIsIgnored list= ${JSON.stringify(result)}`);
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -517,7 +495,11 @@ const ensembleMixedEnties = async (
|
|||||||
profiler?.insertSize("sizeof finalMappings", finalMappings);
|
profiler?.insertSize("sizeof finalMappings", finalMappings);
|
||||||
|
|
||||||
// we check the skipOrNotResults again! in case we adjust some paths!
|
// we check the skipOrNotResults again! in case we adjust some paths!
|
||||||
const allReallySkipKeys = getSkipItemsByList(skipOrNotResults);
|
const allReallySkipKeys = getSkipItemsByList(
|
||||||
|
skipOrNotResults,
|
||||||
|
ignorePaths,
|
||||||
|
onlyAllowPaths
|
||||||
|
);
|
||||||
for (const key of allReallySkipKeys) {
|
for (const key of allReallySkipKeys) {
|
||||||
delete finalMappings[key];
|
delete finalMappings[key];
|
||||||
}
|
}
|
||||||
@ -643,37 +625,15 @@ const getSyncPlanInplace = async (
|
|||||||
mixedEntry.change = false;
|
mixedEntry.change = false;
|
||||||
keptFolder.add(getParentFolder(key));
|
keptFolder.add(getParentFolder(key));
|
||||||
} else if (syncDirection === "incremental_pull_and_delete_only") {
|
} else if (syncDirection === "incremental_pull_and_delete_only") {
|
||||||
if (
|
|
||||||
key === `${configDir}/` ||
|
|
||||||
key === `${configDir}/bookmarks.json`
|
|
||||||
) {
|
|
||||||
// special: never delete .obsidian folder!
|
|
||||||
mixedEntry.decisionBranch = 137;
|
|
||||||
mixedEntry.decision = "folder_existed_both_then_do_nothing";
|
|
||||||
mixedEntry.change = false;
|
|
||||||
keptFolder.add(getParentFolder(key));
|
|
||||||
} else {
|
|
||||||
mixedEntry.decisionBranch = 135;
|
mixedEntry.decisionBranch = 135;
|
||||||
mixedEntry.decision = "folder_to_be_deleted_on_local";
|
mixedEntry.decision = "folder_to_be_deleted_on_local";
|
||||||
mixedEntry.change = true;
|
mixedEntry.change = true;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// bidirectional
|
// bidirectional
|
||||||
if (
|
|
||||||
key === `${configDir}/` ||
|
|
||||||
key === `${configDir}/bookmarks.json`
|
|
||||||
) {
|
|
||||||
// special: never delete .obsidian folder!
|
|
||||||
mixedEntry.decisionBranch = 138;
|
|
||||||
mixedEntry.decision = "folder_existed_both_then_do_nothing";
|
|
||||||
mixedEntry.change = false;
|
|
||||||
keptFolder.add(getParentFolder(key));
|
|
||||||
} else {
|
|
||||||
mixedEntry.decisionBranch = 124;
|
mixedEntry.decisionBranch = 124;
|
||||||
mixedEntry.decision = "folder_to_be_deleted_on_local";
|
mixedEntry.decision = "folder_to_be_deleted_on_local";
|
||||||
mixedEntry.change = true;
|
mixedEntry.change = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// then the folder is created on local
|
// then the folder is created on local
|
||||||
|
|
||||||
@ -1114,36 +1074,14 @@ const getSyncPlanInplace = async (
|
|||||||
mixedEntry.decision = "conflict_created_then_do_nothing";
|
mixedEntry.decision = "conflict_created_then_do_nothing";
|
||||||
mixedEntry.change = false;
|
mixedEntry.change = false;
|
||||||
} else if (syncDirection === "incremental_pull_and_delete_only") {
|
} else if (syncDirection === "incremental_pull_and_delete_only") {
|
||||||
if (
|
|
||||||
key === `${configDir}/` ||
|
|
||||||
key === `${configDir}/bookmarks.json`
|
|
||||||
) {
|
|
||||||
// special: never delete .obsidian/bookmarks.json file!
|
|
||||||
mixedEntry.decisionBranch = 139;
|
|
||||||
mixedEntry.decision = "conflict_created_then_keep_local";
|
|
||||||
mixedEntry.change = true;
|
|
||||||
keptFolder.add(getParentFolder(key));
|
|
||||||
} else {
|
|
||||||
mixedEntry.decisionBranch = 39;
|
mixedEntry.decisionBranch = 39;
|
||||||
mixedEntry.decision = "remote_is_deleted_thus_also_delete_local";
|
mixedEntry.decision = "remote_is_deleted_thus_also_delete_local";
|
||||||
mixedEntry.change = true;
|
mixedEntry.change = true;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
key === `${configDir}/` ||
|
|
||||||
key === `${configDir}/bookmarks.json`
|
|
||||||
) {
|
|
||||||
// special: never delete .obsidian/bookmarks.json file!
|
|
||||||
mixedEntry.decisionBranch = 140;
|
|
||||||
mixedEntry.decision = "conflict_created_then_keep_local";
|
|
||||||
mixedEntry.change = true;
|
|
||||||
keptFolder.add(getParentFolder(key));
|
|
||||||
} else {
|
} else {
|
||||||
mixedEntry.decisionBranch = 7;
|
mixedEntry.decisionBranch = 7;
|
||||||
mixedEntry.decision = "remote_is_deleted_thus_also_delete_local";
|
mixedEntry.decision = "remote_is_deleted_thus_also_delete_local";
|
||||||
mixedEntry.change = true;
|
mixedEntry.change = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// if A is in the previous list and MODIFIED, A has been deleted by B but modified by A
|
// if A is in the previous list and MODIFIED, A has been deleted by B but modified by A
|
||||||
if (skipSizeLargerThan <= 0 || local.sizeEnc! <= skipSizeLargerThan) {
|
if (skipSizeLargerThan <= 0 || local.sizeEnc! <= skipSizeLargerThan) {
|
||||||
@ -1930,7 +1868,7 @@ export async function syncer(
|
|||||||
) => any,
|
) => any,
|
||||||
callbackSyncProcess?: any
|
callbackSyncProcess?: any
|
||||||
) {
|
) {
|
||||||
console.info(`starting sync.`);
|
console.info(`startting sync.`);
|
||||||
markIsSyncingFunc(true);
|
markIsSyncingFunc(true);
|
||||||
|
|
||||||
let everythingOk = true;
|
let everythingOk = true;
|
||||||
@ -2089,6 +2027,6 @@ export async function syncer(
|
|||||||
await ribboonFunc?.(triggerSource, step);
|
await ribboonFunc?.(triggerSource, step);
|
||||||
await statusBarFunc?.(triggerSource, step, everythingOk);
|
await statusBarFunc?.(triggerSource, step, everythingOk);
|
||||||
|
|
||||||
console.info(`ending sync.`);
|
console.info(`endding sync.`);
|
||||||
markIsSyncingFunc(false);
|
markIsSyncingFunc(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -252,10 +252,6 @@ const fromDriveItemToEntity = (x: DriveItem, remoteBaseDir: string): Entity => {
|
|||||||
// why?? /drive/root:/Apps/Graph
|
// why?? /drive/root:/Apps/Graph
|
||||||
const FIFTH_COMMON_PREFIX_REGEX = /^\/drive\/root:\/[^\/]+\/Graph\//g;
|
const FIFTH_COMMON_PREFIX_REGEX = /^\/drive\/root:\/[^\/]+\/Graph\//g;
|
||||||
|
|
||||||
// why again?? /drive/root:/Apps/Graph 1
|
|
||||||
const SIXTH_COMMON_PREFIX_REGEX = /^\/drive\/root:\/[^\/]+\/Graph 1\//g;
|
|
||||||
const SIXTH_COMMON_PREFIX_REGEX_V2 = /^\/drive\/root:\/[^\/]+\/Graph%201\//g;
|
|
||||||
|
|
||||||
// or the root is absolute path /Livefolders,
|
// or the root is absolute path /Livefolders,
|
||||||
// e.g.: /Livefolders/应用/remotely-save/${remoteBaseDir}
|
// e.g.: /Livefolders/应用/remotely-save/${remoteBaseDir}
|
||||||
const SECOND_COMMON_PREFIX_REGEX = /^\/Livefolders\/[^\/]+\/remotely-save\//g;
|
const SECOND_COMMON_PREFIX_REGEX = /^\/Livefolders\/[^\/]+\/remotely-save\//g;
|
||||||
@ -282,11 +278,6 @@ const fromDriveItemToEntity = (x: DriveItem, remoteBaseDir: string): Entity => {
|
|||||||
const fullPathOriginal = `${x.parentReference.path}/${x.name}`;
|
const fullPathOriginal = `${x.parentReference.path}/${x.name}`;
|
||||||
const matchFirstPrefixRes = fullPathOriginal.match(FIRST_COMMON_PREFIX_REGEX);
|
const matchFirstPrefixRes = fullPathOriginal.match(FIRST_COMMON_PREFIX_REGEX);
|
||||||
const matchFifthPrefixRes = fullPathOriginal.match(FIFTH_COMMON_PREFIX_REGEX);
|
const matchFifthPrefixRes = fullPathOriginal.match(FIFTH_COMMON_PREFIX_REGEX);
|
||||||
const matchSixthPrefixRes = fullPathOriginal.match(SIXTH_COMMON_PREFIX_REGEX);
|
|
||||||
const matchSixthV2PrefixRes = fullPathOriginal.match(
|
|
||||||
SIXTH_COMMON_PREFIX_REGEX_V2
|
|
||||||
);
|
|
||||||
|
|
||||||
const matchSecondPrefixRes = fullPathOriginal.match(
|
const matchSecondPrefixRes = fullPathOriginal.match(
|
||||||
SECOND_COMMON_PREFIX_REGEX
|
SECOND_COMMON_PREFIX_REGEX
|
||||||
);
|
);
|
||||||
@ -326,40 +317,6 @@ const fromDriveItemToEntity = (x: DriveItem, remoteBaseDir: string): Entity => {
|
|||||||
key = fullPathOriginal.substring(foundPrefix.length + 1);
|
key = fullPathOriginal.substring(foundPrefix.length + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sixth
|
|
||||||
else if (
|
|
||||||
matchSixthPrefixRes !== null &&
|
|
||||||
fullPathOriginal.startsWith(`${matchSixthPrefixRes[0]}${remoteBaseDir}`)
|
|
||||||
) {
|
|
||||||
const foundPrefix = `${matchSixthPrefixRes[0]}${remoteBaseDir}`;
|
|
||||||
key = fullPathOriginal.substring(foundPrefix.length + 1);
|
|
||||||
} else if (
|
|
||||||
matchSixthPrefixRes !== null &&
|
|
||||||
fullPathOriginal.startsWith(
|
|
||||||
`${matchSixthPrefixRes[0]}${remoteBaseDirEncoded}`
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
const foundPrefix = `${matchSixthPrefixRes[0]}${remoteBaseDirEncoded}`;
|
|
||||||
key = fullPathOriginal.substring(foundPrefix.length + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sixth v2
|
|
||||||
else if (
|
|
||||||
matchSixthV2PrefixRes !== null &&
|
|
||||||
fullPathOriginal.startsWith(`${matchSixthV2PrefixRes[0]}${remoteBaseDir}`)
|
|
||||||
) {
|
|
||||||
const foundPrefix = `${matchSixthV2PrefixRes[0]}${remoteBaseDir}`;
|
|
||||||
key = fullPathOriginal.substring(foundPrefix.length + 1);
|
|
||||||
} else if (
|
|
||||||
matchSixthV2PrefixRes !== null &&
|
|
||||||
fullPathOriginal.startsWith(
|
|
||||||
`${matchSixthV2PrefixRes[0]}${remoteBaseDirEncoded}`
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
const foundPrefix = `${matchSixthV2PrefixRes[0]}${remoteBaseDirEncoded}`;
|
|
||||||
key = fullPathOriginal.substring(foundPrefix.length + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// second
|
// second
|
||||||
else if (
|
else if (
|
||||||
matchSecondPrefixRes !== null &&
|
matchSecondPrefixRes !== null &&
|
||||||
@ -417,8 +374,6 @@ const fromDriveItemToEntity = (x: DriveItem, remoteBaseDir: string): Entity => {
|
|||||||
fullPathOriginal=${fullPathOriginal}
|
fullPathOriginal=${fullPathOriginal}
|
||||||
matchFirstPrefixRes=${matchFirstPrefixRes}
|
matchFirstPrefixRes=${matchFirstPrefixRes}
|
||||||
matchFifthPrefixRes=${matchFifthPrefixRes}
|
matchFifthPrefixRes=${matchFifthPrefixRes}
|
||||||
matchSixthPrefixRes=${matchSixthPrefixRes}
|
|
||||||
matchSixthV2PrefixRes=${matchSixthV2PrefixRes}
|
|
||||||
matchSecondPrefixRes=${matchSecondPrefixRes}
|
matchSecondPrefixRes=${matchSecondPrefixRes}
|
||||||
matchThirdPrefixRes=${matchThirdPrefixRes}
|
matchThirdPrefixRes=${matchThirdPrefixRes}
|
||||||
${constructFromDriveItemToEntityError(x)}`
|
${constructFromDriveItemToEntityError(x)}`
|
||||||
@ -433,8 +388,6 @@ ${constructFromDriveItemToEntityError(x)}`
|
|||||||
fullPathOriginal=${fullPathOriginal}
|
fullPathOriginal=${fullPathOriginal}
|
||||||
matchFirstPrefixRes=${matchFirstPrefixRes}
|
matchFirstPrefixRes=${matchFirstPrefixRes}
|
||||||
matchFifthPrefixRes=${matchFifthPrefixRes}
|
matchFifthPrefixRes=${matchFifthPrefixRes}
|
||||||
matchSixthPrefixRes=${matchSixthPrefixRes}
|
|
||||||
matchSixthV2PrefixRes=${matchSixthV2PrefixRes}
|
|
||||||
matchSecondPrefixRes=${matchSecondPrefixRes}
|
matchSecondPrefixRes=${matchSecondPrefixRes}
|
||||||
matchThirdPrefixRes=${matchThirdPrefixRes}
|
matchThirdPrefixRes=${matchThirdPrefixRes}
|
||||||
${constructFromDriveItemToEntityError(x)}`
|
${constructFromDriveItemToEntityError(x)}`
|
||||||
|
|||||||
@ -138,6 +138,7 @@ if (VALID_REQURL) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import isEqual from "lodash/isEqual";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
// biome-ignore lint: we want to ts-ignore the next line
|
// biome-ignore lint: we want to ts-ignore the next line
|
||||||
import { AuthType, BufferLike, createClient } from "webdav/dist/web/index.js";
|
import { AuthType, BufferLike, createClient } from "webdav/dist/web/index.js";
|
||||||
@ -168,37 +169,23 @@ const getWebdavPath = (fileOrFolderPath: string, remoteBaseDir: string) => {
|
|||||||
return key;
|
return key;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* sometimes the path startswith /../../......
|
|
||||||
* we want to make sure the path is compatible
|
|
||||||
*/
|
|
||||||
const stripLeadingPath = (x: string) => {
|
|
||||||
let y = x;
|
|
||||||
while (y.startsWith("/..")) {
|
|
||||||
y = y.slice("/..".length);
|
|
||||||
}
|
|
||||||
return y;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getNormPath = (fileOrFolderPath: string, remoteBaseDir: string) => {
|
const getNormPath = (fileOrFolderPath: string, remoteBaseDir: string) => {
|
||||||
const strippedFileOrFolderPath = stripLeadingPath(fileOrFolderPath);
|
|
||||||
if (
|
if (
|
||||||
!(
|
!(
|
||||||
strippedFileOrFolderPath === `/${remoteBaseDir}` ||
|
fileOrFolderPath === `/${remoteBaseDir}` ||
|
||||||
strippedFileOrFolderPath.startsWith(`/${remoteBaseDir}/`)
|
fileOrFolderPath.startsWith(`/${remoteBaseDir}/`)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
throw Error(
|
throw Error(
|
||||||
`"${fileOrFolderPath}" after stripping doesn't starts with "/${remoteBaseDir}/"`
|
`"${fileOrFolderPath}" doesn't starts with "/${remoteBaseDir}/"`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const result = strippedFileOrFolderPath.slice(`/${remoteBaseDir}/`.length);
|
|
||||||
return result;
|
return fileOrFolderPath.slice(`/${remoteBaseDir}/`.length);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fromWebdavItemToEntity = (x: FileStat, remoteBaseDir: string): Entity => {
|
const fromWebdavItemToEntity = (x: FileStat, remoteBaseDir: string): Entity => {
|
||||||
let key = getNormPath(x.filename, remoteBaseDir);
|
let key = getNormPath(x.filename, remoteBaseDir);
|
||||||
|
|
||||||
if (x.type === "directory" && !key.endsWith("/")) {
|
if (x.type === "directory" && !key.endsWith("/")) {
|
||||||
key = `${key}/`;
|
key = `${key}/`;
|
||||||
}
|
}
|
||||||
@ -460,17 +447,15 @@ export class FakeFsWebdav extends FakeFs {
|
|||||||
// console.debug(itemsToFetchChunks);
|
// console.debug(itemsToFetchChunks);
|
||||||
const subContents = [] as FileStat[];
|
const subContents = [] as FileStat[];
|
||||||
for (const singleChunk of itemsToFetchChunks) {
|
for (const singleChunk of itemsToFetchChunks) {
|
||||||
const r = singleChunk.map(async (x) => {
|
const r = singleChunk.map((x) => {
|
||||||
let k = (await this.client.getDirectoryContents(x, {
|
return this.client.getDirectoryContents(x, {
|
||||||
deep: false,
|
deep: false,
|
||||||
details: false /* no need for verbose details here */,
|
details: false /* no need for verbose details here */,
|
||||||
// TODO: to support .obsidian,
|
// TODO: to support .obsidian,
|
||||||
// we need to load all files including dot,
|
// we need to load all files including dot,
|
||||||
// anyway to reduce the resources?
|
// anyway to reduce the resources?
|
||||||
// glob: "/**" /* avoid dot files by using glob */,
|
// glob: "/**" /* avoid dot files by using glob */,
|
||||||
})) as FileStat[];
|
}) as Promise<FileStat[]>;
|
||||||
k = k.filter((sub) => stripLeadingPath(sub.filename) !== x);
|
|
||||||
return k;
|
|
||||||
});
|
});
|
||||||
const r3 = await Promise.all(r);
|
const r3 = await Promise.all(r);
|
||||||
for (const r4 of r3) {
|
for (const r4 of r3) {
|
||||||
@ -492,7 +477,7 @@ export class FakeFsWebdav extends FakeFs {
|
|||||||
const f = subContents[i];
|
const f = subContents[i];
|
||||||
contents.push(f);
|
contents.push(f);
|
||||||
if (f.type === "directory") {
|
if (f.type === "directory") {
|
||||||
q.push(stripLeadingPath(f.filename));
|
q.push(f.filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -510,11 +495,7 @@ export class FakeFsWebdav extends FakeFs {
|
|||||||
}
|
}
|
||||||
)) as FileStat[];
|
)) as FileStat[];
|
||||||
}
|
}
|
||||||
|
return contents.map((x) => fromWebdavItemToEntity(x, this.remoteBaseDir));
|
||||||
const result = contents
|
|
||||||
.map((x) => fromWebdavItemToEntity(x, this.remoteBaseDir))
|
|
||||||
.filter((x) => x.keyRaw !== "/");
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async walkPartial(): Promise<Entity[]> {
|
async walkPartial(): Promise<Entity[]> {
|
||||||
@ -527,9 +508,7 @@ export class FakeFsWebdav extends FakeFs {
|
|||||||
details: false /* no need for verbose details here */,
|
details: false /* no need for verbose details here */,
|
||||||
}
|
}
|
||||||
)) as FileStat[];
|
)) as FileStat[];
|
||||||
return contents
|
return contents.map((x) => fromWebdavItemToEntity(x, this.remoteBaseDir));
|
||||||
.map((x) => fromWebdavItemToEntity(x, this.remoteBaseDir))
|
|
||||||
.filter((x) => x.keyRaw !== "/");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async stat(key: string): Promise<Entity> {
|
async stat(key: string): Promise<Entity> {
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
"protocol_dropbox_connect_succ_revoke": "You've connected as user {{username}}. If you want to disconnect, click this button.",
|
"protocol_dropbox_connect_succ_revoke": "You've connected as user {{username}}. If you want to disconnect, click this button.",
|
||||||
"protocol_dropbox_connect_fail": "Something went wrong from response from Dropbox. Maybe the network connection is not good. Maybe you rejected the auth?",
|
"protocol_dropbox_connect_fail": "Something went wrong from response from Dropbox. Maybe the network connection is not good. Maybe you rejected the auth?",
|
||||||
"protocol_dropbox_connect_unknown": "Do not know how to deal with the callback: {{params}}",
|
"protocol_dropbox_connect_unknown": "Do not know how to deal with the callback: {{params}}",
|
||||||
"protocol_dropbox_no_modal": "You are not starting Dropbox connection from the settings page. Abort.",
|
"protocol_dropbox_no_modal": "You are not startting Dropbox connection from the settings page. Abort.",
|
||||||
"protocol_onedrive_connecting": "Connecting to OneDrive...\nPlease DO NOT close this modal.",
|
"protocol_onedrive_connecting": "Connecting to OneDrive...\nPlease DO NOT close this modal.",
|
||||||
"protocol_onedrive_connect_succ_revoke": "You've connected as user {{username}}. If you want to disconnect, click this button.",
|
"protocol_onedrive_connect_succ_revoke": "You've connected as user {{username}}. If you want to disconnect, click this button.",
|
||||||
"protocol_onedrive_connect_fail": "Something went wrong from response from OneDrive. Maybe you rejected the auth?",
|
"protocol_onedrive_connect_fail": "Something went wrong from response from OneDrive. Maybe you rejected the auth?",
|
||||||
@ -110,7 +110,7 @@
|
|||||||
"modal_onedriverevokeauth_clean_button": "Clean",
|
"modal_onedriverevokeauth_clean_button": "Clean",
|
||||||
"modal_onedriverevokeauth_clean_notice": "Cleaned!",
|
"modal_onedriverevokeauth_clean_notice": "Cleaned!",
|
||||||
"modal_onedriverevokeauth_clean_fail": "Something goes wrong while revoking.",
|
"modal_onedriverevokeauth_clean_fail": "Something goes wrong while revoking.",
|
||||||
"modal_syncconfig_attn": "Attention 1/2: This only syncs (copies) the whole Obsidian config dir, not other starting-with-dot folders or files. Except for ignoring folders .git and node_modules, it also doesn't understand the meaning of sub-files and sub-folders inside the config dir.\nAttention 2/2: After the config dir is synced, plugins settings might be corrupted, and Obsidian might need to be restarted to load the new settings.\nIf you are agreed to take your own risk, please click the following second confirm button.",
|
"modal_syncconfig_attn": "Attention 1/2: This only syncs (copies) the whole Obsidian config dir, not other startting-with-dot folders or files. Except for ignoring folders .git and node_modules, it also doesn't understand the meaning of sub-files and sub-folders inside the config dir.\nAttention 2/2: After the config dir is synced, plugins settings might be corrupted, and Obsidian might need to be restarted to load the new settings.\nIf you are agreed to take your own risk, please click the following second confirm button.",
|
||||||
"modal_syncconfig_secondconfirm": "The Second Confirm To Enable.",
|
"modal_syncconfig_secondconfirm": "The Second Confirm To Enable.",
|
||||||
"modal_syncconfig_notice": "You've enabled syncing config folder!",
|
"modal_syncconfig_notice": "You've enabled syncing config folder!",
|
||||||
"modal_qr_shortdesc": "This exports (partial) settings.\nYou can use another device to scan this qrcode.\nOr, you can click the button to copy the special uri and paste it into another device's web browser or Remotely Save Import Setting.",
|
"modal_qr_shortdesc": "This exports (partial) settings.\nYou can use another device to scan this qrcode.\nOr, you can click the button to copy the special uri and paste it into another device's web browser or Remotely Save Import Setting.",
|
||||||
@ -194,7 +194,7 @@
|
|||||||
"settings_s3_reverse_proxy_no_sign_url": "S3 Reverse Proxy (No Sign) Url (experimental)",
|
"settings_s3_reverse_proxy_no_sign_url": "S3 Reverse Proxy (No Sign) Url (experimental)",
|
||||||
"settings_s3_reverse_proxy_no_sign_url_desc": "S3 reverse proxy url without signature. This is useful if you use a revers proxy but do not change the original credential signature. No http(s):// prefix. Leave it blank if you don't know what it is.",
|
"settings_s3_reverse_proxy_no_sign_url_desc": "S3 reverse proxy url without signature. This is useful if you use a revers proxy but do not change the original credential signature. No http(s):// prefix. Leave it blank if you don't know what it is.",
|
||||||
"settings_s3_generatefolderobject": "Generate Folder Object Or Not",
|
"settings_s3_generatefolderobject": "Generate Folder Object Or Not",
|
||||||
"settings_s3_generatefolderobject_desc": "S3 doesn't have \"real\" folder. If you set \"Generate\" here (or use old version), the plugin will upload a zero-byte object ending with \"/\" to represent the folder. In the new version, the plugin skips generating folder object by default.",
|
"settings_s3_generatefolderobject_desc": "S3 doesn't have \"real\" folder. If you set \"Generate\" here (or use old version), the plugin will upload a zero-byte object endding with \"/\" to represent the folder. In the new version, the plugin skips generating folder object by default.",
|
||||||
"settings_s3_generatefolderobject_notgenerate": "Not generate (default)",
|
"settings_s3_generatefolderobject_notgenerate": "Not generate (default)",
|
||||||
"settings_s3_generatefolderobject_generate": "Generate",
|
"settings_s3_generatefolderobject_generate": "Generate",
|
||||||
"settings_s3_connect_succ": "Great! The bucket can be accessed.",
|
"settings_s3_connect_succ": "Great! The bucket can be accessed.",
|
||||||
|
|||||||
@ -1560,7 +1560,6 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.settings.dropbox.refreshToken !== "" &&
|
this.settings.dropbox.refreshToken !== "" &&
|
||||||
current >= this.settings!.dropbox!.credentialsShouldBeDeletedAtTime!
|
current >= this.settings!.dropbox!.credentialsShouldBeDeletedAtTime!
|
||||||
) {
|
) {
|
||||||
console.warn(`dropbox expired`);
|
|
||||||
dropboxExpired = true;
|
dropboxExpired = true;
|
||||||
this.settings.dropbox = cloneDeep(DEFAULT_DROPBOX_CONFIG);
|
this.settings.dropbox = cloneDeep(DEFAULT_DROPBOX_CONFIG);
|
||||||
needSave = true;
|
needSave = true;
|
||||||
@ -1571,7 +1570,6 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.settings.onedrive.refreshToken !== "" &&
|
this.settings.onedrive.refreshToken !== "" &&
|
||||||
current >= this.settings!.onedrive!.credentialsShouldBeDeletedAtTime!
|
current >= this.settings!.onedrive!.credentialsShouldBeDeletedAtTime!
|
||||||
) {
|
) {
|
||||||
console.warn(`onedrive expired`);
|
|
||||||
onedriveExpired = true;
|
onedriveExpired = true;
|
||||||
this.settings.onedrive = cloneDeep(DEFAULT_ONEDRIVE_CONFIG);
|
this.settings.onedrive = cloneDeep(DEFAULT_ONEDRIVE_CONFIG);
|
||||||
needSave = true;
|
needSave = true;
|
||||||
@ -1582,7 +1580,6 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.settings.onedrivefull.refreshToken !== "" &&
|
this.settings.onedrivefull.refreshToken !== "" &&
|
||||||
current >= this.settings!.onedrivefull!.credentialsShouldBeDeletedAtTime!
|
current >= this.settings!.onedrivefull!.credentialsShouldBeDeletedAtTime!
|
||||||
) {
|
) {
|
||||||
console.warn(`onedrive full expired`);
|
|
||||||
onedriveFullExpired = true;
|
onedriveFullExpired = true;
|
||||||
this.settings.onedrivefull = cloneDeep(DEFAULT_ONEDRIVEFULL_CONFIG);
|
this.settings.onedrivefull = cloneDeep(DEFAULT_ONEDRIVEFULL_CONFIG);
|
||||||
needSave = true;
|
needSave = true;
|
||||||
@ -1593,7 +1590,6 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.settings.googledrive.refreshToken !== "" &&
|
this.settings.googledrive.refreshToken !== "" &&
|
||||||
current >= this.settings!.googledrive!.credentialsShouldBeDeletedAtTimeMs!
|
current >= this.settings!.googledrive!.credentialsShouldBeDeletedAtTimeMs!
|
||||||
) {
|
) {
|
||||||
console.warn(`google drive expired`);
|
|
||||||
googleDriveExpired = true;
|
googleDriveExpired = true;
|
||||||
this.settings.googledrive = cloneDeep(DEFAULT_GOOGLEDRIVE_CONFIG);
|
this.settings.googledrive = cloneDeep(DEFAULT_GOOGLEDRIVE_CONFIG);
|
||||||
needSave = true;
|
needSave = true;
|
||||||
@ -1604,7 +1600,6 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.settings.box.refreshToken !== "" &&
|
this.settings.box.refreshToken !== "" &&
|
||||||
current >= this.settings!.box!.credentialsShouldBeDeletedAtTimeMs!
|
current >= this.settings!.box!.credentialsShouldBeDeletedAtTimeMs!
|
||||||
) {
|
) {
|
||||||
console.warn(`box expired`);
|
|
||||||
boxExpired = true;
|
boxExpired = true;
|
||||||
this.settings.box = cloneDeep(DEFAULT_BOX_CONFIG);
|
this.settings.box = cloneDeep(DEFAULT_BOX_CONFIG);
|
||||||
needSave = true;
|
needSave = true;
|
||||||
@ -1615,7 +1610,6 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.settings.pcloud.accessToken !== "" &&
|
this.settings.pcloud.accessToken !== "" &&
|
||||||
current >= this.settings!.pcloud!.credentialsShouldBeDeletedAtTimeMs!
|
current >= this.settings!.pcloud!.credentialsShouldBeDeletedAtTimeMs!
|
||||||
) {
|
) {
|
||||||
console.warn(`pcloud expired`);
|
|
||||||
pCloudExpired = true;
|
pCloudExpired = true;
|
||||||
this.settings.pcloud = cloneDeep(DEFAULT_PCLOUD_CONFIG);
|
this.settings.pcloud = cloneDeep(DEFAULT_PCLOUD_CONFIG);
|
||||||
needSave = true;
|
needSave = true;
|
||||||
@ -1626,7 +1620,6 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.settings.yandexdisk.refreshToken !== "" &&
|
this.settings.yandexdisk.refreshToken !== "" &&
|
||||||
current >= this.settings!.yandexdisk!.credentialsShouldBeDeletedAtTimeMs!
|
current >= this.settings!.yandexdisk!.credentialsShouldBeDeletedAtTimeMs!
|
||||||
) {
|
) {
|
||||||
console.warn(`yandex disk expired`);
|
|
||||||
yandexDiskExpired = true;
|
yandexDiskExpired = true;
|
||||||
this.settings.yandexdisk = cloneDeep(DEFAULT_YANDEXDISK_CONFIG);
|
this.settings.yandexdisk = cloneDeep(DEFAULT_YANDEXDISK_CONFIG);
|
||||||
needSave = true;
|
needSave = true;
|
||||||
@ -1637,7 +1630,6 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
this.settings.koofr.refreshToken !== "" &&
|
this.settings.koofr.refreshToken !== "" &&
|
||||||
current >= this.settings!.koofr!.credentialsShouldBeDeletedAtTimeMs!
|
current >= this.settings!.koofr!.credentialsShouldBeDeletedAtTimeMs!
|
||||||
) {
|
) {
|
||||||
console.warn(`koofr expired`);
|
|
||||||
koofrExpired = true;
|
koofrExpired = true;
|
||||||
this.settings.koofr = cloneDeep(DEFAULT_KOOFR_CONFIG);
|
this.settings.koofr = cloneDeep(DEFAULT_KOOFR_CONFIG);
|
||||||
needSave = true;
|
needSave = true;
|
||||||
|
|||||||
@ -279,7 +279,7 @@ export const reverseString = (x: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface SplitRange {
|
export interface SplitRange {
|
||||||
partNum: number; // starting from 1
|
partNum: number; // startting from 1
|
||||||
start: number;
|
start: number;
|
||||||
end: number; // exclusive
|
end: number; // exclusive
|
||||||
}
|
}
|
||||||
@ -316,7 +316,7 @@ export const getTypeName = (obj: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* starting from 1
|
* Startting from 1
|
||||||
* @param x
|
* @param x
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user