From fa87d870119966b855acd138a2318b601b687609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=40=E5=88=98=E7=BE=A1=E9=B1=BC?= Date: Tue, 16 Sep 2025 08:44:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(sync):=20=E9=80=9A=E8=BF=87=20base64=20?= =?UTF-8?q?=E5=A4=8D=E5=88=B6=E7=B2=98=E8=B4=B4=E9=85=8D=E7=BD=AE=20(#311)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit motivation: 同浏览器多个 profile 简化配置流程,通过同一个同步配置即可实现 --- src/config/setting.js | 1 + src/views/Options/SyncSetting.js | 73 +++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/config/setting.js b/src/config/setting.js index e214e32..da7bdda 100644 --- a/src/config/setting.js +++ b/src/config/setting.js @@ -33,6 +33,7 @@ export const DEFAULT_CSPLIST = ["https://github.com"]; // 禁用CSP名单 // 同步设置 export const OPT_SYNCTYPE_WORKER = "KISS-Worker"; export const OPT_SYNCTYPE_WEBDAV = "WebDAV"; +export const OPT_SYNCTOKEN_PERFIX = "kt_"; export const OPT_SYNCTYPE_ALL = [OPT_SYNCTYPE_WORKER, OPT_SYNCTYPE_WEBDAV]; export const DEFAULT_SYNC = { syncType: OPT_SYNCTYPE_WORKER, // 同步方式 diff --git a/src/views/Options/SyncSetting.js b/src/views/Options/SyncSetting.js index b896639..d260596 100644 --- a/src/views/Options/SyncSetting.js +++ b/src/views/Options/SyncSetting.js @@ -7,18 +7,22 @@ import Alert from "@mui/material/Alert"; import Link from "@mui/material/Link"; import MenuItem from "@mui/material/MenuItem"; import LoadingButton from "@mui/lab/LoadingButton"; +import Button from "@mui/material/Button"; import { URL_KISS_WORKER, OPT_SYNCTYPE_ALL, OPT_SYNCTYPE_WORKER, OPT_SYNCTYPE_WEBDAV, + OPT_SYNCTOKEN_PERFIX, } from "../../config"; import { useState } from "react"; import { syncSettingAndRules } from "../../libs/sync"; import { useAlert } from "../../hooks/Alert"; -import SyncIcon from "@mui/icons-material/Sync"; import { useSetting } from "../../hooks/Setting"; import { kissLog } from "../../libs/log"; +import SyncIcon from "@mui/icons-material/Sync"; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import ContentPasteIcon from '@mui/icons-material/ContentPaste'; export default function SyncSetting() { const i18n = useI18n(); @@ -50,6 +54,57 @@ export default function SyncSetting() { } }; + const handleGenerateShareString = async () => { + try { + const base64Config = btoa(JSON.stringify({ + syncType: syncType, + syncUrl: syncUrl, + syncUser: syncUser, + syncKey: syncKey, + })); + const shareString = `${OPT_SYNCTOKEN_PERFIX}${base64Config}`; + await navigator.clipboard.writeText(shareString); + console.debug("Share string copied to clipboard", shareString); + } catch (error) { + console.error("Failed to copy share string to clipboard", error); + } + }; + + const handleImportFromClipboard = async () => { + try { + const text = await navigator.clipboard.readText(); + console.debug('read_clipboard', text) + if (text.startsWith(OPT_SYNCTOKEN_PERFIX)) { + const base64Config = text.slice(OPT_SYNCTOKEN_PERFIX.length); + const jsonString = atob(base64Config); + const updatedConfig = JSON.parse(jsonString); + + if (!OPT_SYNCTYPE_ALL.includes(updatedConfig.syncType)) { + console.error('error syncType', updatedConfig.syncType) + return; + } + + if ( + updatedConfig.syncUrl + ) { + updateSync({ + syncType: updatedConfig.syncType, + syncUrl: updatedConfig.syncUrl, + syncUser: updatedConfig.syncUser, + syncKey: updatedConfig.syncKey, + }); + } else { + console.error("Invalid config structure"); + } + } else { + console.error("Invalid share string", text); + } + } catch (error) { + console.error("Failed to read from clipboard or parse JSON", error); + } + }; + + if (!sync) { return; } @@ -133,6 +188,22 @@ export default function SyncSetting() { > {i18n("sync_now")} + +