optimize the import and export functions

This commit is contained in:
fyears 2024-04-03 19:43:53 +08:00
parent 577cdde21f
commit 0fc0dcad64
8 changed files with 160 additions and 25 deletions

View File

@ -90,6 +90,8 @@ export type SyncDirectionType =
export type CipherMethodType = "rclone-base64" | "openssl-base64" | "unknown";
export type QRExportType = "all_but_oauth2" | "dropbox" | "onedrive";
export interface RemotelySavePluginSettings {
s3: S3Config;
webdav: WebdavConfig;

View File

@ -5,16 +5,28 @@ import {
COMMAND_URI,
UriParams,
RemotelySavePluginSettings,
QRExportType,
} from "./baseTypes";
import { getShrinkedSettings } from "./remoteForOnedrive";
export const exportQrCodeUri = async (
settings: RemotelySavePluginSettings,
currentVaultName: string,
pluginVersion: string
pluginVersion: string,
exportFields: QRExportType
) => {
const settings2: Partial<RemotelySavePluginSettings> = cloneDeep(settings);
delete settings2.dropbox;
delete settings2.onedrive;
let settings2: Partial<RemotelySavePluginSettings> = {};
if (exportFields === "all_but_oauth2") {
settings2 = cloneDeep(settings);
delete settings2.dropbox;
delete settings2.onedrive;
} else if (exportFields === "dropbox") {
settings2 = { dropbox: cloneDeep(settings.dropbox) };
} else if (exportFields === "onedrive") {
settings2 = { onedrive: getShrinkedSettings(settings.onedrive) };
}
delete settings2.vaultRandomID;
const data = encodeURIComponent(JSON.stringify(settings2));
const vault = encodeURIComponent(currentVaultName);
@ -34,6 +46,20 @@ export interface ProcessQrCodeResultType {
result?: RemotelySavePluginSettings;
}
/**
* we also support directly parse the uri, instead of relying on web browser
* @param input
*/
export const parseUriByHand = (input: string) => {
if (!input.startsWith("obsidian://remotely-save?func=settings&")) {
throw Error(`not valid string`);
}
const k = new URL(input);
const output = Object.fromEntries(k.searchParams);
return output;
};
export const importQrCodeUri = (
inputParams: any,
currentVaultName: string

View File

@ -24,7 +24,7 @@
"syncrun_shortstep2": "2/2 Remotely Save finished!",
"syncrun_abort": "{{manifestID}}-{{theDate}}: abort sync, triggerSource={{triggerSource}}, error while {{syncStatus}}",
"syncrun_abort_protectmodifypercentage": "Abort! you set changing files >= {{protectModifyPercentage}}% is not allowed but {{realModifyDeleteCount}}/{{allFilesCount}}={{percent}}% is going to be modified or deleted! If you are sure you want this sync, please adjust the allowed ratio in the settings.",
"protocol_saveqr": "New not-oauth2 settings for {{manifestName}} is saved. Reopen the plugin settings to make it effective.",
"protocol_saveqr": "New settings for {{manifestName}} is imported and saved. Reopen the plugin settings to make it effective.",
"protocol_callbacknotsupported": "Your uri calls a callback that's not supported yet: {{params}}",
"protocol_dropbox_connecting": "Connecting to Dropbox...\nPlease DO NOT close this modal.",
"protocol_dropbox_connect_succ": "Good! We've connected to Dropbox as user {{username}}!",
@ -105,7 +105,7 @@
"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_notice": "You've enabled syncing config folder!",
"modal_qr_shortdesc": "This exports not-oauth2 settings. (It means that Dropbox, OneDrive info are NOT exported.)\nYou can use another device to scan this qrcode.\nOr, you can click the button to copy the special url.",
"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_button": "Click to copy the special URI",
"modal_qr_button_notice": "The special uri is copied to the clipboard!",
"modal_sizesconflict_title": "Remotely Save: Some conflict were found while skipping large files",
@ -278,10 +278,14 @@
"settings_enablemobilestatusbar_desc": "By default Obsidian mobile hides status bar. But some users want to show it up. So here is a hack.",
"settings_importexport": "Import and Export Partial Settings",
"settings_export": "Export",
"settings_export_desc": "Export not-oauth2 settings by generating a qrcode.",
"settings_export_desc_button": "Get QR Code",
"settings_export_desc": "Export settings by generating a QR code or URI.",
"settings_export_all_but_oauth2_button": "Export Non-Oauth2 Part",
"settings_export_dropbox_button": "Export Dropbox Part",
"settings_export_onedrive_button": "Export OneDrive Part",
"settings_import": "Import",
"settings_import_desc": "You should open a camera or scan-qrcode app, to manually scan the QR code.",
"settings_import_desc": "Paste the exported URI into here and click \"Import\". Or, you can open a camera or scan-qrcode app to scan the QR code.",
"settings_import_button": "Import",
"settings_import_error_notice": "Your URI string is empty or not correct!",
"settings_debug": "Debug",
"settings_debuglevel": "Alter Notice Level",
"settings_debuglevel_desc": "By default the notice level is \"info\". You can change to \"debug\" to get verbose information while syncing.",

View File

@ -24,7 +24,7 @@
"syncrun_shortstep2": "2/2 Remotely Save 已完成同步!",
"syncrun_abort": "{{manifestID}}-{{theDate}}:中断同步,同步来源={{triggerSource}},出错阶段={{syncStatus}}",
"syncrun_abort_protectmodifypercentage": "中断同步!您设置了不允许 >= {{protectModifyPercentage}}% 的变更,但是现在 {{realModifyDeleteCount}}/{{allFilesCount}}={{percent}}% 的文件会被修改或删除!如果您确认这次同步是您想要的,那么请在设置里修改允许比例。",
"protocol_saveqr": " {{manifestName}} 新的非 oauth2 设置保存完成。请重启插件设置页使之生效。",
"protocol_saveqr": " {{manifestName}} 的新设置导入完成。请重启插件设置页使之生效。",
"protocol_callbacknotsupported": "您的 uri callback 暂不支持: {{params}}",
"protocol_dropbox_connecting": "正在连接 Dropbox……\n请不要关闭此弹窗。",
"protocol_dropbox_connect_succ": "好!我们作为用户 {{username}} 连接上了 Dropbox",
@ -105,7 +105,7 @@
"modal_syncconfig_attn": "注意 1/2此设置只同步复制整个 Obsidian 的配置文件夹,但是不会同步其它 . 开头的文件夹或文件。除了会忽略 .git 和 node_modules 文件夹之外,它也并不理解配置文件夹的里各个子文件或子文件夹的含义。\n注意 2/2配置文件夹被同步之后各插件的设置或许会出错且 Obsidian 或许需要重启来重载各插件的新配置。\n如果您同意自行承受以上风险您可以点击以下再次确认按钮。",
"modal_syncconfig_secondconfirm": "再次确认开启",
"modal_syncconfig_notice": "您已开启配置文件夹的同步!",
"modal_qr_shortdesc": "这里可导出非 oauth2 设置。意味着Dropbox 和 OneDrive 信息不会被导出。)\n您可以使用另一个设备来扫描此 QR 码。\n又或者您可以点击以下按钮复制此特殊 URI。",
"modal_qr_shortdesc": "这里可导出(部分)设置。\n您可以使用另一个设备来扫描此 QR 码。\n又或者您可以点击以下按钮复制此特殊 URI,然后粘贴到另一台设备的网络浏览器或 Remotely Save 设置里的导入部分。",
"modal_qr_button": "点击此按钮复制特殊 URI",
"modal_qr_button_notice": "特殊 URI 已被复制到剪贴板!",
"modal_sizesconflict_title": "Remotely Save跳过大文件的时候出现了一些冲突",
@ -277,10 +277,14 @@
"settings_enablemobilestatusbar_desc": "Obsidian 手机版默认隐藏了状态栏。有些用户希望展示它。这里提供了设置选项。",
"settings_importexport": "导入导出部分设置",
"settings_export": "导出",
"settings_export_desc": "用 QR 码导出非 oauth2 的设置信息。",
"settings_export_desc_button": "生成 QR 码",
"settings_export_desc": "用 QR 码或 URI 导出设置信息。",
"settings_export_all_but_oauth2_button": "导出非 Oauth2 部分",
"settings_export_dropbox_button": "导出 Dropbox 部分",
"settings_export_onedrive_button": "导出 OneDrive 部分",
"settings_import": "导入",
"settings_import_desc": "您需要使用系统拍摄 app 或者扫描 QR 码的app来扫描对应的 QR 码。",
"settings_import_desc": "粘贴之前导出的 URI 到这里然后点击“导入”。或,使用拍摄 app 或者扫描 QR 码的 app来扫描对应的 QR 码。",
"settings_import_button": "导入",
"settings_import_error_notice": "您输入的 URI 是空的或者不准确的!",
"settings_debug": "调试",
"settings_debuglevel": "修改同步提示信息",
"settings_debuglevel_desc": "默认值为 \"info\"。您可以改为 \"debug\" 从而在同步时候里获取更多信息。",

View File

@ -24,7 +24,7 @@
"syncrun_shortstep2": "2/2 Remotely Save 已完成同步!",
"syncrun_abort": "{{manifestID}}-{{theDate}}:中斷同步,同步來源={{triggerSource}},出錯階段={{syncStatus}}",
"syncrun_abort_protectmodifypercentage": "中斷同步!您設定了不允許 >= {{protectModifyPercentage}}% 的變更,但是現在 {{realModifyDeleteCount}}/{{allFilesCount}}={{percent}}% 的檔案會被修改或刪除!如果您確認這次同步是您想要的,那麼請在設定裡修改允許比例。",
"protocol_saveqr": " {{manifestName}} 新的非 oauth2 設定儲存完成。請重啟外掛設定頁使之生效。",
"protocol_saveqr": " {{manifestName}} 的新設定匯入完成。請重啟外掛設定頁使之生效。",
"protocol_callbacknotsupported": "您的 uri callback 暫不支援: {{params}}",
"protocol_dropbox_connecting": "正在連線 Dropbox……\n請不要關閉此彈窗。",
"protocol_dropbox_connect_succ": "好!我們作為使用者 {{username}} 連線上了 Dropbox",
@ -104,7 +104,7 @@
"modal_syncconfig_attn": "注意 1/2此設定只同步複製整個 Obsidian 的配置資料夾,但是不會同步其它 . 開頭的資料夾或檔案。除了會忽略 .git 和 node_modules 資料夾之外,它也並不理解配置資料夾的裡各個子檔案或子資料夾的含義。\n注意 2/2配置資料夾被同步之後各外掛的設定或許會出錯且 Obsidian 或許需要重啟來過載各外掛的新配置。\n如果您同意自行承受以上風險您可以點選以下再次確認按鈕。",
"modal_syncconfig_secondconfirm": "再次確認開啟",
"modal_syncconfig_notice": "您已開啟配置資料夾的同步!",
"modal_qr_shortdesc": "這裡可匯出非 oauth2 設定。意味著Dropbox 和 OneDrive 資訊不會被匯出。)\n您可以使用另一個裝置來掃描此 QR 碼。\n又或者您可以點選以下按鈕複製此特殊 URI。",
"modal_qr_shortdesc": "這裡可匯出(部分)設定。\n您可以使用另一個裝置來掃描此 QR 碼。\n又或者您可以點選以下按鈕複製此特殊 URI,然後貼上到另一臺裝置的網路瀏覽器或 Remotely Save 設定裡的匯入部分。",
"modal_qr_button": "點選此按鈕複製特殊 URI",
"modal_qr_button_notice": "特殊 URI 已被複制到剪貼簿!",
"modal_sizesconflict_title": "Remotely Save跳過大檔案的時候出現了一些衝突",
@ -276,10 +276,14 @@
"settings_enablemobilestatusbar_desc": "Obsidian 手機版預設隱藏了狀態列。有些使用者希望展示它。這裡提供了設定選項。",
"settings_importexport": "匯入匯出部分設定",
"settings_export": "匯出",
"settings_export_desc": "用 QR 碼匯出非 oauth2 的設定資訊。",
"settings_export_desc_button": "生成 QR 碼",
"settings_export_desc": "用 QR 碼或 URI 匯出設定資訊。",
"settings_export_all_but_oauth2_button": "匯出非 Oauth2 部分",
"settings_export_dropbox_button": "匯出 Dropbox 部分",
"settings_export_onedrive_button": "匯出 OneDrive 部分",
"settings_import": "匯入",
"settings_import_desc": "您需要使用系統拍攝 app 或者掃描 QR 碼的app來掃描對應的 QR 碼。",
"settings_import_desc": "貼上之前匯出的 URI 到這裡然後點選“匯入”。或,使用拍攝 app 或者掃描 QR 碼的 app來掃描對應的 QR 碼。",
"settings_import_button": "匯入",
"settings_import_error_notice": "您輸入的 URI 是空的或者不準確的!",
"settings_debug": "除錯",
"settings_debuglevel": "修改同步提示資訊",
"settings_debuglevel_desc": "預設值為 \"info\"。您可以改為 \"debug\" 從而在同步時候裡獲取更多資訊。",

View File

@ -524,6 +524,7 @@ export default class RemotelySavePlugin extends Plugin {
this.syncStatus = "idle";
this.registerObsidianProtocolHandler(COMMAND_URI, async (inputParams) => {
// console.debug(inputParams);
const parsed = importQrCodeUri(inputParams, this.app.vault.getName());
if (parsed.status === "error") {
new Notice(parsed.message);

View File

@ -407,6 +407,19 @@ class MyAuthProvider implements AuthenticationProvider {
};
}
/**
* to export the settings in qrcode,
* we want to "trim" or "shrink" the settings
* @param onedriveConfig
*/
export const getShrinkedSettings = (onedriveConfig: OnedriveConfig) => {
const config = cloneDeep(onedriveConfig);
config.accessToken = "x";
config.accessTokenExpiresInSeconds = 1;
config.accessTokenExpiresAtTime = 1;
return config;
};
export class WrappedOnedriveClient {
onedriveConfig: OnedriveConfig;
remoteBaseDir: string;

View File

@ -23,9 +23,14 @@ import {
WebdavAuthType,
WebdavDepthType,
CipherMethodType,
QRExportType,
} from "./baseTypes";
import { exportVaultSyncPlansToFiles } from "./debugMode";
import { exportQrCodeUri } from "./importExport";
import {
exportQrCodeUri,
importQrCodeUri,
parseUriByHand,
} from "./importExport";
import {
clearAllPrevSyncRecordByVault,
clearAllSyncPlanRecords,
@ -52,6 +57,7 @@ import {
stringToFragment,
} from "./misc";
import { simpleTransRemotePrefix } from "./remoteForS3";
import cloneDeep from "lodash/cloneDeep";
class PasswordModal extends Modal {
plugin: RemotelySavePlugin;
@ -695,9 +701,11 @@ class SyncConfigDirModal extends Modal {
class ExportSettingsQrCodeModal extends Modal {
plugin: RemotelySavePlugin;
constructor(app: App, plugin: RemotelySavePlugin) {
exportType: QRExportType;
constructor(app: App, plugin: RemotelySavePlugin, exportType: QRExportType) {
super(app);
this.plugin = plugin;
this.exportType = exportType;
}
async onOpen() {
@ -710,7 +718,8 @@ class ExportSettingsQrCodeModal extends Modal {
const { rawUri, imgUri } = await exportQrCodeUri(
this.plugin.settings,
this.app.vault.getName(),
this.plugin.manifest.version
this.plugin.manifest.version,
this.exportType
);
const div1 = contentEl.createDiv();
@ -2128,15 +2137,87 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
.setName(t("settings_export"))
.setDesc(t("settings_export_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_export_desc_button"));
button.setButtonText(t("settings_export_all_but_oauth2_button"));
button.onClick(async () => {
new ExportSettingsQrCodeModal(this.app, this.plugin).open();
new ExportSettingsQrCodeModal(
this.app,
this.plugin,
"all_but_oauth2"
).open();
});
})
.addButton(async (button) => {
button.setButtonText(t("settings_export_dropbox_button"));
button.onClick(async () => {
new ExportSettingsQrCodeModal(
this.app,
this.plugin,
"dropbox"
).open();
});
})
.addButton(async (button) => {
button.setButtonText(t("settings_export_onedrive_button"));
button.onClick(async () => {
new ExportSettingsQrCodeModal(
this.app,
this.plugin,
"onedrive"
).open();
});
});
let importSettingVal = "";
new Setting(importExportDiv)
.setName(t("settings_import"))
.setDesc(t("settings_import_desc"));
.setDesc(t("settings_import_desc"))
.addText((text) =>
text
.setPlaceholder("obsidian://remotely-save?func=settings&...")
.setValue("")
.onChange((val) => {
importSettingVal = val;
})
)
.addButton(async (button) => {
button.setButtonText(t("confirm"));
button.onClick(async () => {
if (importSettingVal !== "") {
// console.debug(importSettingVal);
try {
const inputParams = parseUriByHand(importSettingVal);
const parsed = importQrCodeUri(
inputParams,
this.app.vault.getName()
);
if (parsed.status === "error") {
new Notice(parsed.message);
} else {
const copied = cloneDeep(parsed.result);
// new Notice(JSON.stringify(copied))
this.plugin.settings = Object.assign(
{},
this.plugin.settings,
copied
);
this.plugin.saveSettings();
new Notice(
t("protocol_saveqr", {
manifestName: this.plugin.manifest.name,
})
);
}
} catch (e) {
new Notice(`${e}`);
}
importSettingVal = "";
} else {
new Notice(t("settings_import_error_notice"));
importSettingVal = "";
}
});
});
//////////////////////////////////////////////////
// below for debug