mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-05-12 11:30:27 +08:00
🚧 WIP(custom): v3.0.0 migrate to vite and esm
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import crypto from 'crypto'
|
||||
import crypto from 'node:crypto'
|
||||
|
||||
import picgo from '@core/picgo'
|
||||
|
||||
@@ -14,7 +14,7 @@ export class AESHelper {
|
||||
'sha512'
|
||||
)
|
||||
|
||||
encrypt(plainText: string) {
|
||||
encrypt (plainText: string) {
|
||||
const iv = crypto.randomBytes(16)
|
||||
const cipher = crypto.createCipheriv('aes-256-cbc', this.key, iv)
|
||||
let encrypted = cipher.update(plainText, 'utf8', 'hex')
|
||||
@@ -22,7 +22,7 @@ export class AESHelper {
|
||||
return `${iv.toString('hex')}:${encrypted}`
|
||||
}
|
||||
|
||||
decrypt(encryptedData: string) {
|
||||
decrypt (encryptedData: string) {
|
||||
const [ivHex, encryptedText] = encryptedData.split(':')
|
||||
if (!ivHex || !encryptedText) return '{}'
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import fs from 'fs-extra'
|
||||
import yaml from 'js-yaml'
|
||||
import path from 'path'
|
||||
import os from 'os'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
|
||||
import { dbPathChecker } from '@core/datastore/dbChecker'
|
||||
import fs from 'fs-extra'
|
||||
import yaml from 'js-yaml'
|
||||
import { ILocales } from 'root/src/universal/types/i18n'
|
||||
|
||||
import { i18nManager } from '~/i18n'
|
||||
|
||||
const configPath = dbPathChecker()
|
||||
const CONFIG_DIR = path.dirname(configPath)
|
||||
|
||||
function beforeOpen() {
|
||||
function beforeOpen () {
|
||||
if (process.platform === 'darwin') {
|
||||
resolveMacWorkFlow()
|
||||
}
|
||||
@@ -18,7 +19,7 @@ function beforeOpen() {
|
||||
resolveOtherI18nFiles()
|
||||
}
|
||||
|
||||
function copyFileOutsideOfElectronAsar(sourceInAsarArchive: string, destOutsideAsarArchive: string) {
|
||||
function copyFileOutsideOfElectronAsar (sourceInAsarArchive: string, destOutsideAsarArchive: string) {
|
||||
if (fs.existsSync(sourceInAsarArchive)) {
|
||||
// file will be copied
|
||||
if (fs.statSync(sourceInAsarArchive).isFile()) {
|
||||
@@ -42,16 +43,16 @@ function copyFileOutsideOfElectronAsar(sourceInAsarArchive: string, destOutsideA
|
||||
/**
|
||||
* macOS 右键菜单
|
||||
*/
|
||||
function resolveMacWorkFlow() {
|
||||
function resolveMacWorkFlow () {
|
||||
const dest = `${os.homedir()}/Library/Services/Upload pictures with PicList.workflow`
|
||||
try {
|
||||
copyFileOutsideOfElectronAsar(path.join(__static, 'Upload pictures with PicList.workflow'), dest)
|
||||
copyFileOutsideOfElectronAsar(path.join('./resources', 'Upload pictures with PicList.workflow'), dest)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
function diffFilesAndUpdate(filePath1: string, filePath2: string) {
|
||||
function diffFilesAndUpdate (filePath1: string, filePath2: string) {
|
||||
try {
|
||||
const file1 = fs.existsSync(filePath1) && fs.readFileSync(filePath1)
|
||||
const file2 = fs.existsSync(filePath1) && fs.readFileSync(filePath2)
|
||||
@@ -68,7 +69,7 @@ function diffFilesAndUpdate(filePath1: string, filePath2: string) {
|
||||
/**
|
||||
* 初始化剪贴板生成图片的脚本
|
||||
*/
|
||||
function resolveClipboardImageGenerator() {
|
||||
function resolveClipboardImageGenerator () {
|
||||
const clipboardFiles = getClipboardFiles()
|
||||
if (!fs.pathExistsSync(path.join(CONFIG_DIR, 'windows10.ps1'))) {
|
||||
clipboardFiles.forEach(item => {
|
||||
@@ -80,12 +81,12 @@ function resolveClipboardImageGenerator() {
|
||||
})
|
||||
}
|
||||
|
||||
function getClipboardFiles() {
|
||||
const files = ['/linux.sh', '/mac.applescript', '/windows.ps1', '/windows10.ps1', '/wsl.sh']
|
||||
function getClipboardFiles () {
|
||||
const files = ['linux.sh', 'mac.applescript', 'windows.ps1', 'windows10.ps1', 'wsl.sh']
|
||||
|
||||
return files.map(item => {
|
||||
return {
|
||||
origin: path.join(__static, item),
|
||||
origin: path.join('./resources', item),
|
||||
dest: path.join(CONFIG_DIR, item)
|
||||
}
|
||||
})
|
||||
@@ -95,7 +96,7 @@ function resolveClipboardImageGenerator() {
|
||||
/**
|
||||
* 初始化其他语言文件
|
||||
*/
|
||||
function resolveOtherI18nFiles() {
|
||||
function resolveOtherI18nFiles () {
|
||||
const i18nFolder = path.join(CONFIG_DIR, 'i18n')
|
||||
if (!fs.pathExistsSync(i18nFolder)) {
|
||||
fs.mkdirSync(i18nFolder)
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import crypto from 'crypto'
|
||||
import { clipboard } from 'electron'
|
||||
import { EventEmitter } from 'events'
|
||||
import crypto from 'node:crypto'
|
||||
import { EventEmitter } from 'node:events'
|
||||
|
||||
import logger from '@core/picgo/logger'
|
||||
import { clipboard, NativeImage } from 'electron'
|
||||
|
||||
class ClipboardWatcher extends EventEmitter {
|
||||
// eslint-disable-next-line no-undef
|
||||
timer: NodeJS.Timeout | null
|
||||
lastImageHash: string | null
|
||||
|
||||
constructor() {
|
||||
constructor () {
|
||||
super()
|
||||
this.lastImageHash = null
|
||||
this.timer = null
|
||||
}
|
||||
|
||||
startListening(watchDelay = 500) {
|
||||
startListening (watchDelay = 500) {
|
||||
this.stopListening(false)
|
||||
|
||||
this.timer = setInterval(() => {
|
||||
@@ -33,7 +34,7 @@ class ClipboardWatcher extends EventEmitter {
|
||||
logger.info('Start to watch clipboard')
|
||||
}
|
||||
|
||||
stopListening(isLog = true) {
|
||||
stopListening (isLog = true) {
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer)
|
||||
this.timer = null
|
||||
@@ -42,7 +43,7 @@ class ClipboardWatcher extends EventEmitter {
|
||||
isLog && logger.info('Stop to watch clipboard')
|
||||
}
|
||||
|
||||
getImageHash(image: Electron.NativeImage): string {
|
||||
getImageHash (image: NativeImage): string {
|
||||
const buffer = image.toBitmap()
|
||||
return crypto.createHash('md5').update(buffer).digest('hex')
|
||||
}
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
import axios from 'axios'
|
||||
import { clipboard, Notification, dialog, Tray } from 'electron'
|
||||
import FormData from 'form-data'
|
||||
import fs from 'fs-extra'
|
||||
import path from 'node:path'
|
||||
|
||||
import db from '@core/datastore'
|
||||
import logger from '@core/picgo/logger'
|
||||
import axios from 'axios'
|
||||
import { clipboard, dialog, Notification, Tray } from 'electron'
|
||||
import FormData from 'form-data'
|
||||
import fs from 'fs-extra'
|
||||
|
||||
import { IShortUrlServer } from '#/types/enum'
|
||||
import { IPrivateShowNotificationOption, IShowMessageBoxResult } from '#/types/types'
|
||||
import { handleUrlEncode } from '#/utils/common'
|
||||
import { configPaths } from '#/utils/configPaths'
|
||||
|
||||
const getExtension = (fileName: string) => path.extname(fileName).slice(1)
|
||||
|
||||
export const isImage = (fileName: string) =>
|
||||
['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico', 'svg', 'avif'].includes(getExtension(fileName))
|
||||
|
||||
export let tray: Tray
|
||||
|
||||
export const setTray = (t: Tray) => {
|
||||
@@ -18,7 +25,7 @@ export const setTray = (t: Tray) => {
|
||||
|
||||
export const getTray = () => tray
|
||||
|
||||
export function setTrayToolTip(title: string): void {
|
||||
export function setTrayToolTip (title: string): void {
|
||||
if (tray) {
|
||||
tray.setToolTip(title)
|
||||
}
|
||||
@@ -64,7 +71,7 @@ export const showNotification = (
|
||||
}
|
||||
|
||||
export const showMessageBox = (options: any) => {
|
||||
return new Promise<IShowMessageBoxResult>(async resolve => {
|
||||
return new Promise<IShowMessageBoxResult>(resolve => {
|
||||
dialog.showMessageBox(options).then(res => {
|
||||
resolve({
|
||||
result: res.response,
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import axios from 'axios'
|
||||
import crypto from 'crypto'
|
||||
import http, { AgentOptions } from 'http'
|
||||
import https from 'https'
|
||||
import path from 'path'
|
||||
import { ISftpPlistConfig } from 'piclist'
|
||||
import querystring from 'querystring'
|
||||
import { S3Client, DeleteObjectCommand, S3ClientConfig } from '@aws-sdk/client-s3'
|
||||
import { NodeHttpHandler } from '@smithy/node-http-handler'
|
||||
import crypto from 'node:crypto'
|
||||
import http, { AgentOptions } from 'node:http'
|
||||
import https from 'node:https'
|
||||
import path from 'node:path'
|
||||
import querystring from 'node:querystring'
|
||||
|
||||
import SSHClient from '~/utils/sshClient'
|
||||
import { DeleteObjectCommand, S3Client, S3ClientConfig } from '@aws-sdk/client-s3'
|
||||
import { NodeHttpHandler } from '@smithy/node-http-handler'
|
||||
import axios from 'axios'
|
||||
import { ISftpPlistConfig } from 'piclist'
|
||||
|
||||
import { IObj, IStringKeyMap } from '#/types/types'
|
||||
import { getAgent } from '~/manage/utils/common'
|
||||
import SSHClient from '~/utils/sshClient'
|
||||
|
||||
interface DogecloudTokenFull {
|
||||
Credentials: {
|
||||
@@ -32,7 +34,7 @@ const dogeRegionMap: IStringKeyMap = {
|
||||
'ap-chengdu': '3'
|
||||
}
|
||||
|
||||
async function dogecloudApi(
|
||||
async function dogecloudApi (
|
||||
apiPath: string,
|
||||
data = {},
|
||||
jsonMode: boolean = false,
|
||||
@@ -65,7 +67,7 @@ async function dogecloudApi(
|
||||
}
|
||||
}
|
||||
|
||||
async function getDogeToken(accessKey: string, secretKey: string): Promise<IObj | DogecloudTokenFull> {
|
||||
async function getDogeToken (accessKey: string, secretKey: string): Promise<IObj | DogecloudTokenFull> {
|
||||
try {
|
||||
const data = await dogecloudApi(
|
||||
'/auth/tmp_token.json',
|
||||
@@ -84,7 +86,7 @@ async function getDogeToken(accessKey: string, secretKey: string): Promise<IObj
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeFileFromS3InMain(configMap: IStringKeyMap, dogeMode: boolean = false) {
|
||||
export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode: boolean = false) {
|
||||
try {
|
||||
const {
|
||||
url: rawUrl,
|
||||
@@ -121,21 +123,21 @@ export async function removeFileFromS3InMain(configMap: IStringKeyMap, dogeMode:
|
||||
const extraOptions = sslEnabled ? { rejectUnauthorized: !!rejectUnauthorized } : {}
|
||||
const handler = sslEnabled
|
||||
? new NodeHttpHandler({
|
||||
httpsAgent: agent.https
|
||||
? agent.https
|
||||
: new https.Agent({
|
||||
...commonOptions,
|
||||
...extraOptions
|
||||
})
|
||||
})
|
||||
httpsAgent: agent.https
|
||||
? agent.https
|
||||
: new https.Agent({
|
||||
...commonOptions,
|
||||
...extraOptions
|
||||
})
|
||||
})
|
||||
: new NodeHttpHandler({
|
||||
httpAgent: agent.http
|
||||
? agent.http
|
||||
: new http.Agent({
|
||||
...commonOptions,
|
||||
...extraOptions
|
||||
})
|
||||
})
|
||||
httpAgent: agent.http
|
||||
? agent.http
|
||||
: new http.Agent({
|
||||
...commonOptions,
|
||||
...extraOptions
|
||||
})
|
||||
})
|
||||
const s3Options: S3ClientConfig = {
|
||||
credentials: {
|
||||
accessKeyId: accessKeyID,
|
||||
@@ -181,14 +183,14 @@ export async function removeFileFromS3InMain(configMap: IStringKeyMap, dogeMode:
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeFileFromDogeInMain(configMap: IStringKeyMap) {
|
||||
export async function removeFileFromDogeInMain (configMap: IStringKeyMap) {
|
||||
try {
|
||||
const {
|
||||
config: { bucketName, AccessKey, SecretKey }
|
||||
} = configMap
|
||||
const token = (await getDogeToken(AccessKey, SecretKey)) as DogecloudTokenFull
|
||||
const bucket = token.Buckets?.find(item => item.name === bucketName || item.s3Bucket === bucketName)
|
||||
const newConfigMap = Object.assign({}, configMap)
|
||||
const newConfigMap = { ...configMap }
|
||||
newConfigMap.config = {
|
||||
...newConfigMap.config,
|
||||
accessKeyID: token.Credentials?.accessKeyId,
|
||||
@@ -205,7 +207,7 @@ export async function removeFileFromDogeInMain(configMap: IStringKeyMap) {
|
||||
}
|
||||
}
|
||||
|
||||
function createHuaweiAuthorization(
|
||||
function createHuaweiAuthorization (
|
||||
bucketName: string,
|
||||
path: string,
|
||||
fileName: string,
|
||||
@@ -218,7 +220,7 @@ function createHuaweiAuthorization(
|
||||
return `OBS ${accessKey}:${singature}`
|
||||
}
|
||||
|
||||
export async function removeFileFromHuaweiInMain(configMap: IStringKeyMap) {
|
||||
export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) {
|
||||
const { fileName, config } = configMap
|
||||
const { accessKeyId, accessKeySecret, bucketName, endpoint } = config
|
||||
let path = config.path || '/'
|
||||
@@ -244,7 +246,7 @@ export async function removeFileFromHuaweiInMain(configMap: IStringKeyMap) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeFileFromSFTPInMain(config: ISftpPlistConfig, fileName: string) {
|
||||
export async function removeFileFromSFTPInMain (config: ISftpPlistConfig, fileName: string) {
|
||||
try {
|
||||
const client = SSHClient.instance
|
||||
await client.connect(config)
|
||||
|
||||
8
src/main/utils/deleteLog.ts
Normal file
8
src/main/utils/deleteLog.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export const deleteLog = (fileName?: string, type?: string, isSuccess = true, msg?: string) => {
|
||||
console.log(`Delete ${fileName} on ${type} ${isSuccess ? 'success' : 'failed'}, message: ${msg || ''}`)
|
||||
}
|
||||
|
||||
export const deleteFailedLog = (fileName: string, type: string, error: any) => {
|
||||
deleteLog(fileName, type, false)
|
||||
console.error(error)
|
||||
}
|
||||
80
src/main/utils/digestAuth.ts
Normal file
80
src/main/utils/digestAuth.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import crypto from 'node:crypto'
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
import { IStringKeyMap } from '#/types/types'
|
||||
const AUTH_KEY_VALUE_RE = /(\w+)=["']?([^'"]{1,10000})["']?/
|
||||
let NC = 0
|
||||
const NC_PAD = '00000000'
|
||||
|
||||
function md5 (text: crypto.BinaryLike) {
|
||||
return crypto.createHash('md5').update(text).digest('hex')
|
||||
}
|
||||
|
||||
export function digestAuthHeader (
|
||||
method: string,
|
||||
uri: string,
|
||||
wwwAuthenticate: string,
|
||||
username: string,
|
||||
password: string
|
||||
) {
|
||||
const parts = wwwAuthenticate.split(',')
|
||||
const opts = {} as IStringKeyMap
|
||||
for (const i of parts) {
|
||||
const m = AUTH_KEY_VALUE_RE.exec(i)
|
||||
if (m) {
|
||||
opts[m[1]] = m[2].replace(/["']/g, '')
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.realm || !opts.nonce) {
|
||||
return ''
|
||||
}
|
||||
|
||||
let qop = opts.qop || ''
|
||||
|
||||
const userpassArray = [username, password]
|
||||
|
||||
let nc = String(++NC)
|
||||
nc = NC_PAD.substring(nc.length) + nc
|
||||
const cnonce = crypto.randomBytes(8).toString('hex')
|
||||
|
||||
const ha1 = md5(userpassArray[0] + ':' + opts.realm + ':' + userpassArray[1])
|
||||
const ha2 = md5(method.toUpperCase() + ':' + uri)
|
||||
let s = ha1 + ':' + opts.nonce
|
||||
if (qop) {
|
||||
qop = qop.split(',')[0]
|
||||
s += ':' + nc + ':' + cnonce + ':' + qop
|
||||
}
|
||||
s += ':' + ha2
|
||||
const response = md5(s)
|
||||
let authstring =
|
||||
'Digest username="' +
|
||||
userpassArray[0] +
|
||||
'", realm="' +
|
||||
opts.realm +
|
||||
'", nonce="' +
|
||||
opts.nonce +
|
||||
'", uri="' +
|
||||
uri +
|
||||
'", response="' +
|
||||
response +
|
||||
'"'
|
||||
if (opts.opaque) {
|
||||
authstring += ', opaque="' + opts.opaque + '"'
|
||||
}
|
||||
if (qop) {
|
||||
authstring += ', qop=' + qop + ', nc=' + nc + ', cnonce="' + cnonce + '"'
|
||||
}
|
||||
return authstring
|
||||
}
|
||||
|
||||
export async function getAuthHeader (method: string, host: string, uri: string, username: string, password: string) {
|
||||
try {
|
||||
await axios.get(`${host}${uri}`)
|
||||
} catch (error: any) {
|
||||
if (error.response.status === 401 && error.response.headers['www-authenticate']) {
|
||||
return digestAuthHeader(method, uri, error.response.headers['www-authenticate'], username, password)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
// fork from https://github.com/sindresorhus/macos-version
|
||||
// cause I can't change it to common-js module
|
||||
|
||||
import fs from 'fs'
|
||||
import process from 'process'
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
|
||||
import semver from 'semver'
|
||||
|
||||
export const isMacOS = process.platform === 'darwin'
|
||||
@@ -21,7 +22,7 @@ const parseVersion = (plist: string) => {
|
||||
return matches[1].replace('10.16', '11')
|
||||
}
|
||||
|
||||
export function macOSVersion(): string {
|
||||
export function macOSVersion (): string {
|
||||
if (!isMacOS) return ''
|
||||
|
||||
if (!version) {
|
||||
@@ -42,7 +43,7 @@ if (process.env.NODE_ENV === 'test') {
|
||||
macOSVersion._parseVersion = parseVersion
|
||||
}
|
||||
|
||||
export function isMacOSVersion(semverRange: string) {
|
||||
export function isMacOSVersion (semverRange: string) {
|
||||
if (!isMacOS) {
|
||||
return false
|
||||
}
|
||||
@@ -52,7 +53,7 @@ export function isMacOSVersion(semverRange: string) {
|
||||
return semver.satisfies(macOSVersion(), clean(semverRange))
|
||||
}
|
||||
|
||||
export function isMacOSVersionGreaterThanOrEqualTo(version: string) {
|
||||
export function isMacOSVersionGreaterThanOrEqualTo (version: string) {
|
||||
if (!isMacOS) {
|
||||
return false
|
||||
}
|
||||
@@ -62,7 +63,7 @@ export function isMacOSVersionGreaterThanOrEqualTo(version: string) {
|
||||
return semver.gte(macOSVersion(), clean(version))
|
||||
}
|
||||
|
||||
export function assertMacOSVersion(semverRange: string) {
|
||||
export function assertMacOSVersion (semverRange: string) {
|
||||
semverRange = semverRange.replace('10.16', '11')
|
||||
|
||||
if (!isMacOSVersion(semverRange)) {
|
||||
@@ -70,7 +71,7 @@ export function assertMacOSVersion(semverRange: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export function assertMacOSVersionGreaterThanOrEqualTo(version: string) {
|
||||
export function assertMacOSVersionGreaterThanOrEqualTo (version: string) {
|
||||
version = version.replace('10.16', '11')
|
||||
|
||||
if (!isMacOSVersionGreaterThanOrEqualTo(version)) {
|
||||
@@ -78,7 +79,7 @@ export function assertMacOSVersionGreaterThanOrEqualTo(version: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export function assertMacOS() {
|
||||
export function assertMacOS () {
|
||||
if (!isMacOS) {
|
||||
throw new Error('Requires macOS')
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import picgo from '@core/picgo'
|
||||
|
||||
import { IPicBedType } from '#/types/types'
|
||||
import { configPaths } from '#/utils/configPaths'
|
||||
|
||||
const getPicBeds = () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import path from 'node:path'
|
||||
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import { Logger } from 'piclist'
|
||||
|
||||
import { isUrl } from '#/utils/common'
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import db from '@core/datastore'
|
||||
|
||||
import { i18nManager } from '~/i18n'
|
||||
|
||||
import { II18nLanguage } from '#/types/enum'
|
||||
import { configPaths } from '#/utils/configPaths'
|
||||
import { i18nManager } from '~/i18n'
|
||||
|
||||
export const initI18n = () => {
|
||||
const currentLanguage = db.get(configPaths.settings.language) || II18nLanguage.ZH_CN
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import picgo from '@core/picgo'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
import picgo from '@core/picgo'
|
||||
|
||||
import { setTrayToolTip } from '~/utils/common'
|
||||
|
||||
import { IPicGoPluginConfig, IPicGoPluginOriginConfig, IStringKeyMap, IUploaderConfigItem, IUploaderConfigListItem } from '#/types/types'
|
||||
import { trimValues } from '#/utils/common'
|
||||
import { configPaths } from '#/utils/configPaths'
|
||||
import { setTrayToolTip } from '~/utils/common'
|
||||
|
||||
export const handleConfigWithFunction = (config: IPicGoPluginOriginConfig[]): IPicGoPluginConfig[] => {
|
||||
for (const i in config) {
|
||||
@@ -13,7 +12,7 @@ export const handleConfigWithFunction = (config: IPicGoPluginOriginConfig[]): IP
|
||||
config[i].default = config[i].default()
|
||||
}
|
||||
if (typeof config[i].choices === 'function') {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
config[i].choices = (config[i].choices as Function)()
|
||||
}
|
||||
}
|
||||
@@ -21,17 +20,13 @@ export const handleConfigWithFunction = (config: IPicGoPluginOriginConfig[]): IP
|
||||
}
|
||||
|
||||
export const completeUploaderMetaConfig = (originData: IStringKeyMap): IUploaderConfigListItem => {
|
||||
return Object.assign(
|
||||
{
|
||||
_configName: 'Default'
|
||||
},
|
||||
trimValues(originData),
|
||||
{
|
||||
_id: uuid(),
|
||||
_createdAt: Date.now(),
|
||||
_updatedAt: Date.now()
|
||||
}
|
||||
)
|
||||
return {
|
||||
_configName: 'Default',
|
||||
...trimValues(originData),
|
||||
_id: uuid(),
|
||||
_createdAt: Date.now(),
|
||||
_updatedAt: Date.now()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import db from '@core/datastore'
|
||||
|
||||
import { generateShortUrl, handleUrlEncodeWithSetting } from '~/utils/common'
|
||||
|
||||
import { IPasteStyle } from '#/types/enum'
|
||||
import { ImgInfo } from '#/types/types'
|
||||
import { configPaths } from '#/utils/configPaths'
|
||||
import { generateShortUrl, handleUrlEncodeWithSetting } from '~/utils/common'
|
||||
|
||||
export const formatCustomLink = (customLink: string, item: ImgInfo) => {
|
||||
const fileName = item.fileName!.replace(new RegExp(`\\${item.extname}$`), '')
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import path from 'node:path'
|
||||
|
||||
import fs from 'fs-extra'
|
||||
import { NodeSSH, Config, SSHExecCommandResponse } from 'node-ssh-no-cpu-features'
|
||||
import path from 'path'
|
||||
import { Config, NodeSSH, SSHExecCommandResponse } from 'node-ssh-no-cpu-features'
|
||||
import { ISftpPlistConfig } from 'piclist/dist/types'
|
||||
import { Client } from 'ssh2-no-cpu-features'
|
||||
|
||||
class SSHClient {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
private static _instance: SSHClient
|
||||
private static _client: NodeSSH
|
||||
private _isConnected = false
|
||||
|
||||
static get instance(): SSHClient {
|
||||
static get instance (): SSHClient {
|
||||
return this._instance || (this._instance = new this())
|
||||
}
|
||||
|
||||
static get client(): NodeSSH {
|
||||
static get client (): NodeSSH {
|
||||
return this._client || (this._client = new NodeSSH())
|
||||
}
|
||||
|
||||
private changeWinStylePathToUnix(path: string): string {
|
||||
private changeWinStylePathToUnix (path: string): string {
|
||||
return path.replace(/\\/g, '/')
|
||||
}
|
||||
|
||||
async connect(config: ISftpPlistConfig): Promise<boolean> {
|
||||
async connect (config: ISftpPlistConfig): Promise<boolean> {
|
||||
const { username, password, privateKey, passphrase } = config
|
||||
const loginInfo: Config = privateKey
|
||||
? {
|
||||
@@ -44,7 +44,7 @@ class SSHClient {
|
||||
}
|
||||
}
|
||||
|
||||
async deleteFileSFTP(config: ISftpPlistConfig, remote: string): Promise<boolean> {
|
||||
async deleteFileSFTP (config: ISftpPlistConfig, remote: string): Promise<boolean> {
|
||||
try {
|
||||
const client = new Client()
|
||||
const { username, password, privateKey, passphrase } = config
|
||||
@@ -91,17 +91,17 @@ class SSHClient {
|
||||
}
|
||||
}
|
||||
|
||||
private async exec(script: string): Promise<boolean> {
|
||||
private async exec (script: string): Promise<boolean> {
|
||||
const execResult = await SSHClient.client.execCommand(script)
|
||||
return execResult.code === 0
|
||||
}
|
||||
|
||||
async execCommand(script: string): Promise<SSHExecCommandResponse> {
|
||||
async execCommand (script: string): Promise<SSHExecCommandResponse> {
|
||||
const execResult = await SSHClient.client.execCommand(script)
|
||||
return execResult || { code: 1, stdout: '', stderr: '' }
|
||||
}
|
||||
|
||||
async getFile(local: string, remote: string): Promise<boolean> {
|
||||
async getFile (local: string, remote: string): Promise<boolean> {
|
||||
if (!this._isConnected) {
|
||||
throw new Error('SSH 未连接')
|
||||
}
|
||||
@@ -118,7 +118,7 @@ class SSHClient {
|
||||
}
|
||||
}
|
||||
|
||||
async putFile(
|
||||
async putFile (
|
||||
local: string,
|
||||
remote: string,
|
||||
config: {
|
||||
@@ -145,7 +145,7 @@ class SSHClient {
|
||||
}
|
||||
}
|
||||
|
||||
async mkdir(
|
||||
async mkdir (
|
||||
dirPath: string,
|
||||
config: {
|
||||
dirMode?: string
|
||||
@@ -180,11 +180,11 @@ class SSHClient {
|
||||
}
|
||||
}
|
||||
|
||||
get isConnected(): boolean {
|
||||
get isConnected (): boolean {
|
||||
return SSHClient.client.isConnected()
|
||||
}
|
||||
|
||||
close(): void {
|
||||
close (): void {
|
||||
SSHClient.client.dispose()
|
||||
this._isConnected = false
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import path from 'node:path'
|
||||
|
||||
import db from '@core/datastore'
|
||||
import logger from '@core/picgo/logger'
|
||||
import { Octokit } from '@octokit/rest'
|
||||
import axios from 'axios'
|
||||
import { app } from 'electron'
|
||||
import fs from 'fs-extra'
|
||||
import { HttpsProxyAgent } from 'hpagent'
|
||||
import path from 'path'
|
||||
import { Octokit } from '@octokit/rest'
|
||||
import { createClient, AuthType, WebDAVClientOptions } from 'webdav'
|
||||
import { AuthType, createClient, WebDAVClientOptions } from 'webdav'
|
||||
|
||||
import db from '@core/datastore'
|
||||
import logger from '@core/picgo/logger'
|
||||
|
||||
import { configPaths } from '#/utils/configPaths'
|
||||
import { ISyncConfig } from '#/types/types'
|
||||
import { formatEndpoint } from '#/utils/common'
|
||||
import { configPaths } from '#/utils/configPaths'
|
||||
|
||||
const STORE_PATH = app.getPath('userData')
|
||||
|
||||
@@ -36,16 +37,16 @@ const getSyncConfig = () => {
|
||||
const getProxyagent = (proxy: string | undefined) => {
|
||||
return proxy
|
||||
? new HttpsProxyAgent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 1000,
|
||||
rejectUnauthorized: false,
|
||||
proxy: proxy.replace('127.0.0.1', 'localhost'),
|
||||
scheduling: 'lifo'
|
||||
})
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 1000,
|
||||
rejectUnauthorized: false,
|
||||
proxy: proxy.replace('127.0.0.1', 'localhost'),
|
||||
scheduling: 'lifo'
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
|
||||
function getOctokit(syncConfig: ISyncConfig) {
|
||||
function getOctokit (syncConfig: ISyncConfig) {
|
||||
const { token, proxy } = syncConfig
|
||||
return new Octokit({
|
||||
auth: token,
|
||||
@@ -82,7 +83,7 @@ const isSyncConfigValidate = ({
|
||||
return type && username && repo && branch && token
|
||||
}
|
||||
|
||||
async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) {
|
||||
async function uploadLocalToRemote (syncConfig: ISyncConfig, fileName: string) {
|
||||
const localFilePath = path.join(STORE_PATH, fileName)
|
||||
if (!fs.existsSync(localFilePath)) {
|
||||
return false
|
||||
@@ -160,7 +161,7 @@ async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) {
|
||||
async function updateLocalToRemote (syncConfig: ISyncConfig, fileName: string) {
|
||||
const localFilePath = path.join(STORE_PATH, fileName)
|
||||
if (!fs.existsSync(localFilePath)) {
|
||||
return false
|
||||
@@ -276,7 +277,7 @@ async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadFile(fileName: string[]): Promise<number> {
|
||||
async function uploadFile (fileName: string[]): Promise<number> {
|
||||
const syncConfig = getSyncConfig()
|
||||
if (!isSyncConfigValidate(syncConfig)) {
|
||||
logger.error('sync config is invalid')
|
||||
@@ -301,7 +302,7 @@ async function uploadFile(fileName: string[]): Promise<number> {
|
||||
return count
|
||||
}
|
||||
|
||||
async function downloadAndWriteFile(url: string, localFilePath: string, config: any, isWriteJson = false) {
|
||||
async function downloadAndWriteFile (url: string, localFilePath: string, config: any, isWriteJson = false) {
|
||||
const res = await axios.get(url, config)
|
||||
if (isHttpResSuccess(res)) {
|
||||
await fs.writeFile(
|
||||
@@ -313,7 +314,7 @@ async function downloadAndWriteFile(url: string, localFilePath: string, config:
|
||||
return false
|
||||
}
|
||||
|
||||
async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string) {
|
||||
async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string) {
|
||||
const localFilePath = path.join(STORE_PATH, fileName)
|
||||
const { username, repo, branch, token, proxy, type } = syncConfig
|
||||
try {
|
||||
@@ -393,7 +394,7 @@ async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string)
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadFile(fileName: string[]): Promise<number> {
|
||||
async function downloadFile (fileName: string[]): Promise<number> {
|
||||
const syncConfig = getSyncConfig()
|
||||
if (!isSyncConfigValidate(syncConfig)) {
|
||||
logger.error('sync config is invalid')
|
||||
@@ -409,4 +410,4 @@ async function downloadFile(fileName: string[]): Promise<number> {
|
||||
return (await Promise.all(fileName.map(downloadFunc))).reduce((a, b) => a + b, 0)
|
||||
}
|
||||
|
||||
export { uploadFile, downloadFile }
|
||||
export { downloadFile, uploadFile }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { autoUpdater } from 'electron-updater'
|
||||
|
||||
import db from '@core/datastore'
|
||||
import updater from 'electron-updater'
|
||||
|
||||
import { configPaths } from '#/utils/configPaths'
|
||||
|
||||
@@ -12,7 +11,7 @@ const updateChecker = async () => {
|
||||
}
|
||||
if (showTip) {
|
||||
try {
|
||||
await autoUpdater.checkForUpdatesAndNotify()
|
||||
await updater.autoUpdater.checkForUpdatesAndNotify()
|
||||
} catch (err) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { screen } from 'electron'
|
||||
|
||||
import db from '@core/datastore'
|
||||
|
||||
import windowManager from 'apis/app/window/windowManager'
|
||||
import { screen } from 'electron'
|
||||
|
||||
import { IWindowList } from '#/types/enum'
|
||||
import { configPaths } from '#/utils/configPaths'
|
||||
|
||||
export function openMiniWindow(hideSettingWindow: boolean = true) {
|
||||
export function openMiniWindow (hideSettingWindow: boolean = true) {
|
||||
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
|
||||
miniWindow.removeAllListeners()
|
||||
if (db.get(configPaths.settings.miniWindowOntop)) {
|
||||
|
||||
Reference in New Issue
Block a user