🎨 Style(custom): lint code

This commit is contained in:
Kuingsmile
2025-08-15 13:29:09 +08:00
parent 0ae27cfeef
commit f11a4264d0
160 changed files with 18208 additions and 20414 deletions

View File

@@ -23,12 +23,12 @@ class RemoteNoticeHandler {
private remoteNotice: IRemoteNotice | null = null
private remoteNoticeLocalCountStorage: IRemoteNoticeLocalCountStorage | null = null
async init () {
async init() {
this.remoteNotice = await this.getRemoteNoticeInfo()
this.initLocalCountStorage()
}
private initLocalCountStorage () {
private initLocalCountStorage() {
const localCountStorage = {}
if (!fs.existsSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH)) {
fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify({}))
@@ -44,14 +44,14 @@ class RemoteNoticeHandler {
}
}
private saveLocalCountStorage (newData?: IRemoteNoticeLocalCountStorage) {
private saveLocalCountStorage(newData?: IRemoteNoticeLocalCountStorage) {
if (newData) {
this.remoteNoticeLocalCountStorage = newData
}
fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify(this.remoteNoticeLocalCountStorage))
}
private async getRemoteNoticeInfo (): Promise<IRemoteNotice | null> {
private async getRemoteNoticeInfo(): Promise<IRemoteNotice | null> {
try {
const noticeInfo = (await axios({
method: 'get',
@@ -68,7 +68,7 @@ class RemoteNoticeHandler {
* if the notice is not shown or is always shown, then show the notice
* @param action
*/
private checkActionCount (action: IRemoteNoticeAction) {
private checkActionCount(action: IRemoteNoticeAction) {
try {
if (!this.remoteNoticeLocalCountStorage) {
return true
@@ -102,7 +102,7 @@ class RemoteNoticeHandler {
}
}
private async doActions (actions: IRemoteNoticeAction[]) {
private async doActions(actions: IRemoteNoticeAction[]) {
for (const action of actions) {
if (this.checkActionCount(action)) {
switch (action.type) {
@@ -117,7 +117,7 @@ class RemoteNoticeHandler {
body: action.data?.content || '',
clickToCopy: !!action.data?.copyToClipboard,
copyContent: action.data?.copyToClipboard || '',
clickFn () {
clickFn() {
if (action.data?.url) {
shell.openExternal(action.data.url)
}
@@ -163,7 +163,7 @@ class RemoteNoticeHandler {
}
}
triggerHook (hook: string) {
triggerHook(hook: string) {
if (!this.remoteNotice || !this.remoteNotice.list) {
return
}

View File

@@ -6,24 +6,30 @@ import shortKeyService from 'apis/app/shortKey/shortKeyService'
import GuiApi from 'apis/gui'
import { globalShortcut } from 'electron'
import type { IKeyCommandType, IPluginShortKeyConfig, IShortKeyConfig, IShortKeyConfigs, IShortKeyHandler } from '#/types/types'
import type {
IKeyCommandType,
IPluginShortKeyConfig,
IShortKeyConfig,
IShortKeyConfigs,
IShortKeyHandler
} from '#/types/types'
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant'
import { configPaths } from '~/utils/configPaths'
class ShortKeyHandler {
private isInModifiedMode: boolean = false
constructor () {
constructor() {
bus.on(TOGGLE_SHORTKEY_MODIFIED_MODE, flag => {
this.isInModifiedMode = flag
})
}
async init () {
async init() {
this.initBuiltInShortKey()
await this.initPluginsShortKey()
}
private initBuiltInShortKey () {
private initBuiltInShortKey() {
const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs
Object.keys(commands)
.filter(item => item.includes('picgo:'))
@@ -38,7 +44,7 @@ class ShortKeyHandler {
})
}
private async initPluginsShortKey () {
private async initPluginsShortKey() {
// get enabled plugin
const pluginList = picgo.pluginLoader.getList()
for (const item of pluginList) {
@@ -68,7 +74,7 @@ class ShortKeyHandler {
}
}
private registerShortKey (
private registerShortKey(
config: IShortKeyConfig | IPluginShortKeyConfig,
command: string,
handler: IShortKeyHandler,
@@ -97,7 +103,7 @@ class ShortKeyHandler {
}
// enable or disable shortKey
bindOrUnbindShortKey (item: IShortKeyConfig, from: string): boolean {
bindOrUnbindShortKey(item: IShortKeyConfig, from: string): boolean {
const command = `${from}:${item.name}`
if (item.enable === false) {
globalShortcut.unregister(item.key)
@@ -121,7 +127,7 @@ class ShortKeyHandler {
}
// update shortKey bindings
updateShortKey (item: IShortKeyConfig, oldKey: string, from: string): boolean {
updateShortKey(item: IShortKeyConfig, oldKey: string, from: string): boolean {
const command = `${from}:${item.name}`
if (globalShortcut.isRegistered(item.key)) return false
globalShortcut.unregister(oldKey)
@@ -134,7 +140,7 @@ class ShortKeyHandler {
return true
}
private async handler (command: string) {
private async handler(command: string) {
if (this.isInModifiedMode) {
return
}
@@ -150,7 +156,7 @@ class ShortKeyHandler {
}
}
async registerPluginShortKey (pluginName: string) {
async registerPluginShortKey(pluginName: string) {
const plugin = await picgo.pluginLoader.getPlugin(pluginName)
if (plugin && plugin.commands) {
if (typeof plugin.commands !== 'function') {
@@ -170,7 +176,7 @@ class ShortKeyHandler {
}
}
unregisterPluginShortKey (pluginName: string) {
unregisterPluginShortKey(pluginName: string) {
const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs
const keyList = Object.keys(commands)
.filter(command => command.includes(pluginName))

View File

@@ -4,22 +4,22 @@ import type { IShortKeyHandler } from '#/types/types'
class ShortKeyService {
private commandList: Map<string, IShortKeyHandler> = new Map()
registerCommand (command: string, handler: IShortKeyHandler) {
registerCommand(command: string, handler: IShortKeyHandler) {
this.commandList.set(command, handler)
}
unregisterCommand (command: string) {
unregisterCommand(command: string) {
this.commandList.delete(command)
}
getShortKeyHandler (command: string): IShortKeyHandler | null {
getShortKeyHandler(command: string): IShortKeyHandler | null {
const handler = this.commandList.get(command)
if (handler) return handler
logger.warn(`cannot find command: ${command}`)
return null
}
getCommandList () {
getCommandList() {
return [...this.commandList.keys()]
}
}

View File

@@ -36,7 +36,7 @@ import uploadPng from '../../../../../resources/upload.png?asset&asarUnpack'
import uploadDarkPng from '../../../../../resources/upload-dark.png?asset&asarUnpack'
let contextMenu: Menu | null
export function setDockMenu () {
export function setDockMenu() {
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
const dockMenu = Menu.buildFromTemplate([
{
@@ -45,7 +45,7 @@ export function setDockMenu () {
},
{
label: $t('START_WATCH_CLIPBOARD'),
click () {
click() {
db.set(configPaths.settings.isListeningClipboard, true)
clipboardPoll.startListening()
clipboardPoll.on('change', () => {
@@ -58,7 +58,7 @@ export function setDockMenu () {
},
{
label: $t('STOP_WATCH_CLIPBOARD'),
click () {
click() {
db.set(configPaths.settings.isListeningClipboard, false)
clipboardPoll.stopListening()
clipboardPoll.removeAllListeners()
@@ -70,7 +70,7 @@ export function setDockMenu () {
app.dock?.setMenu(dockMenu)
}
export function createMenu () {
export function createMenu() {
const submenu = buildPicBedListMenu()
const appMenu = Menu.buildFromTemplate([
{
@@ -79,7 +79,7 @@ export function createMenu () {
{ label: $t('OPEN_MAIN_WINDOW'), click: openMainWindow },
{
label: $t('RELOAD_APP'),
click () {
click() {
app.relaunch()
app.exit(0)
}
@@ -107,7 +107,7 @@ export function createMenu () {
Menu.setApplicationMenu(appMenu)
}
export function createContextMenu () {
export function createContextMenu() {
const ClipboardWatcher = clipboardPoll
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
const isMiniWindowVisible =
@@ -147,7 +147,7 @@ export function createContextMenu () {
},
{
label: $t('RELOAD_APP'),
click () {
click() {
app.relaunch()
app.exit(0)
}
@@ -160,7 +160,7 @@ export function createContextMenu () {
0,
{
label: $t('OPEN_MINI_WINDOW'),
click () {
click() {
openMiniWindow(false)
},
visible: !isMiniWindowVisible
@@ -185,7 +185,7 @@ export function createContextMenu () {
{ label: $t('OPEN_MAIN_WINDOW'), click: openMainWindow },
{
label: $t('OPEN_MINI_WINDOW'),
click () {
click() {
openMiniWindow(false)
},
visible: !isMiniWindowVisible
@@ -207,7 +207,7 @@ export function createContextMenu () {
},
{
label: $t('ABOUT'),
click () {
click() {
dialog.showMessageBox({
title: 'PicList',
message: 'PicList',
@@ -230,7 +230,7 @@ const getTrayIcon = () => {
}
}
export function createTray (tooltip: string) {
export function createTray(tooltip: string) {
const menubarPic = getTrayIcon()
setTray(new Tray(menubarPic))
tray.setToolTip(tooltip)
@@ -309,7 +309,7 @@ export function createTray (tooltip: string) {
// drop-files only be supported in macOS
// so the tray window must be available
if (process.platform === 'darwin') {
(tray as any).on('drop-files', async (_: Event, files: string[]) => {
;(tray as any).on('drop-files', async (_: Event, files: string[]) => {
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const rawInput = cloneDeep(files)
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
@@ -338,14 +338,14 @@ export function createTray (tooltip: string) {
imgs[i].shortUrl = shortUrl
pasteText.push(pasteTextItem)
const isShowResultNotification =
db.get(configPaths.settings.uploadResultNotification) === undefined
? true
: !!db.get(configPaths.settings.uploadResultNotification)
db.get(configPaths.settings.uploadResultNotification) === undefined
? true
: !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) {
const notification = new Notification({
title: $t('UPLOAD_SUCCEED'),
body: shortUrl || imgs[i].imgUrl!
// icon: files[i]
// icon: files[i]
})
setTimeout(() => {
notification.show()

View File

@@ -1,236 +1,236 @@
import db, { GalleryDB } from '@core/datastore'
import picgo from '@core/picgo'
import uploader from 'apis/app/uploader'
import windowManager from 'apis/app/window/windowManager'
import { Notification, WebContents } from 'electron'
import fs from 'fs-extra'
import { cloneDeep } from 'lodash-es'
import type { IPicGo } from 'piclist'
import type { IFileWithPath, ImgInfo, IStringKeyMap, IUploadOption } from '#/types/types'
import { T as $t } from '~/i18n/index'
import { handleCopyUrl, handleUrlEncodeWithSetting } from '~/utils/common'
import { configPaths } from '~/utils/configPaths'
import { IPasteStyle, IWindowList } from '~/utils/enum'
import { changeCurrentUploader } from '~/utils/handleUploaderConfig'
import pasteTemplate from '~/utils/pasteTemplate'
const handleClipboardUploading = async (): Promise<false | ImgInfo[]> => {
const useBuiltinClipboard =
db.get(configPaths.settings.useBuiltinClipboard) === undefined
? true
: !!db.get(configPaths.settings.useBuiltinClipboard)
const win = windowManager.getAvailableWindow()
if (useBuiltinClipboard) {
return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboard()
}
return await uploader.setWebContents(win!.webContents).upload()
}
const handleClipboardUploadingReturnCtx = async (img?: IUploadOption, skipProcess = false): Promise<false | IPicGo> => {
const useBuiltinClipboard =
db.get(configPaths.settings.useBuiltinClipboard) === undefined
? true
: !!db.get(configPaths.settings.useBuiltinClipboard)
const win = windowManager.getAvailableWindow()
if (useBuiltinClipboard) {
return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboardReturnCtx(img, skipProcess)
}
return await uploader.setWebContents(win!.webContents).uploadReturnCtx(img, skipProcess)
}
export const uploadClipboardFiles = async (): Promise<IStringKeyMap> => {
const { needRestore, ctx } = await handleSecondaryUpload(undefined, undefined, 'clipboard')
let img: ImgInfo[] | false = false
if (needRestore) {
const res = await handleClipboardUploadingReturnCtx(ctx ? ctx.processedInput : undefined, true)
img = res ? res.output : false
} else {
img = await handleClipboardUploading()
}
if (img !== false) {
if (img.length > 0) {
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const [pastedText, shortUrl] = await pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink))
img[0].shortUrl = shortUrl
handleCopyUrl(pastedText)
const isShowResultNotification =
db.get(configPaths.settings.uploadResultNotification) === undefined
? true
: !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) {
const notification = new Notification({
title: $t('UPLOAD_SUCCEED'),
body: shortUrl || img[0].imgUrl!
// icon: img[0].imgUrl
})
setTimeout(() => {
notification.show()
}, 100)
}
const inserted = await GalleryDB.getInstance().insert(img[0])
// trayWindow just be created in mac/windows, not in linux
trayWindow?.webContents?.send('clipboardFiles', [])
trayWindow?.webContents?.send('uploadFiles', img)
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
}
return {
url: handleUrlEncodeWithSetting(inserted.imgUrl as string),
fullResult: inserted
}
} else {
const notification = new Notification({
title: $t('UPLOAD_FAILED'),
body: $t('TIPS_UPLOAD_NOT_PICTURES')
})
notification.show()
return {
url: '',
fullResult: {}
}
}
} else {
return {
url: '',
fullResult: {}
}
}
}
export const uploadChoosedFiles = async (
webContents: WebContents,
files: IFileWithPath[]
): Promise<IStringKeyMap[]> => {
const input = files.map(item => item.path)
const rawInput = cloneDeep(input)
const { needRestore, ctx } = await handleSecondaryUpload(webContents, input)
let imgs: ImgInfo[] | false = false
if (needRestore) {
const res = await uploader.setWebContents(webContents).uploadReturnCtx(ctx ? ctx.processedInput : input, true)
imgs = res ? res.output : false
} else {
imgs = await uploader.setWebContents(webContents).upload(input)
}
const result = []
if (imgs !== false) {
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const deleteLocalFile = db.get(configPaths.settings.deleteLocalFile) || false
const pasteText: string[] = []
for (let i = 0; i < imgs.length; i++) {
if (deleteLocalFile) {
fs.remove(rawInput[i])
.then(() => {
picgo.log.info(`delete local file: ${rawInput[i]}`)
})
.catch((err: Error) => {
picgo.log.error(err)
})
}
const [pasteTextItem, shortUrl] = await pasteTemplate(
pasteStyle,
imgs[i],
db.get(configPaths.settings.customLink)
)
imgs[i].shortUrl = shortUrl
pasteText.push(pasteTextItem)
const isShowResultNotification =
db.get(configPaths.settings.uploadResultNotification) === undefined
? true
: !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) {
const notification = new Notification({
title: $t('UPLOAD_SUCCEED'),
body: shortUrl || imgs[i].imgUrl!
// icon: files[i].path
})
setTimeout(() => {
notification.show()
}, i * 100)
}
const inserted = await GalleryDB.getInstance().insert(imgs[i])
result.push({
url: handleUrlEncodeWithSetting(inserted.imgUrl!),
fullResult: inserted
})
}
handleCopyUrl(pasteText.join('\n'))
// trayWindow just be created in mac/windows, not in linux
windowManager.get(IWindowList.TRAY_WINDOW)?.webContents?.send('uploadFiles', imgs)
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
}
return result
} else {
return []
}
}
export const handleSecondaryUpload = async (
webContents?: WebContents,
input?: string[],
uploadType: 'clipboard' | 'file' | 'tray' = 'file'
): Promise<{ needRestore: boolean; ctx: IPicGo | false }> => {
const enableSecondUploader = db.get(configPaths.settings.enableSecondUploader) || false
let currentPicBedType = ''
let currentPicBedConfig = {} as IStringKeyMap
let currentPicBedConfigId = ''
let needRestore = false
let ctx: IPicGo | false = false
if (enableSecondUploader) {
const secondUploader = db.get(configPaths.picBed.secondUploader)
const secondUploaderConfig = db.get(configPaths.picBed.secondUploaderConfig)
const secondUploaderId = db.get(configPaths.picBed.secondUploaderId)
const currentPicBed = db.get('picBed') || ({} as IStringKeyMap)
currentPicBedType = currentPicBed.uploader || currentPicBed.current || 'smms'
currentPicBedConfig = currentPicBed[currentPicBedType] || ({} as IStringKeyMap)
currentPicBedConfigId = currentPicBedConfig._id
if (
secondUploader === currentPicBedType &&
secondUploaderConfig._configName === currentPicBedConfig._configName &&
secondUploaderId === currentPicBedConfigId
) {
picgo.log.info('second uploader is the same as current uploader')
} else {
needRestore = true
let secondImgs: ImgInfo[] | false = false
changeCurrentUploader(secondUploader, secondUploaderConfig, secondUploaderId)
if (uploadType === 'clipboard') {
ctx = await handleClipboardUploadingReturnCtx(undefined)
} else {
ctx = await uploader.setWebContents(webContents!).uploadReturnCtx(input)
}
secondImgs = ctx ? ctx.output : false
if (secondImgs !== false) {
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
if (uploadType === 'clipboard') {
if (secondImgs.length > 0) {
await GalleryDB.getInstance().insert(secondImgs[0])
trayWindow?.webContents?.send('clipboardFiles', [])
trayWindow?.webContents?.send('uploadFiles', secondImgs)
}
} else {
for (const secondImgsItem of secondImgs) {
await GalleryDB.getInstance().insert(secondImgsItem)
}
if (uploadType === 'tray') {
trayWindow?.webContents?.send('dragFiles', secondImgs)
} else {
trayWindow?.webContents?.send('uploadFiles', secondImgs)
}
}
if (windowManager.has(IWindowList.SETTING_WINDOW) && uploadType !== 'tray') {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
}
}
}
}
if (needRestore) {
changeCurrentUploader(currentPicBedType, currentPicBedConfig, currentPicBedConfigId)
}
return {
needRestore,
ctx
}
}
import db, { GalleryDB } from '@core/datastore'
import picgo from '@core/picgo'
import uploader from 'apis/app/uploader'
import windowManager from 'apis/app/window/windowManager'
import { Notification, WebContents } from 'electron'
import fs from 'fs-extra'
import { cloneDeep } from 'lodash-es'
import type { IPicGo } from 'piclist'
import type { IFileWithPath, ImgInfo, IStringKeyMap, IUploadOption } from '#/types/types'
import { T as $t } from '~/i18n/index'
import { handleCopyUrl, handleUrlEncodeWithSetting } from '~/utils/common'
import { configPaths } from '~/utils/configPaths'
import { IPasteStyle, IWindowList } from '~/utils/enum'
import { changeCurrentUploader } from '~/utils/handleUploaderConfig'
import pasteTemplate from '~/utils/pasteTemplate'
const handleClipboardUploading = async (): Promise<false | ImgInfo[]> => {
const useBuiltinClipboard =
db.get(configPaths.settings.useBuiltinClipboard) === undefined
? true
: !!db.get(configPaths.settings.useBuiltinClipboard)
const win = windowManager.getAvailableWindow()
if (useBuiltinClipboard) {
return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboard()
}
return await uploader.setWebContents(win!.webContents).upload()
}
const handleClipboardUploadingReturnCtx = async (img?: IUploadOption, skipProcess = false): Promise<false | IPicGo> => {
const useBuiltinClipboard =
db.get(configPaths.settings.useBuiltinClipboard) === undefined
? true
: !!db.get(configPaths.settings.useBuiltinClipboard)
const win = windowManager.getAvailableWindow()
if (useBuiltinClipboard) {
return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboardReturnCtx(img, skipProcess)
}
return await uploader.setWebContents(win!.webContents).uploadReturnCtx(img, skipProcess)
}
export const uploadClipboardFiles = async (): Promise<IStringKeyMap> => {
const { needRestore, ctx } = await handleSecondaryUpload(undefined, undefined, 'clipboard')
let img: ImgInfo[] | false = false
if (needRestore) {
const res = await handleClipboardUploadingReturnCtx(ctx ? ctx.processedInput : undefined, true)
img = res ? res.output : false
} else {
img = await handleClipboardUploading()
}
if (img !== false) {
if (img.length > 0) {
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const [pastedText, shortUrl] = await pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink))
img[0].shortUrl = shortUrl
handleCopyUrl(pastedText)
const isShowResultNotification =
db.get(configPaths.settings.uploadResultNotification) === undefined
? true
: !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) {
const notification = new Notification({
title: $t('UPLOAD_SUCCEED'),
body: shortUrl || img[0].imgUrl!
// icon: img[0].imgUrl
})
setTimeout(() => {
notification.show()
}, 100)
}
const inserted = await GalleryDB.getInstance().insert(img[0])
// trayWindow just be created in mac/windows, not in linux
trayWindow?.webContents?.send('clipboardFiles', [])
trayWindow?.webContents?.send('uploadFiles', img)
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
}
return {
url: handleUrlEncodeWithSetting(inserted.imgUrl as string),
fullResult: inserted
}
} else {
const notification = new Notification({
title: $t('UPLOAD_FAILED'),
body: $t('TIPS_UPLOAD_NOT_PICTURES')
})
notification.show()
return {
url: '',
fullResult: {}
}
}
} else {
return {
url: '',
fullResult: {}
}
}
}
export const uploadChoosedFiles = async (
webContents: WebContents,
files: IFileWithPath[]
): Promise<IStringKeyMap[]> => {
const input = files.map(item => item.path)
const rawInput = cloneDeep(input)
const { needRestore, ctx } = await handleSecondaryUpload(webContents, input)
let imgs: ImgInfo[] | false = false
if (needRestore) {
const res = await uploader.setWebContents(webContents).uploadReturnCtx(ctx ? ctx.processedInput : input, true)
imgs = res ? res.output : false
} else {
imgs = await uploader.setWebContents(webContents).upload(input)
}
const result = []
if (imgs !== false) {
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const deleteLocalFile = db.get(configPaths.settings.deleteLocalFile) || false
const pasteText: string[] = []
for (let i = 0; i < imgs.length; i++) {
if (deleteLocalFile) {
fs.remove(rawInput[i])
.then(() => {
picgo.log.info(`delete local file: ${rawInput[i]}`)
})
.catch((err: Error) => {
picgo.log.error(err)
})
}
const [pasteTextItem, shortUrl] = await pasteTemplate(
pasteStyle,
imgs[i],
db.get(configPaths.settings.customLink)
)
imgs[i].shortUrl = shortUrl
pasteText.push(pasteTextItem)
const isShowResultNotification =
db.get(configPaths.settings.uploadResultNotification) === undefined
? true
: !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) {
const notification = new Notification({
title: $t('UPLOAD_SUCCEED'),
body: shortUrl || imgs[i].imgUrl!
// icon: files[i].path
})
setTimeout(() => {
notification.show()
}, i * 100)
}
const inserted = await GalleryDB.getInstance().insert(imgs[i])
result.push({
url: handleUrlEncodeWithSetting(inserted.imgUrl!),
fullResult: inserted
})
}
handleCopyUrl(pasteText.join('\n'))
// trayWindow just be created in mac/windows, not in linux
windowManager.get(IWindowList.TRAY_WINDOW)?.webContents?.send('uploadFiles', imgs)
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
}
return result
} else {
return []
}
}
export const handleSecondaryUpload = async (
webContents?: WebContents,
input?: string[],
uploadType: 'clipboard' | 'file' | 'tray' = 'file'
): Promise<{ needRestore: boolean; ctx: IPicGo | false }> => {
const enableSecondUploader = db.get(configPaths.settings.enableSecondUploader) || false
let currentPicBedType = ''
let currentPicBedConfig = {} as IStringKeyMap
let currentPicBedConfigId = ''
let needRestore = false
let ctx: IPicGo | false = false
if (enableSecondUploader) {
const secondUploader = db.get(configPaths.picBed.secondUploader)
const secondUploaderConfig = db.get(configPaths.picBed.secondUploaderConfig)
const secondUploaderId = db.get(configPaths.picBed.secondUploaderId)
const currentPicBed = db.get('picBed') || ({} as IStringKeyMap)
currentPicBedType = currentPicBed.uploader || currentPicBed.current || 'smms'
currentPicBedConfig = currentPicBed[currentPicBedType] || ({} as IStringKeyMap)
currentPicBedConfigId = currentPicBedConfig._id
if (
secondUploader === currentPicBedType &&
secondUploaderConfig._configName === currentPicBedConfig._configName &&
secondUploaderId === currentPicBedConfigId
) {
picgo.log.info('second uploader is the same as current uploader')
} else {
needRestore = true
let secondImgs: ImgInfo[] | false = false
changeCurrentUploader(secondUploader, secondUploaderConfig, secondUploaderId)
if (uploadType === 'clipboard') {
ctx = await handleClipboardUploadingReturnCtx(undefined)
} else {
ctx = await uploader.setWebContents(webContents!).uploadReturnCtx(input)
}
secondImgs = ctx ? ctx.output : false
if (secondImgs !== false) {
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
if (uploadType === 'clipboard') {
if (secondImgs.length > 0) {
await GalleryDB.getInstance().insert(secondImgs[0])
trayWindow?.webContents?.send('clipboardFiles', [])
trayWindow?.webContents?.send('uploadFiles', secondImgs)
}
} else {
for (const secondImgsItem of secondImgs) {
await GalleryDB.getInstance().insert(secondImgsItem)
}
if (uploadType === 'tray') {
trayWindow?.webContents?.send('dragFiles', secondImgs)
} else {
trayWindow?.webContents?.send('uploadFiles', secondImgs)
}
}
if (windowManager.has(IWindowList.SETTING_WINDOW) && uploadType !== 'tray') {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
}
}
}
}
if (needRestore) {
changeCurrentUploader(currentPicBedType, currentPicBedConfig, currentPicBedConfigId)
}
return {
needRestore,
ctx
}
}

View File

@@ -36,11 +36,11 @@ const waitForRename = (window: BrowserWindow, id: number): Promise<string | null
class Uploader {
private webContents: WebContents | null = null
constructor () {
constructor() {
this.init()
}
init () {
init() {
picgo.on(ICOREBuildInEvent.NOTIFICATION, (message: any) => {
new Notification(message).show()
})
@@ -92,12 +92,12 @@ class Uploader {
})
}
setWebContents (webContents: WebContents) {
setWebContents(webContents: WebContents) {
this.webContents = webContents
return this
}
private async getClipboardImagePath (): Promise<string | false> {
private async getClipboardImagePath(): Promise<string | false> {
const imgPath = getClipboardFilePath()
if (imgPath) return imgPath
@@ -115,7 +115,7 @@ class Uploader {
/**
* use electron's clipboard image to upload
*/
async uploadWithBuildInClipboard (): Promise<ImgInfo[] | false> {
async uploadWithBuildInClipboard(): Promise<ImgInfo[] | false> {
let imgPath: string | false = false
try {
imgPath = await this.getClipboardImagePath()
@@ -131,7 +131,7 @@ class Uploader {
}
}
async uploadWithBuildInClipboardReturnCtx (img?: IUploadOption, skipProcess = false): Promise<IPicGo | false> {
async uploadWithBuildInClipboardReturnCtx(img?: IUploadOption, skipProcess = false): Promise<IPicGo | false> {
let imgPath: string | false = false
try {
imgPath = await this.getClipboardImagePath()
@@ -147,7 +147,7 @@ class Uploader {
}
}
async uploadReturnCtx (img?: IUploadOption, skipProcess = false): Promise<IPicGo | false> {
async uploadReturnCtx(img?: IUploadOption, skipProcess = false): Promise<IPicGo | false> {
try {
const ctx = await picgo.uploadReturnCtx(img, skipProcess)
if (!Array.isArray(ctx.output) || !ctx.output.some((item: ImgInfo) => item.imgUrl)) return false
@@ -172,7 +172,7 @@ class Uploader {
}
}
async upload (img?: IUploadOption): Promise<ImgInfo[] | false> {
async upload(img?: IUploadOption): Promise<ImgInfo[] | false> {
try {
const output = await picgo.upload(img)
if (!Array.isArray(output) || !output.some((item: ImgInfo) => item.imgUrl)) return false

View File

@@ -1,277 +1,277 @@
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import bus from '@core/bus'
import { CREATE_APP_MENU } from '@core/bus/constants'
import db from '@core/datastore'
import { app, BrowserWindow, Rectangle } from 'electron'
import type { IWindowListItem } from '#/types/electron'
import type { IBrowserWindowOptions } from '#/types/types'
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant'
import { T as $t } from '~/i18n'
import { configPaths } from '~/utils/configPaths'
import { IWindowList } from '~/utils/enum'
import logo from '../../../../../resources/logo.png?asset&asarUnpack'
const windowList = new Map<string, IWindowListItem>()
const getDefaultWindowSizes = (): { width: number; height: number } => {
const [mainWindowWidth, mainWindowHeight] = db.get([
configPaths.settings.mainWindowWidth,
configPaths.settings.mainWindowHeight
])
return {
width: mainWindowWidth || 1200,
height: mainWindowHeight || 800
}
}
function setMiniWindowShape (win: BrowserWindow) {
const radius = 32
const shape: Rectangle[] = []
for (let y = -radius; y <= radius; y++) {
for (let x = -radius; x <= radius; x++) {
if (x * x + y * y <= radius * radius) {
shape.push({ x: radius + x, y: radius + y, width: 1, height: 1 })
}
}
}
win.setShape(shape)
}
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const preloadPath = fileURLToPath(new URL('../preload/index.mjs', import.meta.url))
const { width: defaultWindowWidth, height: defaultWindowHeight } = getDefaultWindowSizes()
const trayWindowOptions = {
height: 350,
width: 196,
show: false,
frame: false,
fullscreenable: false,
resizable: false,
transparent: true,
vibrancy: 'ultra-dark',
webPreferences: {
sandbox: false,
preload: preloadPath,
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
backgroundThrottling: true,
webSecurity: false
}
}
const settingWindowOptions = {
height: defaultWindowHeight,
width: defaultWindowWidth,
show: false,
frame: true,
center: true,
fullscreenable: true,
resizable: true,
title: 'PicList',
transparent: false,
backgroundColor: '#ebeef5',
titleBarStyle: 'hidden',
webPreferences: {
sandbox: false,
webviewTag: true,
backgroundThrottling: true,
preload: preloadPath,
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
webSecurity: false
}
} as IBrowserWindowOptions
if (process.platform !== 'darwin') {
settingWindowOptions.frame = false
settingWindowOptions.icon = logo
}
const miniWindowOptions = {
height: 64,
width: 64,
show: process.platform === 'linux',
frame: false,
fullscreenable: false,
skipTaskbar: true,
resizable: false,
transparent: process.platform !== 'linux',
icon: logo,
webPreferences: {
sandbox: false,
preload: preloadPath,
nodeIntegration: false,
contextIsolation: true,
backgroundThrottling: true,
nodeIntegrationInWorker: false
}
} as IBrowserWindowOptions
if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindowOptions.alwaysOnTop = true
}
const renameWindowOptions = {
height: 270,
width: 350,
show: true,
fullscreenable: false,
icon: logo,
resizable: true,
webPreferences: {
sandbox: false,
preload: preloadPath,
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
backgroundThrottling: false
}
} as IBrowserWindowOptions
if (process.platform !== 'darwin') {
renameWindowOptions.show = true
renameWindowOptions.backgroundColor = '#3f3c37'
renameWindowOptions.autoHideMenuBar = true
renameWindowOptions.transparent = false
}
const toolboxWindowOptions = {
height: 450,
width: 800,
show: false,
frame: true,
center: true,
fullscreenable: false,
resizable: false,
title: `PicList ${$t('TOOLBOX')}`,
backgroundColor: '#ebeef5',
icon: logo,
webPreferences: {
sandbox: false,
backgroundThrottling: true,
preload: preloadPath,
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
webSecurity: false
}
} as IBrowserWindowOptions
if (process.platform !== 'darwin') {
toolboxWindowOptions.backgroundColor = '#3f3c37'
toolboxWindowOptions.autoHideMenuBar = true
toolboxWindowOptions.transparent = false
}
windowList.set(IWindowList.TRAY_WINDOW, {
isValid: process.platform !== 'linux',
multiple: false,
options: () => trayWindowOptions,
callback (window) {
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
window.loadURL(process.env.ELECTRON_RENDERER_URL)
} else {
window.loadFile(path.join(__dirname, '../renderer/index.html'))
}
window.on('blur', () => {
window.hide()
})
}
})
windowList.set(IWindowList.SETTING_WINDOW, {
isValid: true,
multiple: false,
options: () => settingWindowOptions,
callback (window, windowManager) {
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#main-page/upload`)
} else {
window.loadFile(path.join(__dirname, '../renderer/index.html'), {
hash: 'main-page/upload'
})
}
window.on('closed', () => {
bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, false)
if (process.platform === 'linux') {
process.nextTick(() => {
app.quit()
})
}
})
bus.emit(CREATE_APP_MENU)
windowManager.create(IWindowList.MINI_WINDOW)
}
})
windowList.set(IWindowList.MINI_WINDOW, {
isValid: process.platform !== 'darwin',
multiple: false,
options: () => miniWindowOptions,
callback (window) {
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#mini-page`)
} else {
window.loadFile(path.join(__dirname, '../renderer/index.html'), {
hash: 'mini-page'
})
}
setMiniWindowShape(window)
}
})
windowList.set(IWindowList.RENAME_WINDOW, {
isValid: true,
multiple: true,
options: () => renameWindowOptions,
async callback (window, windowManager) {
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#rename-page`)
} else {
window.loadFile(path.join(__dirname, '../renderer/index.html'), {
hash: 'rename-page'
})
}
const currentWindow = windowManager.getAvailableWindow(true)
if (currentWindow && currentWindow.isVisible()) {
const { x, y, width, height } = currentWindow.getBounds()
const positionX = Math.floor(x + width / 2 - 150)
const positionY = Math.floor(y + height / 2 - (height > 400 ? 88 : 0))
window.setPosition(positionX, positionY, false)
}
}
})
windowList.set(IWindowList.TOOLBOX_WINDOW, {
isValid: true,
multiple: false,
options: () => toolboxWindowOptions,
async callback (window, windowManager) {
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#toolbox-page`)
} else {
window.loadFile(path.join(__dirname, '../renderer/index.html'), {
hash: 'toolbox-page'
})
}
const currentWindow = windowManager.getAvailableWindow(true)
if (currentWindow && currentWindow.isVisible()) {
const { x, y, width, height } = currentWindow.getBounds()
const positionX = Math.floor(x + width / 2 - 400)
const positionY = Math.floor(y + height / 2 - (height > 400 ? 225 : 0))
window.setPosition(positionX, positionY, false)
}
}
})
export default windowList
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import bus from '@core/bus'
import { CREATE_APP_MENU } from '@core/bus/constants'
import db from '@core/datastore'
import { app, BrowserWindow, Rectangle } from 'electron'
import type { IWindowListItem } from '#/types/electron'
import type { IBrowserWindowOptions } from '#/types/types'
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant'
import { T as $t } from '~/i18n'
import { configPaths } from '~/utils/configPaths'
import { IWindowList } from '~/utils/enum'
import logo from '../../../../../resources/logo.png?asset&asarUnpack'
const windowList = new Map<string, IWindowListItem>()
const getDefaultWindowSizes = (): { width: number; height: number } => {
const [mainWindowWidth, mainWindowHeight] = db.get([
configPaths.settings.mainWindowWidth,
configPaths.settings.mainWindowHeight
])
return {
width: mainWindowWidth || 1200,
height: mainWindowHeight || 800
}
}
function setMiniWindowShape(win: BrowserWindow) {
const radius = 32
const shape: Rectangle[] = []
for (let y = -radius; y <= radius; y++) {
for (let x = -radius; x <= radius; x++) {
if (x * x + y * y <= radius * radius) {
shape.push({ x: radius + x, y: radius + y, width: 1, height: 1 })
}
}
}
win.setShape(shape)
}
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const preloadPath = fileURLToPath(new URL('../preload/index.mjs', import.meta.url))
const { width: defaultWindowWidth, height: defaultWindowHeight } = getDefaultWindowSizes()
const trayWindowOptions = {
height: 350,
width: 196,
show: false,
frame: false,
fullscreenable: false,
resizable: false,
transparent: true,
vibrancy: 'ultra-dark',
webPreferences: {
sandbox: false,
preload: preloadPath,
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
backgroundThrottling: true,
webSecurity: false
}
}
const settingWindowOptions = {
height: defaultWindowHeight,
width: defaultWindowWidth,
show: false,
frame: true,
center: true,
fullscreenable: true,
resizable: true,
title: 'PicList',
transparent: false,
backgroundColor: '#ebeef5',
titleBarStyle: 'hidden',
webPreferences: {
sandbox: false,
webviewTag: true,
backgroundThrottling: true,
preload: preloadPath,
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
webSecurity: false
}
} as IBrowserWindowOptions
if (process.platform !== 'darwin') {
settingWindowOptions.frame = false
settingWindowOptions.icon = logo
}
const miniWindowOptions = {
height: 64,
width: 64,
show: process.platform === 'linux',
frame: false,
fullscreenable: false,
skipTaskbar: true,
resizable: false,
transparent: process.platform !== 'linux',
icon: logo,
webPreferences: {
sandbox: false,
preload: preloadPath,
nodeIntegration: false,
contextIsolation: true,
backgroundThrottling: true,
nodeIntegrationInWorker: false
}
} as IBrowserWindowOptions
if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindowOptions.alwaysOnTop = true
}
const renameWindowOptions = {
height: 270,
width: 350,
show: true,
fullscreenable: false,
icon: logo,
resizable: true,
webPreferences: {
sandbox: false,
preload: preloadPath,
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
backgroundThrottling: false
}
} as IBrowserWindowOptions
if (process.platform !== 'darwin') {
renameWindowOptions.show = true
renameWindowOptions.backgroundColor = '#3f3c37'
renameWindowOptions.autoHideMenuBar = true
renameWindowOptions.transparent = false
}
const toolboxWindowOptions = {
height: 450,
width: 800,
show: false,
frame: true,
center: true,
fullscreenable: false,
resizable: false,
title: `PicList ${$t('TOOLBOX')}`,
backgroundColor: '#ebeef5',
icon: logo,
webPreferences: {
sandbox: false,
backgroundThrottling: true,
preload: preloadPath,
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
webSecurity: false
}
} as IBrowserWindowOptions
if (process.platform !== 'darwin') {
toolboxWindowOptions.backgroundColor = '#3f3c37'
toolboxWindowOptions.autoHideMenuBar = true
toolboxWindowOptions.transparent = false
}
windowList.set(IWindowList.TRAY_WINDOW, {
isValid: process.platform !== 'linux',
multiple: false,
options: () => trayWindowOptions,
callback(window) {
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
window.loadURL(process.env.ELECTRON_RENDERER_URL)
} else {
window.loadFile(path.join(__dirname, '../renderer/index.html'))
}
window.on('blur', () => {
window.hide()
})
}
})
windowList.set(IWindowList.SETTING_WINDOW, {
isValid: true,
multiple: false,
options: () => settingWindowOptions,
callback(window, windowManager) {
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#main-page/upload`)
} else {
window.loadFile(path.join(__dirname, '../renderer/index.html'), {
hash: 'main-page/upload'
})
}
window.on('closed', () => {
bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, false)
if (process.platform === 'linux') {
process.nextTick(() => {
app.quit()
})
}
})
bus.emit(CREATE_APP_MENU)
windowManager.create(IWindowList.MINI_WINDOW)
}
})
windowList.set(IWindowList.MINI_WINDOW, {
isValid: process.platform !== 'darwin',
multiple: false,
options: () => miniWindowOptions,
callback(window) {
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#mini-page`)
} else {
window.loadFile(path.join(__dirname, '../renderer/index.html'), {
hash: 'mini-page'
})
}
setMiniWindowShape(window)
}
})
windowList.set(IWindowList.RENAME_WINDOW, {
isValid: true,
multiple: true,
options: () => renameWindowOptions,
async callback(window, windowManager) {
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#rename-page`)
} else {
window.loadFile(path.join(__dirname, '../renderer/index.html'), {
hash: 'rename-page'
})
}
const currentWindow = windowManager.getAvailableWindow(true)
if (currentWindow && currentWindow.isVisible()) {
const { x, y, width, height } = currentWindow.getBounds()
const positionX = Math.floor(x + width / 2 - 150)
const positionY = Math.floor(y + height / 2 - (height > 400 ? 88 : 0))
window.setPosition(positionX, positionY, false)
}
}
})
windowList.set(IWindowList.TOOLBOX_WINDOW, {
isValid: true,
multiple: false,
options: () => toolboxWindowOptions,
async callback(window, windowManager) {
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#toolbox-page`)
} else {
window.loadFile(path.join(__dirname, '../renderer/index.html'), {
hash: 'toolbox-page'
})
}
const currentWindow = windowManager.getAvailableWindow(true)
if (currentWindow && currentWindow.isVisible()) {
const { x, y, width, height } = currentWindow.getBounds()
const positionX = Math.floor(x + width / 2 - 400)
const positionY = Math.floor(y + height / 2 - (height > 400 ? 225 : 0))
window.setPosition(positionX, positionY, false)
}
}
})
export default windowList

View File

@@ -5,10 +5,10 @@ import type { IWindowListItem, IWindowManager } from '#/types/electron'
import { IWindowList } from '~/utils/enum'
class WindowManager implements IWindowManager {
#windowMap: Map< string, BrowserWindow> = new Map()
#windowMap: Map<string, BrowserWindow> = new Map()
#windowIdMap: Map<number, string> = new Map()
create (name: string) {
create(name: string) {
const windowConfig: IWindowListItem = windowList.get(name)!
if (!windowConfig.isValid) return null
@@ -30,14 +30,14 @@ class WindowManager implements IWindowManager {
return window
}
get (name: string) {
get(name: string) {
if (this.has(name)) {
return this.#windowMap.get(name)!
}
return this.create(name)
}
has (name: string) {
has(name: string) {
return this.#windowMap.has(name)
}
@@ -49,7 +49,7 @@ class WindowManager implements IWindowManager {
}
}
getAvailableWindow (isSkipMiniWindow = false) {
getAvailableWindow(isSkipMiniWindow = false) {
const miniWindow = this.#windowMap.get(IWindowList.MINI_WINDOW)
if (miniWindow && miniWindow.isVisible() && !isSkipMiniWindow) {
return miniWindow

View File

@@ -1,31 +1,31 @@
import { EventEmitter } from 'node:events'
class OptimizedBus extends EventEmitter {
constructor () {
super()
this.setMaxListeners(50)
}
once (event: string | symbol, listener: (...args: any[]) => void): this {
const wrappedListener = (...args: any[]) => {
try {
listener(...args)
} finally {
this.removeListener(event, wrappedListener)
}
}
return super.once(event, wrappedListener)
}
cleanupListeners () {
const events = this.eventNames()
events.forEach(event => {
const listenerCount = this.listenerCount(event)
console.log(` listener count (${listenerCount}) for event: ${String(event)}`)
})
}
}
const bus = new OptimizedBus()
export default bus
import { EventEmitter } from 'node:events'
class OptimizedBus extends EventEmitter {
constructor() {
super()
this.setMaxListeners(50)
}
once(event: string | symbol, listener: (...args: any[]) => void): this {
const wrappedListener = (...args: any[]) => {
try {
listener(...args)
} finally {
this.removeListener(event, wrappedListener)
}
}
return super.once(event, wrappedListener)
}
cleanupListeners() {
const events = this.eventNames()
events.forEach(event => {
const listenerCount = this.listenerCount(event)
console.log(` listener count (${listenerCount}) for event: ${String(event)}`)
})
}
}
const bus = new OptimizedBus()
export default bus

View File

@@ -23,7 +23,7 @@ const errorMsg = {
brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP')
}
function dbChecker () {
function dbChecker() {
if (process.type !== 'renderer') {
// db save bak
try {
@@ -80,7 +80,7 @@ function dbChecker () {
/**
* Get config path
*/
function dbPathChecker (): string {
function dbPathChecker(): string {
if (_configFilePath) {
return _configFilePath
}
@@ -120,11 +120,11 @@ function dbPathChecker (): string {
}
}
function dbPathDir () {
function dbPathDir() {
return path.dirname(dbPathChecker())
}
function getGalleryDBPath (): {
function getGalleryDBPath(): {
dbPath: string
dbBackupPath: string
} {

View File

@@ -19,7 +19,7 @@ export const DB_PATH: string = getGalleryDBPath().dbPath
class ConfigStore {
#db: JSONStore
constructor () {
constructor() {
this.#db = new JSONStore(CONFIG_PATH)
if (!this.#db.has('picBed')) {
@@ -43,11 +43,11 @@ class ConfigStore {
this.read()
}
read (flush?: boolean): IJSON {
read(flush?: boolean): IJSON {
return this.#db.read(flush)
}
getSingle (key = ''): any {
getSingle(key = ''): any {
if (key === '') {
return this.#db.read(true)
}
@@ -55,43 +55,43 @@ class ConfigStore {
return this.#db.get(key)
}
get (key: string): any
get (key: string[]): any[]
get (key: string | string[] = ''): any {
get(key: string): any
get(key: string[]): any[]
get(key: string | string[] = ''): any {
if (Array.isArray(key)) {
return key.map(k => this.getSingle(k))
}
return this.getSingle(key)
}
set (key: string, value: any): void {
set(key: string, value: any): void {
this.read(true)
return this.#db.set(key, value)
}
has (key: string) {
has(key: string) {
this.read(true)
return this.#db.has(key)
}
unset (key: string, value: any): boolean {
unset(key: string, value: any): boolean {
this.read(true)
return this.#db.unset(key, value)
}
saveConfig (config: Partial<IConfig>): void {
saveConfig(config: Partial<IConfig>): void {
Object.keys(config).forEach((name: string) => {
this.set(name, config[name])
})
}
removeConfig (config: IConfig): void {
removeConfig(config: IConfig): void {
Object.keys(config).forEach((name: string) => {
this.unset(name, config[name])
})
}
getConfigPath () {
getConfigPath() {
return CONFIG_PATH
}
}
@@ -103,11 +103,11 @@ export default db
// v2.3.0 add gallery db
class GalleryDB {
static #instance: DBStore
private constructor () {
private constructor() {
console.log('init gallery db')
}
static getInstance (): DBStore {
static getInstance(): DBStore {
if (!GalleryDB.#instance) {
GalleryDB.#instance = new DBStore(DB_PATH, 'gallery')
}

View File

@@ -21,7 +21,7 @@ picgo.GUI_VERSION = pkg.version
const originPicGoSaveConfig = picgo.saveConfig.bind(picgo)
function flushDB () {
function flushDB() {
db.read(true)
}

View File

@@ -15,7 +15,7 @@ interface IConfigMap {
}
export default class AlistApi {
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const { fileName, config } = configMap
try {
const { version, url, uploadPath, token } = config

View File

@@ -26,7 +26,7 @@ const getAListToken = async (url: string, username: string, password: string) =>
}
export default class AListplistApi {
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const { fileName, config } = configMap
try {
const { url, username, password, uploadPath } = config

View File

@@ -9,11 +9,11 @@ interface IConfigMap {
}
export default class AliyunApi {
static #getKey (fileName: string, path?: string): string {
static #getKey(fileName: string, path?: string): string {
return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${fileName}` : fileName
}
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const { fileName, config } = configMap
try {
const client = new OSS({ ...config, region: config.area })

View File

@@ -39,7 +39,7 @@ const apiMap: IStringKeyMap = {
}
export default class ALLApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
static async delete(configMap: IStringKeyMap): Promise<boolean> {
const api = apiMap[configMap.type]
return api ? await api.delete(configMap) : false
}

View File

@@ -4,7 +4,7 @@ import { removeFileFromS3InMain } from '~/utils/deleteFunc'
import { deleteFailedLog } from '~/utils/deleteLog'
export default class AwsS3Api {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
static async delete(configMap: IStringKeyMap): Promise<boolean> {
try {
return await removeFileFromS3InMain(getRawData(configMap))
} catch (error: any) {

View File

@@ -4,7 +4,7 @@ import { removeFileFromDogeInMain } from '~/utils/deleteFunc'
import { deleteFailedLog } from '~/utils/deleteLog'
export default class AwsS3Api {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
static async delete(configMap: IStringKeyMap): Promise<boolean> {
try {
return await removeFileFromDogeInMain(getRawData(configMap))
} catch (error: any) {

View File

@@ -10,18 +10,18 @@ interface IConfigMap {
}
export default class GithubApi {
static #createOctokit (token: string) {
static #createOctokit(token: string) {
return new Octokit({
auth: token
})
}
static #createKey (path: string | undefined, fileName: string): string {
static #createKey(path: string | undefined, fileName: string): string {
const formatedFileName = fileName.replace(/%2F/g, '/')
return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${formatedFileName}` : formatedFileName
}
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const {
fileName,
hash,

View File

@@ -4,7 +4,7 @@ import { removeFileFromHuaweiInMain } from '~/utils/deleteFunc'
import { deleteFailedLog } from '~/utils/deleteLog'
export default class HuaweicloudApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
static async delete(configMap: IStringKeyMap): Promise<boolean> {
try {
return await removeFileFromHuaweiInMain(getRawData(configMap))
} catch (error: any) {

View File

@@ -11,7 +11,7 @@ interface IConfigMap {
export default class ImgurApi {
static #baseUrl = 'https://api.imgur.com/3'
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const { config: { clientId = '', username = '', accessToken = '' } = {}, hash = '' } = configMap
let Authorization: string, apiUrl: string

View File

@@ -7,7 +7,7 @@ interface IConfigMap {
}
export default class LocalApi {
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const { hash } = configMap
if (!hash) {
deleteLog(hash, 'Local', false, 'Local.delete: invalid params')

View File

@@ -6,7 +6,7 @@ import type { IStringKeyMap } from '#/types/types'
import { deleteFailedLog, deleteLog } from '~/utils/deleteLog'
export default class LskyplistApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
static async delete(configMap: IStringKeyMap): Promise<boolean> {
const { hash, config } = configMap
if (!hash || !config || !config.token) {
deleteLog(hash, 'Lskyplist', false, 'LskyplistApi.delete: invalid params')

View File

@@ -4,7 +4,7 @@ import type { IStringKeyMap } from '#/types/types'
import { deleteFailedLog, deleteLog } from '~/utils/deleteLog'
export default class PiclistApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
static async delete(configMap: IStringKeyMap): Promise<boolean> {
const { config, fullResult } = configMap
const { host, port } = config
if (!fullResult) return true

View File

@@ -8,7 +8,7 @@ interface IConfigMap {
}
export default class QiniuApi {
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const {
fileName,
config: { accessKey, secretKey, bucket, path }

View File

@@ -4,7 +4,7 @@ import { removeFileFromSFTPInMain } from '~/utils/deleteFunc'
import { deleteFailedLog } from '~/utils/deleteLog'
export default class SftpPlistApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
static async delete(configMap: IStringKeyMap): Promise<boolean> {
const { fileName, config } = configMap
try {
return await removeFileFromSFTPInMain(getRawData(config), fileName)

View File

@@ -11,7 +11,7 @@ interface IConfigMap {
export default class SmmsApi {
static readonly #baseUrl = 'https://smms.app/api/v2'
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const { hash, config } = configMap
if (!hash || !config || !config.token) {
deleteLog(hash, 'Smms', false, 'SmmsApi.delete: invalid params')

View File

@@ -7,14 +7,14 @@ interface IConfigMap {
config: PartialKeys<ITcYunConfig, 'path'>
}
export default class TcyunApi {
static #createCOS (SecretId: string, SecretKey: string): COS {
static #createCOS(SecretId: string, SecretKey: string): COS {
return new COS({
SecretId,
SecretKey
})
}
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const {
fileName,
config: { secretId, secretKey, bucket, area, path }

View File

@@ -9,7 +9,7 @@ interface IConfigMap {
}
export default class UpyunApi {
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const {
fileName,
config: { bucket, operator, password, path }

View File

@@ -10,7 +10,7 @@ interface IConfigMap {
}
export default class WebdavApi {
static async delete (configMap: IConfigMap): Promise<boolean> {
static async delete(configMap: IConfigMap): Promise<boolean> {
const {
fileName,
config: { host, username, password, path, sslEnabled, authType }

View File

@@ -8,7 +8,16 @@ import { BrowserWindow, dialog, ipcMain, IpcMainEvent, MessageBoxOptions, Notifi
import fs from 'fs-extra'
import { cloneDeep } from 'lodash-es'
import type { IGuiApi, ImgInfo, IShowFileExplorerOption, IShowInputBoxOption, IShowMessageBoxOption, IShowMessageBoxResult, IShowNotificationOption, IUploadOption } from '#/types/types'
import type {
IGuiApi,
ImgInfo,
IShowFileExplorerOption,
IShowInputBoxOption,
IShowMessageBoxOption,
IShowMessageBoxResult,
IShowNotificationOption,
IUploadOption
} from '#/types/types'
import { SHOW_INPUT_BOX } from '~/events/constant'
import { T as $t } from '~/i18n'
import { handleCopyUrl } from '~/utils/common'
@@ -21,18 +30,18 @@ class GuiApi implements IGuiApi {
private static instance: GuiApi
private windowId: number = -1
private settingWindowId: number = -1
private constructor () {
private constructor() {
console.log('init guiapi')
}
static getInstance (): GuiApi {
static getInstance(): GuiApi {
if (!GuiApi.instance) {
GuiApi.instance = new GuiApi()
}
return GuiApi.instance
}
private async showSettingWindow () {
private async showSettingWindow() {
this.settingWindowId = await getSettingWindowId()
const settingWindow = BrowserWindow.fromId(this.settingWindowId)
if (settingWindow?.isVisible()) {
@@ -46,11 +55,11 @@ class GuiApi implements IGuiApi {
})
}
private getWebcontentsByWindowId (id: number) {
private getWebcontentsByWindowId(id: number) {
return BrowserWindow.fromId(id)?.webContents
}
async showInputBox (
async showInputBox(
options: IShowInputBoxOption = {
title: '',
placeholder: ''
@@ -65,13 +74,13 @@ class GuiApi implements IGuiApi {
})
}
async showFileExplorer (options: IShowFileExplorerOption = {}) {
async showFileExplorer(options: IShowFileExplorerOption = {}) {
this.windowId = await getWindowId()
const res = await dialog.showOpenDialog(BrowserWindow.fromId(this.windowId)!, options)
return res.filePaths || []
}
async upload (input: IUploadOption) {
async upload(input: IUploadOption) {
this.windowId = await getWindowId()
const webContents = this.getWebcontentsByWindowId(this.windowId)
const rawInput = cloneDeep(input)
@@ -122,7 +131,7 @@ class GuiApi implements IGuiApi {
return []
}
showNotification (
showNotification(
options: IShowNotificationOption = {
title: '',
body: ''
@@ -135,7 +144,7 @@ class GuiApi implements IGuiApi {
notification.show()
}
showMessageBox (
showMessageBox(
options: IShowMessageBoxOption = {
title: '',
message: '',
@@ -159,7 +168,7 @@ class GuiApi implements IGuiApi {
/**
* get picgo config/data path
*/
async getConfigPath () {
async getConfigPath() {
const currentConfigPath = dbPathChecker()
const galleryDBPath = getGalleryDBPath().dbPath
return {
@@ -169,12 +178,12 @@ class GuiApi implements IGuiApi {
}
}
get galleryDB (): DBStore {
get galleryDB(): DBStore {
return new Proxy<DBStore>(GalleryDB.getInstance(), {
get (target, prop: keyof DBStore) {
get(target, prop: keyof DBStore) {
if (prop === 'overwrite') {
return new Proxy(GalleryDB.getInstance().overwrite, {
apply (target, ctx, args) {
apply(target, ctx, args) {
return new Promise(resolve => {
const guiApi = GuiApi.getInstance()
guiApi
@@ -197,7 +206,7 @@ class GuiApi implements IGuiApi {
}
if (prop === 'removeById') {
return new Proxy(GalleryDB.getInstance().removeById, {
apply (target, ctx, args) {
apply(target, ctx, args) {
return new Promise(resolve => {
const guiApi = GuiApi.getInstance()
guiApi