This commit is contained in:
2025-04-15 00:52:23 +08:00
parent b76a685988
commit c7763227d0
24 changed files with 748 additions and 384 deletions

View File

@ -19,26 +19,26 @@ const userscriptsConfig = {
},
};
const userscriptsRules = Object.fromEntries(
Object.keys(userscriptsConfig.rules).map((name) => {
const ruleName = name.split("/")[1];
// eslint-disable-next-line import/no-dynamic-require, global-require
const ruleMeta = require(`eslint-plugin-userscripts/lib/rules/${ruleName}.js`);
return [
name,
{
...ruleMeta,
meta: {
...ruleMeta.meta,
docs: {
...ruleMeta.meta.docs,
url: `https://yash-singh1.github.io/eslint-plugin-userscripts/#/rules/${ruleName}`,
},
},
},
];
})
);
// const userscriptsRules = Object.fromEntries(
// Object.keys(userscriptsConfig.rules).map((name) => {
// const ruleName = name.split("/")[1];
// // eslint-disable-next-line import/no-dynamic-require, global-require
// const ruleMeta = require(`eslint-plugin-userscripts/lib/rules/${ruleName}.js`);
// return [
// name,
// {
// ...ruleMeta,
// meta: {
// ...ruleMeta.meta,
// docs: {
// ...ruleMeta.meta.docs,
// url: `https://yash-singh1.github.io/eslint-plugin-userscripts/#/rules/${ruleName}`,
// },
// },
// },
// ];
// })
// );
// 默认规则
const config = {
@ -128,4 +128,4 @@ const config = {
// 以文本形式导出默认规则
const defaultConfig = JSON.stringify(config);
export { defaultConfig, userscriptsConfig, userscriptsRules };
export { defaultConfig, userscriptsConfig };

View File

@ -39,6 +39,7 @@
"react-router-dom": "^7.1.1",
"semver": "^7.6.3",
"uuid": "^11.0.3",
"webdav": "^5.8.0",
"yaml": "^2.6.1"
},
"devDependencies": {
@ -63,6 +64,7 @@
"eslint": "^9.24.0",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-userscripts": "^0.5.6",
"fake-indexeddb": "^6.0.0",
"globals": "^16.0.0",
"jsdom": "^25.0.1",

View File

@ -1,7 +1,4 @@
/* eslint-disable camelcase */
/* eslint-disable import/prefer-default-export */
import { ExtServer } from "@App/app/const";
import { api } from "@App/pkg/axios";
import { ExtServer, ExtServerApi } from "@App/app/const";
import { WarpTokenError } from "./error";
type NetDiskType = "baidu" | "onedrive";
@ -11,8 +8,8 @@ export function GetNetDiskToken(netDiskType: NetDiskType): Promise<{
msg: string;
data: { token: { access_token: string; refresh_token: string } };
}> {
return api
.get(`/auth/net-disk/token?netDiskType=${netDiskType}`)
return fetch(ExtServerApi + `auth/net-disk/token?netDiskType=${netDiskType}`)
.then((resp) => resp.json())
.then((resp) => {
return resp.data;
});
@ -26,11 +23,17 @@ export function RefreshToken(
msg: string;
data: { token: { access_token: string; refresh_token: string } };
}> {
return api
.post(`/auth/net-disk/token/refresh?netDiskType=${netDiskType}`, {
return fetch(ExtServerApi + `auth/net-disk/token/refresh?netDiskType=${netDiskType}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
netDiskType,
refreshToken,
})
}),
})
.then((resp) => resp.json())
.then((resp) => {
return resp.data;
});
@ -38,9 +41,7 @@ export function RefreshToken(
export function NetDisk(netDiskType: NetDiskType) {
return new Promise<void>((resolve) => {
const loginWindow = window.open(
`${ExtServer}api/v1/auth/net-disk?netDiskType=${netDiskType}`
);
const loginWindow = window.open(`${ExtServer}api/v1/auth/net-disk?netDiskType=${netDiskType}`);
const t = setInterval(() => {
try {
if (loginWindow!.closed) {

View File

@ -1,5 +1,3 @@
/* eslint-disable no-unused-vars */
import IoC from "@App/app/ioc";
import { SystemConfig } from "@App/pkg/config/config";
import { AuthVerify } from "../auth";
import FileSystem, { File, FileReader, FileWriter } from "../filesystem";
@ -11,12 +9,9 @@ export default class BaiduFileSystem implements FileSystem {
path: string;
systemConfig: SystemConfig;
constructor(path?: string, accessToken?: string) {
this.path = path || "/apps";
this.accessToken = accessToken;
this.systemConfig = IoC.instance(SystemConfig) as SystemConfig;
}
async verify(): Promise<void> {
@ -31,15 +26,11 @@ export default class BaiduFileSystem implements FileSystem {
}
openDir(path: string): Promise<FileSystem> {
return Promise.resolve(
new BaiduFileSystem(joinPath(this.path, path), this.accessToken)
);
return Promise.resolve(new BaiduFileSystem(joinPath(this.path, path), this.accessToken));
}
create(path: string): Promise<FileWriter> {
return Promise.resolve(
new BaiduFileWriter(this, joinPath(this.path, path))
);
return Promise.resolve(new BaiduFileWriter(this, joinPath(this.path, path)));
}
createDir(dir: string): Promise<void> {
@ -51,15 +42,12 @@ export default class BaiduFileSystem implements FileSystem {
urlencoded.append("rtype", "3");
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
return this.request(
`https://pan.baidu.com/rest/2.0/xpan/file?method=create&access_token=${this.accessToken}`,
{
method: "POST",
headers: myHeaders,
body: urlencoded,
redirect: "follow",
}
).then((data) => {
return this.request(`https://pan.baidu.com/rest/2.0/xpan/file?method=create&access_token=${this.accessToken}`, {
method: "POST",
headers: myHeaders,
body: urlencoded,
redirect: "follow",
}).then((data) => {
if (data.errno) {
throw new Error(JSON.stringify(data));
}
@ -71,9 +59,23 @@ export default class BaiduFileSystem implements FileSystem {
request(url: string, config?: RequestInit) {
config = config || {};
const headers = <Headers>config.headers || new Headers();
// 利用GM函数的匿名实现不发送cookie,因为某些情况cookie会导致-6错误
headers.append(`${this.systemConfig.scriptCatFlag}-gm-xhr`, "true");
headers.append(`${this.systemConfig.scriptCatFlag}-anonymous`, "true");
// 处理请求匿名不发送cookie
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: [100],
addRules: [
{
id: 100,
action: {
type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS,
responseHeaders: [{ operation: chrome.declarativeNetRequest.HeaderOperation.REMOVE, header: "cookie" }],
},
condition: {
urlFilter: url,
resourceTypes: [chrome.declarativeNetRequest.ResourceType.XMLHTTPREQUEST],
},
},
],
});
config.headers = headers;
return fetch(url, config)
.then((data) => data.json())
@ -92,6 +94,11 @@ export default class BaiduFileSystem implements FileSystem {
});
}
return data;
})
.finally(() => {
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: [100],
});
});
}
@ -103,9 +110,7 @@ export default class BaiduFileSystem implements FileSystem {
`https://pan.baidu.com/rest/2.0/xpan/file?method=filemanager&access_token=${this.accessToken}&opera=delete`,
{
method: "POST",
body: `async=0&filelist=${encodeURIComponent(
JSON.stringify(filelist)
)}`,
body: `async=0&filelist=${encodeURIComponent(JSON.stringify(filelist))}`,
headers: myHeaders,
}
).then((data) => {
@ -145,10 +150,6 @@ export default class BaiduFileSystem implements FileSystem {
}
getDirUrl(): Promise<string> {
return Promise.resolve(
`https://pan.baidu.com/disk/main#/index?category=all&path=${encodeURIComponent(
this.path
)}`
);
return Promise.resolve(`https://pan.baidu.com/disk/main#/index?category=all&path=${encodeURIComponent(this.path)}`);
}
}

View File

@ -1,6 +1,3 @@
/* eslint-disable no-unused-vars */
import IoC from "@App/app/ioc";
import { SystemConfig } from "@App/pkg/config/config";
import { AuthVerify } from "../auth";
import FileSystem, { File, FileReader, FileWriter } from "../filesystem";
import { joinPath } from "../utils";
@ -11,12 +8,9 @@ export default class OneDriveFileSystem implements FileSystem {
path: string;
systemConfig: SystemConfig;
constructor(path?: string, accessToken?: string) {
this.path = path || "/";
this.accessToken = accessToken;
this.systemConfig = IoC.instance(SystemConfig) as SystemConfig;
}
async verify(): Promise<void> {
@ -33,15 +27,11 @@ export default class OneDriveFileSystem implements FileSystem {
if (path.startsWith("ScriptCat")) {
path = path.substring(9);
}
return Promise.resolve(
new OneDriveFileSystem(joinPath(this.path, path), this.accessToken)
);
return Promise.resolve(new OneDriveFileSystem(joinPath(this.path, path), this.accessToken));
}
create(path: string): Promise<FileWriter> {
return Promise.resolve(
new OneDriveFileWriter(this, joinPath(this.path, path))
);
return Promise.resolve(new OneDriveFileWriter(this, joinPath(this.path, path)));
}
createDir(dir: string): Promise<void> {
@ -65,18 +55,15 @@ export default class OneDriveFileSystem implements FileSystem {
if (parent !== "") {
parent = `:${parent}:`;
}
return this.request(
`https://graph.microsoft.com/v1.0/me/drive/special/approot${parent}/children`,
{
method: "POST",
headers: myHeaders,
body: JSON.stringify({
name: dirs[dirs.length - 1],
folder: {},
"@microsoft.graph.conflictBehavior": "replace",
}),
}
).then((data: any) => {
return this.request(`https://graph.microsoft.com/v1.0/me/drive/special/approot${parent}/children`, {
method: "POST",
headers: myHeaders,
body: JSON.stringify({
name: dirs[dirs.length - 1],
folder: {},
"@microsoft.graph.conflictBehavior": "replace",
}),
}).then((data: any) => {
if (data.errno) {
throw new Error(JSON.stringify(data));
}
@ -84,7 +71,6 @@ export default class OneDriveFileSystem implements FileSystem {
});
}
// eslint-disable-next-line no-undef
request(url: string, config?: RequestInit, nothen?: boolean) {
config = config || {};
const headers = <Headers>config.headers || new Headers();
@ -121,10 +107,7 @@ export default class OneDriveFileSystem implements FileSystem {
delete(path: string): Promise<void> {
return this.request(
`https://graph.microsoft.com/v1.0/me/drive/special/approot:${joinPath(
this.path,
path
)}`,
`https://graph.microsoft.com/v1.0/me/drive/special/approot:${joinPath(this.path, path)}`,
{
method: "DELETE",
},
@ -144,9 +127,7 @@ export default class OneDriveFileSystem implements FileSystem {
} else {
path = `:${path}:`;
}
return this.request(
`https://graph.microsoft.com/v1.0/me/drive/special/approot${path}/children`
).then((data) => {
return this.request(`https://graph.microsoft.com/v1.0/me/drive/special/approot${path}/children`).then((data) => {
const list: File[] = [];
data.value.forEach((val: any) => {
list.push({

View File

@ -1,6 +1,4 @@
/* eslint-disable max-classes-per-file */
/* eslint-disable import/prefer-default-export */
import { WebDAVClient } from "webdav/web";
import { WebDAVClient } from "webdav";
import { FileReader, FileWriter } from "../filesystem";
export class WebDAVFileReader implements FileReader {
@ -42,10 +40,7 @@ export class WebDAVFileWriter implements FileWriter {
async write(content: string | Blob): Promise<void> {
let resp;
if (content instanceof Blob) {
resp = await this.client.putFileContents(
this.path,
await content.arrayBuffer()
);
resp = await this.client.putFileContents(this.path, await content.arrayBuffer());
} else {
resp = await this.client.putFileContents(this.path, content);
}

View File

@ -1,4 +1,4 @@
import { AuthType, createClient, FileStat, WebDAVClient } from "webdav/web";
import { AuthType, createClient, FileStat, WebDAVClient } from "webdav";
import FileSystem, { File, FileReader, FileWriter } from "../filesystem";
import { joinPath } from "../utils";
import { WebDAVFileReader, WebDAVFileWriter } from "./rw";
@ -11,12 +11,7 @@ export default class WebDAVFileSystem implements FileSystem {
basePath: string = "/";
constructor(
authType: AuthType | WebDAVClient,
url?: string,
username?: string,
password?: string
) {
constructor(authType: AuthType | WebDAVClient, url?: string, username?: string, password?: string) {
if (typeof authType === "object") {
this.client = authType;
this.basePath = joinPath(url || "");
@ -44,28 +39,20 @@ export default class WebDAVFileSystem implements FileSystem {
}
open(file: File): Promise<FileReader> {
return Promise.resolve(
new WebDAVFileReader(this.client, joinPath(file.path, file.name))
);
return Promise.resolve(new WebDAVFileReader(this.client, joinPath(file.path, file.name)));
}
openDir(path: string): Promise<FileSystem> {
return Promise.resolve(
new WebDAVFileSystem(this.client, joinPath(this.basePath, path), this.url)
);
return Promise.resolve(new WebDAVFileSystem(this.client, joinPath(this.basePath, path), this.url));
}
create(path: string): Promise<FileWriter> {
return Promise.resolve(
new WebDAVFileWriter(this.client, joinPath(this.basePath, path))
);
return Promise.resolve(new WebDAVFileWriter(this.client, joinPath(this.basePath, path)));
}
async createDir(path: string): Promise<void> {
try {
return Promise.resolve(
await this.client.createDirectory(joinPath(this.basePath, path))
);
return Promise.resolve(await this.client.createDirectory(joinPath(this.basePath, path)));
} catch (e: any) {
// 如果是405错误,则忽略
if (e.message.includes("405")) {
@ -80,9 +67,7 @@ export default class WebDAVFileSystem implements FileSystem {
}
async list(): Promise<File[]> {
const dir = (await this.client.getDirectoryContents(
this.basePath
)) as FileStat[];
const dir = (await this.client.getDirectoryContents(this.basePath)) as FileStat[];
const ret: File[] = [];
dir.forEach((item: FileStat) => {
if (item.type !== "file") {

195
pnpm-lock.yaml generated
View File

@ -74,6 +74,9 @@ importers:
uuid:
specifier: ^11.0.3
version: 11.0.3
webdav:
specifier: ^5.8.0
version: 5.8.0
yaml:
specifier: ^2.6.1
version: 2.6.1
@ -141,6 +144,9 @@ importers:
eslint-plugin-react-hooks:
specifier: ^5.2.0
version: 5.2.0(eslint@9.24.0(jiti@1.21.7))
eslint-plugin-userscripts:
specifier: ^0.5.6
version: 0.5.6(eslint@9.24.0(jiti@1.21.7))
fake-indexeddb:
specifier: ^6.0.0
version: 6.0.0
@ -352,6 +358,9 @@ packages:
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
'@buttercup/fetch@0.2.1':
resolution: {integrity: sha512-sCgECOx8wiqY8NN1xN22BqqKzXYIG2AicNLlakOAI4f0WgyLVUbAigMf8CZhBtJxdudTcB1gD5lciqi44jwJvg==}
'@cspotcode/source-map-support@0.8.1':
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
@ -967,55 +976,46 @@ packages:
resolution: {integrity: sha512-10ICosOwYChROdQoQo589N5idQIisxjaFE/PAnX2i0Zr84mY0k9zul1ArH0rnJ/fpgiqfu13TFZR5A5YJLOYZA==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.24.4':
resolution: {integrity: sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.24.4':
resolution: {integrity: sha512-uHYJ0HNOI6pGEeZ/5mgm5arNVTI0nLlmrbdph+pGXpC9tFHFDQmDMOEqkmUObRfosJqpU8RliYoGz06qSdtcjg==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.24.4':
resolution: {integrity: sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-powerpc64le-gnu@4.24.4':
resolution: {integrity: sha512-q73XUPnkwt9ZNF2xRS4fvneSuaHw2BXuV5rI4cw0fWYVIWIBeDZX7c7FWhFQPNTnE24172K30I+dViWRVD9TwA==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.24.4':
resolution: {integrity: sha512-Aie/TbmQi6UXokJqDZdmTJuZBCU3QBDA8oTKRGtd4ABi/nHgXICulfg1KI6n9/koDsiDbvHAiQO3YAUNa/7BCw==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-s390x-gnu@4.24.4':
resolution: {integrity: sha512-P8MPErVO/y8ohWSP9JY7lLQ8+YMHfTI4bAdtCi3pC2hTeqFJco2jYspzOzTUB8hwUWIIu1xwOrJE11nP+0JFAQ==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.24.4':
resolution: {integrity: sha512-K03TljaaoPK5FOyNMZAAEmhlyO49LaE4qCsr0lYHUKyb6QacTNF9pnfPpXnFlFD3TXuFbFbz7tJ51FujUXkXYA==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.24.4':
resolution: {integrity: sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.24.4':
resolution: {integrity: sha512-ku2GvtPwQfCqoPFIJCqZ8o7bJcj+Y54cZSr43hHca6jLwAiCbZdBUOrqE6y29QFajNAzzpIOwsckaTFmN6/8TA==}
@ -1080,7 +1080,6 @@ packages:
resolution: {integrity: sha512-nJzY+Ur6FxWM0xc+G2tY1TQu3s6qgolxXb5K2VLIDHSPqDAjqRc35ypQc9Tz3rUPb8HVh+X7YLIZxA0hE4eQOg==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rspack/binding-linux-arm64-musl@1.0.14':
resolution: {integrity: sha512-qgybhxI/nnoa8CUz7zKTC0Oh37NZt9uRxsSV7+ZYrfxqbrVCoNVuutPpY724uUHy1M6W34kVEm1uT1N4Ka5cZg==}
@ -1092,7 +1091,6 @@ packages:
resolution: {integrity: sha512-sRi77ccO/oOfyBNq3FgW2pDtXcgMzslLokOby8NpD/kv/SxtOE4ORoLZKzdJyGNh2WDPbtSwIDWPes2x4MKASQ==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rspack/binding-linux-x64-gnu@1.0.14':
resolution: {integrity: sha512-5vzaDRw3/sGKo3ax/1cU3/cxqNjajwlt2LU288vXNe1/n8oe/pcDfYcTugpOe/A1DqzadanudJszLpFcKsaFtQ==}
@ -1104,7 +1102,6 @@ packages:
resolution: {integrity: sha512-KnrFQUj6SKJFGXqJW9Kgdv+mRGcPCirQesuwXtW+9YejT6MzLRRdJ4NDQdfcmfLZK9+ap+l73bLXAyMiIBZiOw==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rspack/binding-linux-x64-musl@1.0.14':
resolution: {integrity: sha512-4U6QD9xVS1eGme52DuJr6Fg/KdcUfJ+iKwH49Up460dZ/fLvGylnVGA+V0mzPlKi8gfy7NwFuYXZdu3Pwi1YYg==}
@ -1116,7 +1113,6 @@ packages:
resolution: {integrity: sha512-ZcTl4LBgxp5Bfyu9x7NhYRAR4qWPwhhxzwXmiQ1ya7DsdqiYaiCr59dPQx7ZaExXckeHGly75B3aTn1II9Vexw==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rspack/binding-win32-arm64-msvc@1.0.14':
resolution: {integrity: sha512-SjeYw7qqRHYZ5RPClu+ffKZsShQdU3amA1OwC3M0AS6dbfEcji8482St3Y8Z+QSzYRapCEZij9LMM/9ypEhISg==}
@ -1836,6 +1832,9 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
base-64@1.0.0:
resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==}
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@ -1898,6 +1897,9 @@ packages:
peerDependencies:
esbuild: '>=0.18'
byte-length@1.0.2:
resolution: {integrity: sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==}
bytes@3.0.0:
resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
engines: {node: '>= 0.8'}
@ -1944,6 +1946,9 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
charenc@0.0.2:
resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
check-error@2.1.1:
resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
engines: {node: '>= 16'}
@ -2094,6 +2099,9 @@ packages:
engines: {node: '>=10'}
hasBin: true
crypt@0.0.2:
resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
@ -2108,6 +2116,10 @@ packages:
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
data-uri-to-buffer@4.0.1:
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
engines: {node: '>= 12'}
data-urls@5.0.0:
resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
engines: {node: '>=18'}
@ -2299,6 +2311,10 @@ packages:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
entities@6.0.0:
resolution: {integrity: sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==}
engines: {node: '>=0.12'}
env-paths@2.2.1:
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
engines: {node: '>=6'}
@ -2408,6 +2424,12 @@ packages:
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
eslint-plugin-userscripts@0.5.6:
resolution: {integrity: sha512-/DXb8UKyEkNCzXOA6j4E4rCWn2mLCUw2TMxrzSoz3spi4cyANlE0JNmtRleAmzc1HTUmZXr5fIMCQxyLS73DZQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: '>=8.40.0 <11'
eslint-scope@5.1.1:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
engines: {node: '>=8.0.0'}
@ -2544,6 +2566,10 @@ packages:
fast-uri@3.0.3:
resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==}
fast-xml-parser@4.5.3:
resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==}
hasBin: true
fastq@1.17.1:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
@ -2567,6 +2593,10 @@ packages:
picomatch:
optional: true
fetch-blob@3.2.0:
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
engines: {node: ^12.20 || >= 14.13}
file-entry-cache@8.0.0:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
@ -2614,6 +2644,10 @@ packages:
resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==}
engines: {node: '>= 6'}
formdata-polyfill@4.0.10:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
forwarded@0.2.0:
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
engines: {node: '>= 0.6'}
@ -2770,6 +2804,9 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
hot-patcher@2.0.1:
resolution: {integrity: sha512-ECg1JFG0YzehicQaogenlcs2qg6WsXQsxtnbr1i696u5tLUjtJdQAh0u2g0Q5YV45f263Ta1GnUJsc8WIfJf4Q==}
hpack.js@2.1.6:
resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==}
@ -2931,6 +2968,9 @@ packages:
resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
engines: {node: '>= 0.4'}
is-buffer@1.1.6:
resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
is-callable@1.2.7:
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
engines: {node: '>= 0.4'}
@ -3198,6 +3238,9 @@ packages:
launch-editor@2.9.1:
resolution: {integrity: sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==}
layerr@3.0.0:
resolution: {integrity: sha512-tv754Ki2dXpPVApOrjTyRo4/QegVb9eVFq4mjqp4+NM5NaX7syQvN5BBNfV/ZpAHCEHV24XdUVrBAoka4jt3pA==}
lazystream@1.0.1:
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
engines: {node: '>= 0.6.3'}
@ -3283,6 +3326,9 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
md5@2.3.0:
resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
mdn-data@2.12.1:
resolution: {integrity: sha512-rsfnCbOHjqrhWxwt5/wtSLzpoKTzW7OXdT5lLOIH1OTYhWu9rRJveGq0sKvDZODABH7RX+uoR+DYcpFnq4Tf6Q==}
@ -3403,9 +3449,20 @@ packages:
neo-async@2.6.2:
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
nested-property@4.0.0:
resolution: {integrity: sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==}
node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
node-fetch-native@1.6.4:
resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==}
node-fetch@3.3.2:
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
node-forge@1.3.1:
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
engines: {node: '>= 6.13.0'}
@ -3576,6 +3633,9 @@ packages:
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
path-posix@1.0.0:
resolution: {integrity: sha512-1gJ0WpNIiYcQydgg3Ed8KzvIqTsDpNwq+cjBCssvBtuTWjEqY1AW+i+OepiEMqDCzyro9B2sLAe4RBPajMYFiA==}
path-scurry@1.11.1:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
@ -3681,6 +3741,9 @@ packages:
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
engines: {node: '>=0.6'}
querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@ -4195,6 +4258,9 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
strnum@1.1.2:
resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==}
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@ -4495,6 +4561,13 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
url-join@5.0.0:
resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
url-parse@1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
use-callback-ref@1.3.2:
resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==}
engines: {node: '>=10'}
@ -4631,6 +4704,14 @@ packages:
wbuf@1.7.3:
resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==}
web-streams-polyfill@3.3.3:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
webdav@5.8.0:
resolution: {integrity: sha512-iuFG7NamJ41Oshg4930iQgfIpRrUiatPWIekeznYgEf2EOraTRcDPTjy7gIOMtkdpKTaqPk1E68NO5PAGtJahA==}
engines: {node: '>=14'}
webidl-conversions@7.0.0:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
@ -4918,6 +4999,10 @@ snapshots:
'@bcoe/v8-coverage@0.2.3': {}
'@buttercup/fetch@0.2.1':
optionalDependencies:
node-fetch: 3.3.2
'@cspotcode/source-map-support@0.8.1':
dependencies:
'@jridgewell/trace-mapping': 0.3.9
@ -6571,6 +6656,8 @@ snapshots:
balanced-match@1.0.2: {}
base-64@1.0.0: {}
base64-js@1.5.1: {}
batch@0.6.1: {}
@ -6657,6 +6744,8 @@ snapshots:
esbuild: 0.23.1
load-tsconfig: 0.2.5
byte-length@1.0.2: {}
bytes@3.0.0: {}
bytes@3.1.2: {}
@ -6707,6 +6796,8 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
charenc@0.0.2: {}
check-error@2.1.1: {}
chokidar@3.6.0:
@ -6873,6 +6964,8 @@ snapshots:
node-rsa: 1.1.1
pbf: 3.3.0
crypt@0.0.2: {}
crypto-js@4.2.0: {}
css-tree@3.0.1:
@ -6886,6 +6979,8 @@ snapshots:
csstype@3.1.3: {}
data-uri-to-buffer@4.0.1: {}
data-urls@5.0.0:
dependencies:
whatwg-mimetype: 4.0.0
@ -7048,6 +7143,8 @@ snapshots:
entities@4.5.0: {}
entities@6.0.0: {}
env-paths@2.2.1: {}
error-ex@1.3.2:
@ -7352,6 +7449,11 @@ snapshots:
string.prototype.matchall: 4.0.12
string.prototype.repeat: 1.0.0
eslint-plugin-userscripts@0.5.6(eslint@9.24.0(jiti@1.21.7)):
dependencies:
eslint: 9.24.0(jiti@1.21.7)
semver: 7.6.3
eslint-scope@5.1.1:
dependencies:
esrecurse: 4.3.0
@ -7606,6 +7708,10 @@ snapshots:
fast-uri@3.0.3: {}
fast-xml-parser@4.5.3:
dependencies:
strnum: 1.1.2
fastq@1.17.1:
dependencies:
reusify: 1.0.4
@ -7623,6 +7729,11 @@ snapshots:
picomatch: 4.0.2
optional: true
fetch-blob@3.2.0:
dependencies:
node-domexception: 1.0.0
web-streams-polyfill: 3.3.3
file-entry-cache@8.0.0:
dependencies:
flat-cache: 4.0.1
@ -7676,6 +7787,10 @@ snapshots:
combined-stream: 1.0.8
mime-types: 2.1.35
formdata-polyfill@4.0.10:
dependencies:
fetch-blob: 3.2.0
forwarded@0.2.0: {}
fraction.js@4.3.7: {}
@ -7837,6 +7952,8 @@ snapshots:
dependencies:
function-bind: 1.1.2
hot-patcher@2.0.1: {}
hpack.js@2.1.6:
dependencies:
inherits: 2.0.4
@ -8020,6 +8137,8 @@ snapshots:
call-bound: 1.0.3
has-tostringtag: 1.0.2
is-buffer@1.1.6: {}
is-callable@1.2.7: {}
is-core-module@2.15.1:
@ -8307,6 +8426,8 @@ snapshots:
picocolors: 1.1.1
shell-quote: 1.8.1
layerr@3.0.0: {}
lazystream@1.0.1:
dependencies:
readable-stream: 2.3.8
@ -8382,6 +8503,12 @@ snapshots:
math-intrinsics@1.1.0: {}
md5@2.3.0:
dependencies:
charenc: 0.0.2
crypt: 0.0.2
is-buffer: 1.1.6
mdn-data@2.12.1: {}
media-typer@0.3.0: {}
@ -8474,8 +8601,18 @@ snapshots:
neo-async@2.6.2:
optional: true
nested-property@4.0.0: {}
node-domexception@1.0.0: {}
node-fetch-native@1.6.4: {}
node-fetch@3.3.2:
dependencies:
data-uri-to-buffer: 4.0.1
fetch-blob: 3.2.0
formdata-polyfill: 4.0.10
node-forge@1.3.1: {}
node-releases@2.0.18: {}
@ -8653,6 +8790,8 @@ snapshots:
path-parse@1.0.7: {}
path-posix@1.0.0: {}
path-scurry@1.11.1:
dependencies:
lru-cache: 10.4.3
@ -8742,6 +8881,8 @@ snapshots:
dependencies:
side-channel: 1.1.0
querystringify@2.2.0: {}
queue-microtask@1.2.3: {}
randombytes@2.1.0:
@ -9400,6 +9541,8 @@ snapshots:
strip-json-comments@3.1.1: {}
strnum@1.1.2: {}
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
@ -9769,6 +9912,13 @@ snapshots:
dependencies:
punycode: 2.3.1
url-join@5.0.0: {}
url-parse@1.5.10:
dependencies:
querystringify: 2.2.0
requires-port: 1.0.0
use-callback-ref@1.3.2(@types/react@18.3.12)(react@18.3.1):
dependencies:
react: 18.3.1
@ -9954,6 +10104,25 @@ snapshots:
dependencies:
minimalistic-assert: 1.0.1
web-streams-polyfill@3.3.3: {}
webdav@5.8.0:
dependencies:
'@buttercup/fetch': 0.2.1
base-64: 1.0.0
byte-length: 1.0.2
entities: 6.0.0
fast-xml-parser: 4.5.3
hot-patcher: 2.0.1
layerr: 3.0.0
md5: 2.3.0
minimatch: 9.0.5
nested-property: 4.0.0
node-fetch: 3.3.2
path-posix: 1.0.0
url-join: 5.0.0
url-parse: 1.5.10
webidl-conversions@7.0.0: {}
webpack-bundle-analyzer@4.10.2:

View File

@ -3,12 +3,8 @@ import { version } from "../../package.json";
export const ExtVersion = version;
export const ExtServer = "https://ext.scriptcat.org/";
export const ExtServerApi = ExtServer + "api/v1/";
export const ExternalWhitelist = [
"greasyfork.org",
"scriptcat.org",
"tampermonkey.net.cn",
"openuserjs.org",
];
export const ExternalWhitelist = ["greasyfork.org", "scriptcat.org", "tampermonkey.net.cn", "openuserjs.org"];
export const ExternalMessage = "externalMessage";

View File

@ -358,5 +358,6 @@
"collapse": "Collapse",
"expand": "Expand",
"menu_expand_num_before": "Menu item more than",
"menu_expand_num_after": "Auto-hide."
"menu_expand_num_after": "Auto-hide.",
"eslint_config_format_error": "ESLint configuration format error"
}

View File

@ -363,5 +363,6 @@
"expand": "展开",
"menu_expand_num_before": "菜单项超过",
"menu_expand_num_after": "个时,自动隐藏",
"script_name_cannot_be_set_to_empty": "脚本name不可以设置为空"
"script_name_cannot_be_set_to_empty": "脚本name不可以设置为空",
"eslint_config_format_error": "eslint配置格式错误"
}

View File

@ -1,6 +1,8 @@
import React from "react";
import { Input, Select, Space } from "@arco-design/web-react";
import FileSystemFactory, { FileSystemType } from "@Packages/filesystem/factory";
const fsParams = FileSystemFactory.params();
const fileSystemList: {
key: FileSystemType;
@ -65,10 +67,7 @@ const FileSystemParams: React.FC<{
<>
<span>{fsParams[fileSystemType][key].title}</span>
<Select
value={
fileSystemParams[key] ||
fsParams[fileSystemType][key].options![0]
}
value={fileSystemParams[key] || fsParams[fileSystemType][key].options![0]}
onChange={(value) => {
onChangeFileSystemParams({
...fileSystemParams,

View File

@ -1,29 +1,28 @@
import React, { useState } from "react";
import {
Button,
Card,
Collapse,
Link,
Message,
Space,
Typography,
} from "@arco-design/web-react";
import React, { useEffect, useState } from "react";
import { Button, Card, Collapse, Link, Message, Space, Typography } from "@arco-design/web-react";
import { useTranslation } from "react-i18next";
import FileSystemParams from "../FileSystemParams";
import { systemConfig } from "@App/pages/store/global";
import { FileSystemType } from "@Packages/filesystem/factory";
const CollapseItem = Collapse.Item;
const GMApiSetting: React.FC = () => {
const systemConfig = IoC.instance(SystemConfig) as SystemConfig;
const [status, setStatus] = useState(systemConfig.catFileStorage.status);
const [fileSystemType, setFilesystemType] = useState<FileSystemType>(
systemConfig.catFileStorage.filesystem
);
const [status, setStatus] = useState("unset");
const [fileSystemType, setFilesystemType] = useState<FileSystemType>("webdav");
const [fileSystemParams, setFilesystemParam] = useState<{
[key: string]: any;
}>(systemConfig.catFileStorage.params[fileSystemType] || {});
}>({});
const { t } = useTranslation();
useEffect(() => {
systemConfig.getCatFileStorage().then((res) => {
setStatus(res.status);
setFilesystemType(res.filesystem);
setFilesystemParam(res.params[res.filesystem] || {});
});
}, []);
return (
<Card title={t("gm_api")} bordered={false}>
<Collapse bordered={false} defaultActiveKey={["storage"]}>
@ -48,10 +47,7 @@ const GMApiSetting: React.FC = () => {
type="primary"
onClick={async () => {
try {
await FileSystemFactory.create(
fileSystemType,
fileSystemParams
);
await FileSystemFactory.create(fileSystemType, fileSystemParams);
} catch (e) {
Message.error(`${t("account_validation_failed")}: ${e}`);
return;
@ -87,10 +83,7 @@ const GMApiSetting: React.FC = () => {
type="secondary"
onClick={async () => {
try {
let fs = await FileSystemFactory.create(
fileSystemType,
fileSystemParams
);
let fs = await FileSystemFactory.create(fileSystemType, fileSystemParams);
fs = await fs.openDir("ScriptCat/app");
window.open(await fs.getDirUrl(), "_black");
} catch (e) {
@ -110,17 +103,9 @@ const GMApiSetting: React.FC = () => {
setFilesystemParam(params);
}}
/>
{status === "unset" && (
<Typography.Text type="secondary">{t("not_set")}</Typography.Text>
)}
{status === "success" && (
<Typography.Text type="success">{t("in_use")}</Typography.Text>
)}
{status === "error" && (
<Typography.Text type="error">
{t("storage_error")}
</Typography.Text>
)}
{status === "unset" && <Typography.Text type="secondary">{t("not_set")}</Typography.Text>}
{status === "success" && <Typography.Text type="success">{t("in_use")}</Typography.Text>}
{status === "error" && <Typography.Text type="error">{t("storage_error")}</Typography.Text>}
</Space>
</CollapseItem>
</Collapse>

View File

@ -14,12 +14,11 @@ import { RiPlayFill, RiStopFill } from "react-icons/ri";
import { useTranslation } from "react-i18next";
import { ScriptIcons } from "@App/pages/options/routes/utils";
import { ScriptMenu, ScriptMenuItem } from "@App/app/service/service_worker/popup";
import { selectMenuExpandNum } from "@App/pages/store/features/setting";
import { useAppSelector } from "@App/pages/store/hooks";
import { popupClient, runtimeClient, scriptClient } from "@App/pages/store/features/script";
import { i18nName } from "@App/locales/locales";
import { subscribeScriptRunStatus } from "@App/app/service/queue";
import { messageQueue } from "@App/pages/store/global";
import { messageQueue, systemConfig } from "@App/pages/store/global";
const CollapseItem = Collapse.Item;
@ -46,7 +45,7 @@ const ScriptMenuList: React.FC<{
[key: string]: boolean;
}>({});
const { t } = useTranslation();
const menuExpandNum = useAppSelector(selectMenuExpandNum);
const [menuExpandNum, setMenuExpandNum] = useState(5);
let url: URL;
try {
@ -70,6 +69,10 @@ const ScriptMenuList: React.FC<{
return newList;
});
});
// 获取配置
systemConfig.getMenuExpandNum().then((num) => {
setMenuExpandNum(num);
});
return () => {
unsub();
};

View File

@ -16,7 +16,7 @@ import React, { ReactNode, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import "./index.css";
import { useAppDispatch, useAppSelector } from "@App/pages/store/hooks";
import { selectThemeMode, setDarkMode } from "@App/pages/store/features/setting";
import { selectThemeMode, setDarkMode } from "@App/pages/store/features/config";
import { RiFileCodeLine, RiImportLine, RiPlayListAddLine, RiTerminalBoxLine, RiTimerLine } from "react-icons/ri";
const MainLayout: React.FC<{

View File

@ -80,7 +80,7 @@ import {
requestStopScript,
requestRunScript,
} from "@App/pages/store/features/script";
import { selectScriptListColumnWidth } from "@App/pages/store/features/setting";
import { systemConfig } from "@App/pages/store/global";
type ListType = Script & { loading?: boolean };
@ -93,7 +93,6 @@ function ScriptList() {
const [cloudScript, setCloudScript] = useState<Script>();
const dispatch = useAppDispatch();
const scriptList = useAppSelector(selectScripts);
const scriptListColumnWidth = useAppSelector(selectScriptListColumnWidth);
const inputRef = useRef<RefInputType>(null);
const navigate = useNavigate();
const openUserConfig = useSearchParams()[0].get("userConfig") || "";
@ -557,12 +556,14 @@ function ScriptList() {
});
}
}
setNewColumns(
columns.map((item) => {
item.width = scriptListColumnWidth[item.key!] ?? item.width;
return item;
})
);
systemConfig.getScriptListColumnWidth().then((columnWidth) => {
setNewColumns(
columns.map((item) => {
item.width = columnWidth[item.key!] ?? item.width;
return item;
})
);
});
}, []);
// 处理拖拽排序

View File

@ -1,13 +1,5 @@
import React, { useState } from "react";
import {
Button,
Card,
Checkbox,
Input,
Message,
Select,
Space,
} from "@arco-design/web-react";
import { useEffect, useState } from "react";
import { Button, Card, Checkbox, Input, Message, Select, Space } from "@arco-design/web-react";
import Title from "@arco-design/web-react/es/Typography/title";
import { IconQuestionCircleFill } from "@arco-design/web-react/icon";
import { format } from "prettier";
@ -17,22 +9,24 @@ import i18n from "@App/locales/locales";
import { useTranslation } from "react-i18next";
import dayjs from "dayjs";
import Logger from "@App/app/logger/logger";
import { systemConfig } from "@App/pages/store/global";
import { FileSystemType } from "@Packages/filesystem/factory";
import FileSystemParams from "@App/pages/components/FileSystemParams";
function Setting() {
const systemConfig = IoC.instance(SystemConfig) as SystemConfig;
const [syncDelete, setSyncDelete] = useState<boolean>(
systemConfig.cloudSync.syncDelete
);
const [enableCloudSync, setEnableCloudSync] = useState(
systemConfig.cloudSync.enable
);
const [fileSystemType, setFilesystemType] = useState<FileSystemType>(
systemConfig.cloudSync.filesystem
);
const [syncDelete, setSyncDelete] = useState<boolean>();
const [enableCloudSync, setEnableCloudSync] = useState<boolean>();
const [fileSystemType, setFilesystemType] = useState<FileSystemType>("webdav");
const [fileSystemParams, setFilesystemParam] = useState<{
[key: string]: any;
}>(systemConfig.cloudSync.params[fileSystemType] || {});
}>({});
const [language, setLanguage] = useState(i18n.language);
const [menuExpandNum, setMenuExpandNum] = useState(5);
const [checkScriptUpdateCycle, setCheckScriptUpdateCycle] = useState(0);
const [updateDisableScript, setUpdateDisableScript] = useState(false);
const [silenceUpdateScript, setSilenceUpdateScript] = useState(false);
const [enableEslint, setEnableEslint] = useState(false);
const [eslintConfig, setEslintConfig] = useState("");
const languageList: { key: string; title: string }[] = [];
const { t } = useTranslation();
Object.keys(i18n.store.data).forEach((key) => {
@ -49,6 +43,34 @@ function Setting() {
title: t("help_translate"),
});
useEffect(() => {
const loadConfigs = async () => {
const [cloudSync, menuExpandNum, checkCycle, updateDisabled, silenceUpdate, eslintConfig, enableEslint] =
await Promise.all([
systemConfig.getCloudSync(),
systemConfig.getMenuExpandNum(),
systemConfig.getCheckScriptUpdateCycle(),
systemConfig.getUpdateDisableScript(),
systemConfig.getSilenceUpdateScript(),
systemConfig.getEslintConfig(),
systemConfig.getEnableEslint(),
]);
setSyncDelete(cloudSync.syncDelete);
setEnableCloudSync(cloudSync.enable);
setFilesystemType(cloudSync.filesystem);
setFilesystemParam(cloudSync.params[cloudSync.filesystem] || {});
setMenuExpandNum(menuExpandNum);
setCheckScriptUpdateCycle(checkCycle);
setUpdateDisableScript(updateDisabled);
setSilenceUpdateScript(silenceUpdate);
setEslintConfig(eslintConfig);
setEnableEslint(enableEslint);
};
loadConfigs();
}, []);
return (
<Space
className="setting"
@ -69,10 +91,7 @@ function Setting() {
className="w-24"
onChange={(value) => {
if (value === "help") {
window.open(
"https://crowdin.com/project/scriptcat",
"_blank"
);
window.open("https://crowdin.com/project/scriptcat", "_blank");
return;
}
setLanguage(value);
@ -94,9 +113,11 @@ function Setting() {
<Input
style={{ width: "64px" }}
type="number"
defaultValue={systemConfig.menuExpandNum.toString()}
value={menuExpandNum.toString()}
onChange={(val) => {
systemConfig.menuExpandNum = parseInt(val, 10);
const num = parseInt(val, 10);
setMenuExpandNum(num);
systemConfig.setMenuExpandNum(num);
}}
/>
{t("menu_expand_num_after")}
@ -134,16 +155,9 @@ function Setting() {
if (enableCloudSync) {
Message.info(t("cloud_sync_account_verification")!);
try {
await FileSystemFactory.create(
fileSystemType,
fileSystemParams
);
await FileSystemFactory.create(fileSystemType, fileSystemParams);
} catch (e) {
Message.error(
`${t(
"cloud_sync_verification_failed"
)}: ${JSON.stringify(Logger.E(e))}`
);
Message.error(`${t("cloud_sync_verification_failed")}: ${JSON.stringify(Logger.E(e))}`);
return;
}
}
@ -177,12 +191,14 @@ function Setting() {
<Space>
<span>{t("script_subscription_check_interval")}:</span>
<Select
defaultValue={systemConfig.checkScriptUpdateCycle.toString()}
value={checkScriptUpdateCycle.toString()}
style={{
width: 120,
}}
onChange={(value) => {
systemConfig.checkScriptUpdateCycle = parseInt(value, 10);
const num = parseInt(value, 10);
setCheckScriptUpdateCycle(num);
systemConfig.setCheckScriptUpdateCycle(num);
}}
>
<Select.Option value="0">{t("never")}</Select.Option>
@ -194,17 +210,19 @@ function Setting() {
</Space>
<Checkbox
onChange={(checked) => {
systemConfig.updateDisableScript = checked;
setEnableCloudSync(checked);
systemConfig.setUpdateDisableScript(checked);
}}
defaultChecked={systemConfig.updateDisableScript}
checked={updateDisableScript}
>
{t("update_disabled_scripts")}
</Checkbox>
<Checkbox
onChange={(checked) => {
systemConfig.silenceUpdateScript = checked;
setSilenceUpdateScript(checked);
systemConfig.setSilenceUpdateScript(checked);
}}
defaultChecked={systemConfig.silenceUpdateScript}
checked={silenceUpdateScript}
>
{t("silent_update_non_critical_changes")}
</Checkbox>
@ -215,9 +233,10 @@ function Setting() {
<Space direction="vertical" className="w-full">
<Checkbox
onChange={(checked) => {
systemConfig.enableEslint = checked;
setEnableEslint(checked);
systemConfig.setEnableEslint(checked);
}}
defaultChecked={systemConfig.enableEslint}
checked={enableEslint}
>
{t("enable_eslint")}
</Checkbox>
@ -246,12 +265,21 @@ function Setting() {
minRows: 4,
maxRows: 8,
}}
defaultValue={format(systemConfig.eslintConfig, {
parser: "json",
plugins: [babel],
})}
value={eslintConfig}
onChange={(v) => {
setEslintConfig(v);
}}
onBlur={(v) => {
systemConfig.eslintConfig = v.target.value;
format(eslintConfig, {
parser: "json",
plugins: [babel],
})
.then((res) => {
systemConfig.setEslintConfig(v.target.value);
})
.catch((e) => {
Message.error(`${t("eslint_config_format_error")}: ${JSON.stringify(Logger.E(e))}`);
});
}}
/>
</Space>

View File

@ -1,16 +1,5 @@
import React, { useRef, useState } from "react";
import {
Button,
Card,
Checkbox,
Drawer,
Empty,
Input,
List,
Message,
Modal,
Space,
} from "@arco-design/web-react";
import React, { useEffect, useRef, useState } from "react";
import { Button, Card, Checkbox, Drawer, Empty, Input, List, Message, Modal, Space } from "@arco-design/web-react";
import Title from "@arco-design/web-react/es/Typography/title";
import { formatUnixTime } from "@App/pkg/utils/utils";
import FileSystemParams from "@App/pages/components/FileSystemParams";
@ -18,20 +7,27 @@ import { IconQuestionCircleFill } from "@arco-design/web-react/icon";
import { RefInputType } from "@arco-design/web-react/es/Input/interface";
import { useTranslation } from "react-i18next";
import { FileSystemType } from "@Packages/filesystem/factory";
import { systemConfig } from "@App/pages/store/global";
function Tools() {
const [loading, setLoading] = useState<{ [key: string]: boolean }>({});
const fileRef = useRef<HTMLInputElement>(null);
const [fileSystemType, setFilesystemType] = useState<FileSystemType>(
systemConfig.backup.filesystem
);
const [fileSystemType, setFilesystemType] = useState<FileSystemType>("webdav");
const [fileSystemParams, setFilesystemParam] = useState<{
[key: string]: any;
}>(systemConfig.backup.params[fileSystemType] || {});
}>({});
const [backupFileList, setBackupFileList] = useState<File[]>([]);
const vscodeRef = useRef<RefInputType>(null);
const { t } = useTranslation();
useEffect(() => {
// 获取配置
systemConfig.getBackup().then((backup) => {
setFilesystemType(backup.filesystem);
setFilesystemParam(backup.params[backup.filesystem] || {});
});
}, []);
return (
<Space
className="tools"
@ -47,12 +43,7 @@ function Tools() {
<Space direction="vertical">
<Title heading={6}>{t("local")}</Title>
<Space>
<input
type="file"
ref={fileRef}
style={{ display: "none" }}
accept=".zip"
/>
<input type="file" ref={fileRef} style={{ display: "none" }} accept=".zip" />
<Button
type="primary"
loading={loading.local}
@ -96,12 +87,12 @@ function Tools() {
loading={loading.cloud}
onClick={() => {
// Store parameters
const params = { ...systemConfig.backup.params };
const params = { ...fileSystemParams };
params[fileSystemType] = fileSystemParams;
systemConfig.backup = {
systemConfig.setBackup({
filesystem: fileSystemType,
params,
};
});
setLoading((prev) => ({ ...prev, cloud: true }));
Message.info(t("preparing_backup")!);
syncCtrl
@ -123,10 +114,7 @@ function Tools() {
key="list"
type="primary"
onClick={async () => {
let fs = await FileSystemFactory.create(
fileSystemType,
fileSystemParams
);
let fs = await FileSystemFactory.create(fileSystemType, fileSystemParams);
try {
fs = await fs.openDir("ScriptCat");
let list = await fs.list();
@ -158,10 +146,7 @@ function Tools() {
type="secondary"
size="mini"
onClick={async () => {
let fs = await FileSystemFactory.create(
fileSystemType,
fileSystemParams
);
let fs = await FileSystemFactory.create(fileSystemType, fileSystemParams);
try {
fs = await fs.openDir("ScriptCat");
const url = await fs.getDirUrl();
@ -190,20 +175,14 @@ function Tools() {
dataSource={backupFileList}
render={(item: File) => (
<List.Item key={item.name}>
<List.Item.Meta
title={item.name}
description={formatUnixTime(item.updatetime / 1000)}
/>
<List.Item.Meta title={item.name} description={formatUnixTime(item.updatetime / 1000)} />
<Space className="w-full justify-end">
<Button
type="primary"
size="small"
onClick={async () => {
Message.info(t("pulling_data_from_cloud")!);
let fs = await FileSystemFactory.create(
fileSystemType,
fileSystemParams
);
let fs = await FileSystemFactory.create(fileSystemType, fileSystemParams);
let file: FileReader;
let data: Blob;
try {
@ -237,22 +216,13 @@ function Tools() {
onClick={() => {
Modal.confirm({
title: t("confirm_delete"),
content: `${t("confirm_delete_backup_file")}${
item.name
}?`,
content: `${t("confirm_delete_backup_file")}${item.name}?`,
onOk: async () => {
let fs = await FileSystemFactory.create(
fileSystemType,
fileSystemParams
);
let fs = await FileSystemFactory.create(fileSystemType, fileSystemParams);
try {
fs = await fs.openDir("ScriptCat");
await fs.delete(item.name);
setBackupFileList(
backupFileList.filter(
(i) => i.name !== item.name
)
);
setBackupFileList(backupFileList.filter((i) => i.name !== item.name));
Message.success(t("delete_success")!);
} catch (e) {
Message.error(`${t("delete_failed")}${e}`);

View File

@ -0,0 +1,51 @@
import { SystemConfig } from "@App/pkg/config/config";
import { createAppSlice } from "../hooks";
import { PayloadAction } from "@reduxjs/toolkit";
import { editor } from "monaco-editor";
function setAutoMode() {
const darkTheme = window.matchMedia("(prefers-color-scheme: dark)");
const isMatch = (match: boolean) => {
if (match) {
document.body.setAttribute("arco-theme", "dark");
editor.setTheme("vs-dark");
} else {
document.body.removeAttribute("arco-theme");
editor.setTheme("vs");
}
};
darkTheme.addEventListener("change", (e) => {
isMatch(e.matches);
});
isMatch(darkTheme.matches);
}
export const configSlice = createAppSlice({
name: "setting",
initialState: {
lightMode: localStorage.lightMode || "auto",
},
reducers: (create) => {
// 初始化黑夜模式
setAutoMode();
return {
setDarkMode: create.reducer((state, action: PayloadAction<"light" | "dark" | "auto">) => {
localStorage.loghtMode = action.payload;
state.lightMode = action.payload;
if (action.payload === "auto") {
setAutoMode();
} else {
document.body.setAttribute("arco-theme", action.payload);
editor.setTheme(action.payload === "dark" ? "vs-dark" : "vs");
}
}),
};
},
selectors: {
selectThemeMode: (state) => state.lightMode,
},
});
export const { setDarkMode } = configSlice.actions;
export const { selectThemeMode } = configSlice.selectors;

View File

@ -1,82 +0,0 @@
import { createAppSlice } from "../hooks";
import { PayloadAction } from "@reduxjs/toolkit";
import { editor } from "monaco-editor";
function setAutoMode() {
const darkTheme = window.matchMedia("(prefers-color-scheme: dark)");
const isMatch = (match: boolean) => {
if (match) {
document.body.setAttribute("arco-theme", "dark");
editor.setTheme("vs-dark");
} else {
document.body.removeAttribute("arco-theme");
editor.setTheme("vs");
}
};
darkTheme.addEventListener("change", (e) => {
isMatch(e.matches);
});
isMatch(darkTheme.matches);
}
export type SystemConfig = {
lightMode: "light" | "dark" | "auto";
eslint: {
enable: boolean;
config: string;
};
scriptListColumnWidth: { [key: string]: number };
menuExpandNum: number;
};
export const settingSlice = createAppSlice({
name: "setting",
initialState: {
lightMode: localStorage.lightMode || "auto",
eslint: {
enable: true,
config: "",
},
scriptListColumnWidth: {} as { [key: string]: number },
menuExpandNum: 5,
} as SystemConfig,
reducers: (create) => {
// 初始化黑夜模式
setAutoMode();
// 加载配置
chrome.storage.sync.get("systemSetting", (result) => {
const systemSetting = result.systemSetting as SystemConfig;
settingSlice.actions.initSetting(systemSetting);
if (systemSetting) {
localStorage.lightMode = systemSetting.lightMode;
}
});
return {
initSetting: create.reducer((state, action: PayloadAction<SystemConfig>) => {
state.menuExpandNum = action.payload.menuExpandNum;
}),
setDarkMode: create.reducer((state, action: PayloadAction<"light" | "dark" | "auto">) => {
localStorage.loghtMode = action.payload;
state.lightMode = action.payload;
if (action.payload === "auto") {
setAutoMode();
} else {
document.body.setAttribute("arco-theme", action.payload);
editor.setTheme(action.payload === "dark" ? "vs-dark" : "vs");
}
}),
menuExpandNum: create.reducer((state, action: PayloadAction<number>) => {
state.menuExpandNum = action.payload;
}),
};
},
selectors: {
selectThemeMode: (state) => state.lightMode,
selectScriptListColumnWidth: (state) => state.scriptListColumnWidth,
selectMenuExpandNum: (state) => state.menuExpandNum,
},
});
export const { setDarkMode } = settingSlice.actions;
export const { selectThemeMode, selectScriptListColumnWidth, selectMenuExpandNum } = settingSlice.selectors;

View File

@ -1,5 +1,7 @@
import { SystemConfig } from "@App/pkg/config/config";
import { ExtensionMessage } from "@Packages/message/extension_message";
import { MessageQueue } from "@Packages/message/message_queue";
export const message = new ExtensionMessage();
export const messageQueue = new MessageQueue();
export const systemConfig = new SystemConfig(messageQueue);

View File

@ -1,12 +1,12 @@
import type { Action, ThunkAction } from "@reduxjs/toolkit";
import { combineSlices, configureStore } from "@reduxjs/toolkit";
import { setupListeners } from "@reduxjs/toolkit/query";
import { settingSlice } from "./features/setting";
import { scriptSlice } from "./features/script";
import { configSlice } from "./features/config";
// `combineSlices` automatically combines the reducers using
// their `reducerPath`s, therefore we no longer need to call `combineReducers`.
const rootReducer = combineSlices(settingSlice, scriptSlice);
const rootReducer = combineSlices(configSlice, scriptSlice);
// Infer the `RootState` type from the root reducer
export type RootState = ReturnType<typeof rootReducer>;

View File

@ -0,0 +1,58 @@
export default class ChromeStorage {
private prefix: string;
private storage: chrome.storage.StorageArea;
constructor(prefix: string, sync: boolean) {
this.prefix = `${prefix}_`;
this.storage = sync ? chrome.storage.sync : chrome.storage.local;
}
public buildKey(key: string): string {
return this.prefix + key;
}
public get(key: string): Promise<any> {
return new Promise((resolve) => {
key = this.buildKey(key);
this.storage.get(key, (items) => {
resolve(items[key]);
});
});
}
public set(key: string, value: any): Promise<void> {
return new Promise((resolve) => {
const kvp: { [key: string]: any } = {};
kvp[this.buildKey(key)] = value;
this.storage.set(kvp, () => resolve());
});
}
public remove(key: string): Promise<void> {
return new Promise((resolve) => {
this.storage.remove(this.buildKey(key), () => resolve());
});
}
public removeAll(): Promise<void> {
return new Promise((resolve) => {
this.storage.clear(() => resolve());
});
}
public keys(): Promise<{ [key: string]: any }> {
return new Promise((resolve) => {
const ret: { [key: string]: any } = {};
const prefix = this.buildKey("");
this.storage.get((items) => {
Object.keys(items).forEach((key) => {
if (key.startsWith(prefix)) {
ret[key.substring(prefix.length)] = items[key];
}
});
resolve(ret);
});
});
}
}

217
src/pkg/config/config.ts Normal file
View File

@ -0,0 +1,217 @@
import { Message } from "@arco-design/web-react";
import ChromeStorage from "./chrome_storage";
import { defaultConfig } from "../../../eslint/linter-config";
import { FileSystemType } from "@Packages/filesystem/factory";
import { MessageQueue } from "@Packages/message/message_queue";
export const SystamConfigChange = "systemConfigChange";
export type CloudSyncConfig = {
enable: boolean;
syncDelete: boolean;
filesystem: FileSystemType;
params: { [key: string]: any };
};
export type CATFileStorage = {
filesystem: FileSystemType;
params: { [key: string]: any };
status: "unset" | "success" | "error";
};
export class SystemConfig {
public cache = new Map<string, any>();
public storage = new ChromeStorage("system", true);
constructor(private mq: MessageQueue) {
this.mq.subscribe("systemConfigChange", (msg) => {
const { key, value } = msg;
this.cache.set(key, value);
});
}
async getAll(): Promise<{ [key: string]: any }> {
const ret: { [key: string]: any } = {};
const list = await this.storage.keys();
Object.keys(list).forEach((key) => {
this.cache.set(key, list[key]);
ret[key] = list[key];
});
return ret;
}
get<T>(key: string, defaultValue: T): Promise<T> {
if (this.cache.has(key)) {
return Promise.resolve(this.cache.get(key));
}
return this.storage.get(key).then((val) => {
if (val === undefined) {
return defaultValue;
}
this.cache.set(key, val);
return val;
});
}
public set(key: string, val: any) {
this.cache.set(key, val);
this.storage.set(key, val);
// 发送消息通知更新
this.mq.publish(SystamConfigChange, {
key,
value: val,
});
}
public getChangetime() {
return this.get("changetime", 0);
}
public setChangetime(n: number) {
this.set("changetime", 0);
}
// 检查更新周期,单位为秒
public getCheckScriptUpdateCycle() {
return this.get("check_script_update_cycle", 86400);
}
public setCheckScriptUpdateCycle(n: number) {
this.set("check_script_update_cycle", n);
}
public getSilenceUpdateScript() {
return this.get("silence_update_script", false);
}
public setSilenceUpdateScript(val: boolean) {
this.set("silence_update_script", val);
}
public getEnableAutoSync() {
return this.get("enable_auto_sync", true);
}
public setEnableAutoSync(enable: boolean) {
this.set("enable_auto_sync", enable);
}
// 更新已经禁用的脚本
public getUpdateDisableScript() {
return this.get("update_disable_script", true);
}
public setUpdateDisableScript(enable: boolean) {
this.set("update_disable_script", enable);
}
public getVscodeUrl() {
return this.get("vscode_url", "ws://localhost:8642");
}
public setVscodeUrl(val: string) {
this.set("vscode_url", val);
}
public getVscodeReconnect() {
return this.get("vscode_reconnect", false);
}
public setVscodeReconnect(val: boolean) {
this.set("vscode_reconnect", val);
}
public getBackup(): Promise<{
filesystem: FileSystemType;
params: { [key: string]: any };
}> {
return this.get("backup", {
filesystem: "webdav",
params: {},
});
}
public setBackup(data: { filesystem: FileSystemType; params: { [key: string]: any } }) {
this.set("backup", data);
}
getCloudSync(): Promise<CloudSyncConfig> {
return this.get("cloud_sync", {
enable: false,
syncDelete: true,
filesystem: "webdav",
params: {},
});
}
setCloudSync(data: CloudSyncConfig) {
this.set("cloud_sync", data);
}
getCatFileStorage(): Promise<CATFileStorage> {
return this.get("cat_file_storage", {
status: "unset",
filesystem: "webdav",
params: {},
});
}
setCatFileStorage(data: CATFileStorage | undefined) {
this.set("cat_file_storage", data);
}
getEnableEslint() {
return this.get("enable_eslint", true);
}
setEnableEslint(val: boolean) {
this.set("enable_eslint", val);
}
getEslintConfig() {
return this.get("eslint_config", defaultConfig);
}
setEslintConfig(v: string) {
if (v === "") {
this.set("eslint_config", v);
Message.success("ESLint规则已重置");
return;
}
try {
JSON.parse(v);
this.set("eslint_config", v);
Message.success("ESLint规则已保存");
} catch (err: any) {
Message.error(err.toString());
}
}
// 日志清理周期
getLogCleanCycle() {
return this.get("log_clean_cycle", 7);
}
setLogCleanCycle(val: number) {
this.set("log_clean_cycle", val);
}
// 设置脚本列表列宽度
getScriptListColumnWidth() {
return this.get<{ [key: string]: number }>("script_list_column_width", {});
}
setScriptListColumnWidth(val: { [key: string]: number }) {
this.set("script_list_column_width", val);
}
// 展开菜单数
getMenuExpandNum() {
return this.get("menu_expand_num", 5);
}
setMenuExpandNum(val: number) {
this.set("menu_expand_num", val);
}
}