diff --git a/CHANGELOG.md b/CHANGELOG.md index f48d857..0ed305d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +## :tada: 2.9.3 (2024-08-22) + + +### :sparkles: Features + +* **custom:** add advanced picbed manual link ([26149ad](https://github.com/Kuingsmile/piclist/commit/26149ad)) +* **custom:** remove some dev output ([a046b40](https://github.com/Kuingsmile/piclist/commit/a046b40)) +* **custom:** support avif picture preview ([630eb03](https://github.com/Kuingsmile/piclist/commit/630eb03)) +* **custom:** support secondary picbed upload ([8962a46](https://github.com/Kuingsmile/piclist/commit/8962a46)), closes [#226](https://github.com/Kuingsmile/piclist/issues/226) + + +### :bug: Bug Fixes + +* **custom:** fix piclist picbed bugs ([893da24](https://github.com/Kuingsmile/piclist/commit/893da24)), closes [#236](https://github.com/Kuingsmile/piclist/issues/236) +* **custom:** fix type error ([6bf6d6b](https://github.com/Kuingsmile/piclist/commit/6bf6d6b)) + + +### :pencil: Documentation + +* **custom:** prepare for new version ([0007d9a](https://github.com/Kuingsmile/piclist/commit/0007d9a)) + + + ## :tada: 2.9.2 (2024-07-30) diff --git a/currentVersion.md b/currentVersion.md index 4125299..d441ae5 100644 --- a/currentVersion.md +++ b/currentVersion.md @@ -1,5 +1,9 @@ ### ✨ Features -- 新增高级自定义图床 -- 相册页面现在加载图片时会显示loading图 -- 优化了相册页面的加载速度 \ No newline at end of file +- 新增第二图床上传支持 +- 现在管理页面支持预览avif图片 +- 调整了图床配置页面的日期显示格式 + +### 🐛 Bug Fixes + +- 修复了PicList图床对core版的兼容性问题 diff --git a/currentVersion_en.md b/currentVersion_en.md index 54f08f3..23edb93 100644 --- a/currentVersion_en.md +++ b/currentVersion_en.md @@ -1,5 +1,9 @@ ### ✨ Features -- Add advanced custom image bed -- The album page now displays a loading image when loading pictures -- Optimized the loading speed of the album page +- Added support for the second image bed upload +- Now the management page supports previewing avif images +- Adjusted the date display format on the image bed configuration page + +### 🐛 Bug Fixes + +- Fixed the compatibility issue of PicList image bed with the core version \ No newline at end of file diff --git a/package.json b/package.json index b47f24e..3da93ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "piclist", - "version": "2.9.2", + "version": "2.9.3", "author": { "name": "Kuingsmile", "email": "pkukuing@gmail.com" @@ -67,7 +67,7 @@ "multer": "^1.4.5-lts.1", "node-ssh-no-cpu-features": "^2.0.0", "nodejs-file-downloader": "^4.12.1", - "piclist": "^1.9.1", + "piclist": "^1.9.3", "pinia": "^2.1.7", "pinia-plugin-persistedstate": "^3.2.1", "proxy-agent": "^5.0.0", @@ -97,7 +97,7 @@ "@types/lowdb": "^1.0.15", "@types/mime-types": "^2.1.4", "@types/multer": "^1.4.11", - "@types/node": "^16.10.2", + "@types/node": "^22.0.0", "@types/semver": "^7.5.6", "@types/tunnel": "^0.0.7", "@types/upyun": "^3.4.3", diff --git a/public/i18n/en.yml b/public/i18n/en.yml index 38f9735..888250a 100644 --- a/public/i18n/en.yml +++ b/public/i18n/en.yml @@ -25,6 +25,7 @@ NO_MORE_NOTICE: No More Notice SHOW_DEVTOOLS: Show Devtools FEEDBACK: Feedback CURRENT_PICBED: Current Picbed +CURRENT_SECOND_PICBED: Current Second Picbed START_WATCH_CLIPBOARD: Start Watch Clipboard STOP_WATCH_CLIPBOARD: Stop Watch Clipboard OPEN_TOOLBOX: Open Toolbox @@ -183,6 +184,8 @@ SETTINGS_TIMESTAMP_RENAME: Timestamp Rename SETTINGS_ADVANCED_RENAME: Advanced Rename SETTINGS_ADVANCED_RENAME_ENABLE: Enable Advanced Rename SETTINGS_ADVANCED_RENAME_FORMAT: Advanced Rename Format +SETTINGS_ENABLE_SECOND_PICBED: Enable Second Picbed +SETTINGS_SET_SECOND_PICBED: Set Second Picbed SETTINGS_OPEN_UPLOAD_TIPS: Open Upload Tips SETTINGS_OPEN_UPLOAD_RESULT_TIPS: Open Upload Result Tips SETTINGS_MINI_WINDOW_ON_TOP: Mini Window On Top diff --git a/public/i18n/zh-CN.yml b/public/i18n/zh-CN.yml index e27cb18..e60931a 100644 --- a/public/i18n/zh-CN.yml +++ b/public/i18n/zh-CN.yml @@ -25,6 +25,7 @@ NO_MORE_NOTICE: 以后不再提醒 SHOW_DEVTOOLS: 打开开发者工具 FEEDBACK: 反馈问题 CURRENT_PICBED: 当前图床 +CURRENT_SECOND_PICBED: 当前第二图床 START_WATCH_CLIPBOARD: 开始监听剪贴板 STOP_WATCH_CLIPBOARD: 停止监听剪贴板 OPEN_TOOLBOX: 打开修复工具箱 @@ -185,6 +186,8 @@ SETTINGS_TIMESTAMP_RENAME: 时间戳重命名 SETTINGS_ADVANCED_RENAME: 高级重命名 SETTINGS_ADVANCED_RENAME_ENABLE: 开启高级重命名 SETTINGS_ADVANCED_RENAME_FORMAT: 重命名格式 +SETTINGS_ENABLE_SECOND_PICBED: 启用第二图床同步上传 +SETTINGS_SET_SECOND_PICBED: 设置第二图床 SETTINGS_OPEN_UPLOAD_TIPS: 开启上传进度提示 SETTINGS_OPEN_UPLOAD_RESULT_TIPS: 开启上传结果提示 SETTINGS_MINI_WINDOW_ON_TOP: Mini窗口置顶 diff --git a/public/i18n/zh-TW.yml b/public/i18n/zh-TW.yml index a58d687..1c88f00 100644 --- a/public/i18n/zh-TW.yml +++ b/public/i18n/zh-TW.yml @@ -25,6 +25,7 @@ NO_MORE_NOTICE: 以後不再提醒 SHOW_DEVTOOLS: 開啟開發者工具 FEEDBACK: 問題反饋 CURRENT_PICBED: 當前圖床 +CURRENT_SECOND_PICBED: 當前第二圖床 START_WATCH_CLIPBOARD: 開始監聽剪貼簿 STOP_WATCH_CLIPBOARD: 停止監聽剪貼簿 OPEN_TOOLBOX: 開啟修復工具箱 @@ -183,6 +184,8 @@ SETTINGS_TIMESTAMP_RENAME: 以時間戳命名 SETTINGS_ADVANCED_RENAME: 高級命名 SETTINGS_ADVANCED_RENAME_ENABLE: 啟用高級命名 SETTINGS_ADVANCED_RENAME_FORMAT: 高級命名格式 +SETTINGS_ENABLE_SECOND_PICBED: 啟用第二圖床同步上傳 +SETTINGS_SET_SECOND_PICBED: 設定第二圖床 SETTINGS_OPEN_UPLOAD_TIPS: 開啟上傳提示 SETTINGS_OPEN_UPLOAD_RESULT_TIPS: 開啟上傳結果提示 SETTINGS_MINI_WINDOW_ON_TOP: Mini視窗置頂 diff --git a/src/main/apis/app/system/index.ts b/src/main/apis/app/system/index.ts index 5454f71..bc3b2a3 100644 --- a/src/main/apis/app/system/index.ts +++ b/src/main/apis/app/system/index.ts @@ -16,7 +16,7 @@ import db, { GalleryDB } from '@core/datastore' import picgo from '@core/picgo' import uploader from 'apis/app/uploader' -import { uploadClipboardFiles } from 'apis/app/uploader/apis' +import { handleSecondaryUpload, uploadClipboardFiles } from 'apis/app/uploader/apis' import windowManager from 'apis/app/window/windowManager' import { buildPicBedListMenu } from '~/events/remotes/menu' @@ -309,6 +309,7 @@ export function createTray(tooltip: string) { const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN const rawInput = cloneDeep(files) const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)! + await handleSecondaryUpload(trayWindow.webContents, files, 'tray') const imgs = await uploader.setWebContents(trayWindow.webContents).upload(files) const deleteLocalFile = db.get(configPaths.settings.deleteLocalFile) || false if (imgs !== false) { diff --git a/src/main/apis/app/uploader/apis.ts b/src/main/apis/app/uploader/apis.ts index a8a4ac8..59b5764 100644 --- a/src/main/apis/app/uploader/apis.ts +++ b/src/main/apis/app/uploader/apis.ts @@ -14,6 +14,7 @@ import pasteTemplate from '~/utils/pasteTemplate' import { IPasteStyle, IWindowList } from '#/types/enum' import { configPaths } from '#/utils/configPaths' +import { changeCurrentUploader } from '~/utils/handleUploaderConfig' const handleClipboardUploading = async (): Promise => { const useBuiltinClipboard = @@ -28,6 +29,7 @@ const handleClipboardUploading = async (): Promise => { } export const uploadClipboardFiles = async (): Promise => { + await handleSecondaryUpload(undefined, undefined, 'clipboard') const img = await handleClipboardUploading() if (img !== false) { if (img.length > 0) { @@ -84,6 +86,7 @@ export const uploadChoosedFiles = async ( ): Promise => { const input = files.map(item => item.path) const rawInput = cloneDeep(input) + await handleSecondaryUpload(webContents, input) const imgs = await uploader.setWebContents(webContents).upload(input) const result = [] if (imgs !== false) { @@ -132,3 +135,65 @@ export const uploadChoosedFiles = async ( return [] } } + +export const handleSecondaryUpload = async ( + webContents?: WebContents, + input?: string[], + uploadType: 'clipboard' | 'file' | 'tray' = 'file' +): Promise => { + const enableSecondUploader = db.get(configPaths.settings.enableSecondUploader) || false + let currentPicBedType = '' + let currentPicBedConfig = {} as IStringKeyMap + let currentPicBedConfigId = '' + let needRestore = 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') { + secondImgs = await handleClipboardUploading() + } else { + secondImgs = await uploader.setWebContents(webContents!).upload(input) + } + 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 (let i = 0; i < secondImgs.length; i++) { + await GalleryDB.getInstance().insert(secondImgs[i]) + } + 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) + } +} diff --git a/src/main/apis/app/window/windowList.ts b/src/main/apis/app/window/windowList.ts index 6c7688c..9f3febc 100644 --- a/src/main/apis/app/window/windowList.ts +++ b/src/main/apis/app/window/windowList.ts @@ -233,19 +233,9 @@ windowList.set(IWindowList.RENAME_WINDOW, { window.loadURL(handleWindowParams(RENAME_WINDOW_URL)) const currentWindow = windowManager.getAvailableWindow(true) if (currentWindow && currentWindow.isVisible()) { - // bounds: { x: 821, y: 75, width: 800, height: 450 } - const bounds = currentWindow.getBounds() - let positionX = bounds.x + bounds.width / 2 - 150 - let positionY - // if is the settingWindow - if (bounds.height > 400) { - positionY = bounds.y + bounds.height / 2 - 88 - } else { - // if is the miniWindow - positionY = bounds.y + bounds.height / 2 - } - positionX = Math.floor(positionX) - positionY = Math.floor(positionY) + 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) } } @@ -259,16 +249,9 @@ windowList.set(IWindowList.TOOLBOX_WINDOW, { window.loadURL(TOOLBOX_WINDOW_URL) const currentWindow = windowManager.getAvailableWindow(true) if (currentWindow && currentWindow.isVisible()) { - const bounds = currentWindow.getBounds() - let positionX = bounds.x + bounds.width / 2 - 400 - let positionY - if (bounds.height > 400) { - positionY = bounds.y + bounds.height / 2 - 225 - } else { - positionY = bounds.y + bounds.height / 2 - } - positionX = Math.floor(positionX) - positionY = Math.floor(positionY) + 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) } } diff --git a/src/main/apis/app/window/windowManager.ts b/src/main/apis/app/window/windowManager.ts index 0ec2cc0..960eae6 100644 --- a/src/main/apis/app/window/windowManager.ts +++ b/src/main/apis/app/window/windowManager.ts @@ -9,36 +9,31 @@ class WindowManager implements IWindowManager { create(name: IWindowList) { const windowConfig: IWindowListItem = windowList.get(name)! - if (windowConfig.isValid) { - if (!windowConfig.multiple) { - if (this.has(name)) return this.#windowMap.get(name)! - } - const window = new BrowserWindow(windowConfig.options()) - const id = window.id - if (windowConfig.multiple) { - this.#windowMap.set(`${name}_${window.id}`, window) - this.#windowIdMap.set(window.id, `${name}_${window.id}`) - } else { - this.#windowMap.set(name, window) - this.#windowIdMap.set(window.id, name) - } - windowConfig.callback(window, this) - window.on('close', () => { - this.deleteById(id) - }) - return window - } else { - return null + if (!windowConfig.isValid) return null + + if (!windowConfig.multiple) { + if (this.has(name)) return this.#windowMap.get(name)! } + + const window = new BrowserWindow(windowConfig.options()) + const id = window.id + const windowName = windowConfig.multiple ? `${name}_${id}` : name + + this.#windowMap.set(windowName, window) + this.#windowIdMap.set(id, windowName) + + windowConfig.callback(window, this) + window.on('close', () => { + this.deleteById(id) + }) + return window } get(name: IWindowList) { if (this.has(name)) { return this.#windowMap.get(name)! - } else { - const window = this.create(name) - return window } + return this.create(name) } has(name: IWindowList) { @@ -57,11 +52,15 @@ class WindowManager implements IWindowManager { const miniWindow = this.#windowMap.get(IWindowList.MINI_WINDOW) if (miniWindow && miniWindow.isVisible() && !isSkipMiniWindow) { return miniWindow - } else { - const settingWindow = this.#windowMap.get(IWindowList.SETTING_WINDOW) - const trayWindow = this.#windowMap.get(IWindowList.TRAY_WINDOW) - return settingWindow || trayWindow || this.create(IWindowList.SETTING_WINDOW)! } + + const settingWindow = this.#windowMap.get(IWindowList.SETTING_WINDOW) + if (settingWindow) return settingWindow + + const trayWindow = this.#windowMap.get(IWindowList.TRAY_WINDOW) + if (trayWindow) return trayWindow + + return this.create(IWindowList.SETTING_WINDOW)! } } diff --git a/src/main/apis/gui/index.ts b/src/main/apis/gui/index.ts index 50991c1..25930bb 100644 --- a/src/main/apis/gui/index.ts +++ b/src/main/apis/gui/index.ts @@ -17,6 +17,7 @@ import pasteTemplate from '~/utils/pasteTemplate' import { SHOW_INPUT_BOX } from '#/events/constants' import { IPasteStyle } from '#/types/enum' import { configPaths } from '#/utils/configPaths' +import { handleSecondaryUpload } from '../app/uploader/apis' // Cross-process support may be required in the future class GuiApi implements IGuiApi { @@ -78,6 +79,7 @@ class GuiApi implements IGuiApi { this.windowId = await getWindowId() const webContents = this.getWebcontentsByWindowId(this.windowId) const rawInput = cloneDeep(input) + await handleSecondaryUpload(webContents!, input) const imgs = await uploader.setWebContents(webContents!).upload(input) if (imgs !== false) { const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN diff --git a/src/main/events/remotes/menu.ts b/src/main/events/remotes/menu.ts index a2558c8..c268c31 100644 --- a/src/main/events/remotes/menu.ts +++ b/src/main/events/remotes/menu.ts @@ -13,7 +13,7 @@ import { T } from '~/i18n' import clipboardPoll from '~/utils/clipboardPoll' import { setTrayToolTip } from '~/utils/common' import getPicBeds from '~/utils/getPicBeds' -import { changeCurrentUploader } from '~/utils/handleUploaderConfig' +import { changeCurrentUploader, changeSecondUploader } from '~/utils/handleUploaderConfig' import { PICGO_CONFIG_PLUGIN, @@ -139,6 +139,59 @@ const buildMainPageMenu = (win: BrowserWindow) => { return Menu.buildFromTemplate(template) } +const buildSecondPicBedMenu = () => { + const picBeds = getPicBeds() + const secondUploader = picgo.getConfig(configPaths.picBed.secondUploader) + const defaultSecondUploaderId = picgo.getConfig(configPaths.picBed.secondUploaderId) + const currentPicBedName = picBeds.find(item => item.type === secondUploader)?.name + const picBedConfigList = picgo.getConfig('uploader') + const currentPicBedMenuItem = [ + { + label: `${T('CURRENT_SECOND_PICBED')} - ${currentPicBedName || 'None'}`, + enabled: false + }, + { + type: 'separator' + } + ] + let submenu = picBeds + .filter(item => item.visible) + .map(item => { + const configList = picBedConfigList?.[item.type]?.configList + const hasSubmenu = !!configList + return { + label: item.name, + type: !hasSubmenu ? 'checkbox' : undefined, + checked: !hasSubmenu ? secondUploader === item.type : undefined, + submenu: hasSubmenu + ? configList.map(config => { + return { + label: config._configName || 'Default', + // if only one config, use checkbox, or radio will checked as default + // see: https://github.com/electron/electron/issues/21292 + type: 'checkbox', + checked: config._id === defaultSecondUploaderId && item.type === secondUploader, + click: function () { + changeSecondUploader(item.type, config, config._id) + } + } + }) + : undefined, + click: !hasSubmenu + ? function () { + picgo.saveConfig({ + [configPaths.picBed.secondUploader]: item.type + }) + } + : undefined + } + }) + // @ts-expect-error submenu type + submenu = currentPicBedMenuItem.concat(submenu) + // @ts-expect-error submenu type + return Menu.buildFromTemplate(submenu) +} + const buildPicBedListMenu = () => { const picBeds = getPicBeds() const currentPicBed = picgo.getConfig(configPaths.picBed.uploader) @@ -339,4 +392,4 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { return Menu.buildFromTemplate(menu) } -export { buildMiniPageMenu, buildMainPageMenu, buildPicBedListMenu, buildPluginPageMenu } +export { buildMiniPageMenu, buildMainPageMenu, buildPicBedListMenu, buildPluginPageMenu, buildSecondPicBedMenu } diff --git a/src/main/events/rpc/index.ts b/src/main/events/rpc/index.ts index 12bc314..abae4bb 100644 --- a/src/main/events/rpc/index.ts +++ b/src/main/events/rpc/index.ts @@ -15,17 +15,12 @@ import { manageRouter } from '~/events/rpc/routes/manage' import { IRPCActionType, IRPCType } from '#/types/enum' import { RPC_ACTIONS, RPC_ACTIONS_INVOKE } from '#/events/constants' -const isDevelopment = process.env.NODE_ENV !== 'production' - class RPCServer implements IRPCServer { private routes: IRPCRoutes = new Map() private routesWithResponse: IRPCRoutes = new Map() private rpcEventHandler = async (event: IpcMainEvent, action: IRPCActionType, args: any[]) => { try { - if (isDevelopment) { - console.log(`action: ${action} args: ${JSON.stringify(args)}`) - } const route = this.routes.get(action) await route?.handler?.(event, args) } catch (e: any) { @@ -35,9 +30,6 @@ class RPCServer implements IRPCServer { private rpcEventHandlerWithResponse = async (event: IpcMainInvokeEvent, action: IRPCActionType, args: any[]) => { try { - if (isDevelopment) { - console.log(`action: ${action} args: ${JSON.stringify(args)}`) - } const route = this.routesWithResponse.get(action) return await route?.handler?.(event, args) } catch (e: any) { diff --git a/src/main/events/rpc/routes/system/window.ts b/src/main/events/rpc/routes/system/window.ts index fe5f88a..dd9cd3c 100644 --- a/src/main/events/rpc/routes/system/window.ts +++ b/src/main/events/rpc/routes/system/window.ts @@ -2,7 +2,13 @@ import { app, BrowserWindow } from 'electron' import windowManager from 'apis/app/window/windowManager' -import { buildMainPageMenu, buildMiniPageMenu, buildPicBedListMenu, buildPluginPageMenu } from '~/events/remotes/menu' +import { + buildMainPageMenu, + buildMiniPageMenu, + buildPicBedListMenu, + buildPluginPageMenu, + buildSecondPicBedMenu +} from '~/events/remotes/menu' import { openMiniWindow } from '~/utils/windowHelper' import { IRPCActionType, IWindowList } from '#/types/enum' @@ -83,6 +89,16 @@ export default [ }) } }, + { + action: IRPCActionType.SHOW_SECOND_UPLOADER_MENU, + handler: async () => { + const window = windowManager.get(IWindowList.SETTING_WINDOW)! + const menu = buildSecondPicBedMenu() + menu.popup({ + window + }) + } + }, { action: IRPCActionType.SHOW_PLUGIN_PAGE_MENU, handler: async (_: IIPCEvent, args: [plugin: IPicGoPlugin]) => { diff --git a/src/main/utils/handleUploaderConfig.ts b/src/main/utils/handleUploaderConfig.ts index 07ad164..e9f919f 100644 --- a/src/main/utils/handleUploaderConfig.ts +++ b/src/main/utils/handleUploaderConfig.ts @@ -56,6 +56,25 @@ export const getPicBedConfig = (type: string) => { } } +export const changeSecondUploader = (type: string, config?: IStringKeyMap, id?: string) => { + if (!type) { + return + } + if (id) { + picgo.saveConfig({ + [configPaths.picBed.secondUploaderId]: id + }) + } + if (config) { + picgo.saveConfig({ + [configPaths.picBed.secondUploaderConfig]: config + }) + } + picgo.saveConfig({ + [configPaths.picBed.secondUploader]: type + }) +} + export const changeCurrentUploader = (type: string, config?: IStringKeyMap, id?: string) => { if (!type) { return diff --git a/src/renderer/apis/piclist.ts b/src/renderer/apis/piclist.ts index 221fe20..5d30b9e 100644 --- a/src/renderer/apis/piclist.ts +++ b/src/renderer/apis/piclist.ts @@ -6,6 +6,8 @@ export default class PiclistApi { static async delete(configMap: IStringKeyMap): Promise { const { config, fullResult } = configMap const { host, port } = config + if (!fullResult) return true + if (!host) { deleteLog(fullResult, 'Piclist', false, 'PiclistApi.delete: invalid params') return false diff --git a/src/renderer/manage/pages/BucketPage.vue b/src/renderer/manage/pages/BucketPage.vue index 853817d..bde0b40 100644 --- a/src/renderer/manage/pages/BucketPage.vue +++ b/src/renderer/manage/pages/BucketPage.vue @@ -1292,7 +1292,7 @@ const tableData = reactive([] as any[]) const isShowUploadPanel = ref(false) const activeUpLoadTab = ref('uploading') const uploadTaskList = ref([] as IUploadTask[]) -const refreshUploadTaskId = ref(null) +const refreshUploadTaskId = ref(undefined) const uploadPanelFilesList = ref([] as any[]) const cancelToken = ref('') const isLoadingUploadPanelFiles = ref(false) @@ -1309,7 +1309,7 @@ const isLoadingDownloadData = ref(false) const activeDownLoadTab = ref('downloading') const currentDownloadFileList = reactive([] as any[]) const downloadTaskList = ref([] as IDownloadTask[]) -const refreshDownloadTaskId = ref(null) +const refreshDownloadTaskId = ref(undefined) const downloadCancelToken = ref('') const downloadingTaskList = computed(() => downloadTaskList.value.filter(item => ['downloading', 'queuing', 'paused'].includes(item.status)) @@ -1365,8 +1365,8 @@ const batchRenameReplace = ref('') const isRenameIncludeExt = ref(false) const isSingleRename = ref(false) const itemToBeRenamed = ref({} as any) -let fileTransferInterval: NodeJS.Timer | null = null -let downloadInterval: NodeJS.Timer | null = null +let fileTransferInterval: NodeJS.Timeout | undefined +let downloadInterval: NodeJS.Timeout | undefined // 当前页面信息相关 const currentPicBedName = computed(() => manageStore.config.picBed[configMap.alias].picBedName) diff --git a/src/renderer/manage/pages/assets/icons/avif.webp b/src/renderer/manage/pages/assets/icons/avif.webp new file mode 100644 index 0000000..357472f Binary files /dev/null and b/src/renderer/manage/pages/assets/icons/avif.webp differ diff --git a/src/renderer/manage/utils/icon.ts b/src/renderer/manage/utils/icon.ts index cd47e91..880fc62 100644 --- a/src/renderer/manage/utils/icon.ts +++ b/src/renderer/manage/utils/icon.ts @@ -21,6 +21,7 @@ export const availableIconList = [ 'au', 'avc', 'avi', + 'avif', 'avs', 'bak', 'bas', diff --git a/src/renderer/pages/PicGoSetting.vue b/src/renderer/pages/PicGoSetting.vue index c79daab..eece303 100644 --- a/src/renderer/pages/PicGoSetting.vue +++ b/src/renderer/pages/PicGoSetting.vue @@ -215,6 +215,18 @@ + + + + + + {{ $T('SETTINGS_CLICK_TO_SET') }} + + ({ registry: '', proxy: '', mainWindowWidth: 1200, - mainWindowHeight: 800 + mainWindowHeight: 800, + enableSecondUploader: false }) const proxy = ref('') @@ -1080,7 +1093,8 @@ const autoWatchKeys = [ 'proxy', 'autoCopy', 'encodeOutputURL', - 'useShortUrl' + 'useShortUrl', + 'enableSecondUploader' ] const addWatch = () => { @@ -1259,6 +1273,10 @@ function initArray(arrayT: string | string[], defaultValue: string[]) { return arrayT } +async function handleChangeSecondPicBed() { + sendRPC(IRPCActionType.SHOW_SECOND_UPLOADER_MENU) +} + function openFile(file: string) { sendRPC(IRPCActionType.PICLIST_OPEN_FILE, file) } diff --git a/src/renderer/pages/UploaderConfigPage.vue b/src/renderer/pages/UploaderConfigPage.vue index 63753e2..65db622 100644 --- a/src/renderer/pages/UploaderConfigPage.vue +++ b/src/renderer/pages/UploaderConfigPage.vue @@ -80,13 +80,13 @@ import { saveConfig } from '@/utils/dataSender' import { T as $T } from '@/i18n/index' import { useStore } from '@/hooks/useStore' import { PICBEDS_PAGE, UPLOADER_CONFIG_PAGE } from '@/router/config' +import { sendRPC, triggerRPC } from '@/utils/common' import { IRPCActionType } from '#/types/enum' import { configPaths } from '#/utils/configPaths' -import { sendRPC, triggerRPC } from '@/utils/common' -const $router = useRouter() -const $route = useRoute() +const router = useRouter() +const route = useRoute() const type = ref('') const curConfigList = ref([]) @@ -113,7 +113,7 @@ onBeforeRouteUpdate((to, _, next) => { }) onBeforeMount(() => { - type.value = $route.params.type as string + type.value = route.params.type as string getCurrentConfigList() }) @@ -124,7 +124,7 @@ async function getCurrentConfigList() { } function openEditPage(configId: string) { - $router.push({ + router.push({ name: PICBEDS_PAGE, params: { type: type.value, @@ -137,7 +137,7 @@ function openEditPage(configId: string) { } function formatTime(time: number): string { - return dayjs(time).format('YY/MM/DD HH:mm') + return dayjs(time).format('YY-MM-DD HH:mm') } async function deleteConfig(id: string) { @@ -148,7 +148,7 @@ async function deleteConfig(id: string) { } function addNewConfig() { - $router.push({ + router.push({ name: PICBEDS_PAGE, params: { type: type.value, diff --git a/src/renderer/utils/common.ts b/src/renderer/utils/common.ts index 2a8a5e5..65c2ad5 100644 --- a/src/renderer/utils/common.ts +++ b/src/renderer/utils/common.ts @@ -4,19 +4,14 @@ import { isReactive, isRef, toRaw, unref } from 'vue' import { RPC_ACTIONS, RPC_ACTIONS_INVOKE } from '#/events/constants' import { IRPCActionType } from '#/types/enum' -const isDevelopment = process.env.NODE_ENV !== 'production' - export const handleTalkingDataEvent = (data: ITalkingDataOptions) => { - const { EventId, Label = '', MapKv = {} } = data - MapKv.from = window.location.href try { + const { EventId, Label = '', MapKv = {} } = data + MapKv.from = window.location.href window.TDAPP.onEvent(EventId, Label, MapKv) } catch (e) { console.error(e) } - if (isDevelopment) { - console.log('talkingData', data) - } } /** @@ -41,26 +36,14 @@ export function sendToMain(channel: string, ...args: any[]) { ipcRenderer.send(channel, ...data) } -/** - * send a rpc request & do not need to wait for the response - * - * or the response will be handled by other listener - */ export function sendRPC(action: IRPCActionType, ...args: any[]): void { - const data = getRawData(args) - ipcRenderer.send(RPC_ACTIONS, action, data) + ipcRenderer.send(RPC_ACTIONS, action, getRawData(args)) } export function sendRpcSync(action: IRPCActionType, ...args: any[]) { - const data = getRawData(args) - return ipcRenderer.sendSync(RPC_ACTIONS, action, data) + return ipcRenderer.sendSync(RPC_ACTIONS, action, getRawData(args)) } -/** - * trigger RPC action - * TODO: create an isolate rpc handler - */ export async function triggerRPC(action: IRPCActionType, ...args: any[]): Promise { - const data = getRawData(args) - return await ipcRenderer.invoke(RPC_ACTIONS_INVOKE, action, data) + return await ipcRenderer.invoke(RPC_ACTIONS_INVOKE, action, getRawData(args)) } diff --git a/src/universal/types/enum.ts b/src/universal/types/enum.ts index ba5e51a..d72c20a 100644 --- a/src/universal/types/enum.ts +++ b/src/universal/types/enum.ts @@ -96,6 +96,7 @@ export enum IRPCActionType { SHOW_MINI_PAGE_MENU = 'SHOW_MINI_PAGE_MENU', SHOW_MAIN_PAGE_MENU = 'SHOW_MAIN_PAGE_MENU', SHOW_UPLOAD_PAGE_MENU = 'SHOW_UPLOAD_PAGE_MENU', + SHOW_SECOND_UPLOADER_MENU = 'SHOW_SECOND_UPLOADER_MENU', SHOW_PLUGIN_PAGE_MENU = 'SHOW_PLUGIN_PAGE_MENU', SET_MINI_WINDOW_POS = 'SET_MINI_WINDOW_POS', MINI_WINDOW_ON_TOP = 'MINI_WINDOW_ON_TOP', diff --git a/src/universal/types/i18n.d.ts b/src/universal/types/i18n.d.ts index 506a714..a47561d 100644 --- a/src/universal/types/i18n.d.ts +++ b/src/universal/types/i18n.d.ts @@ -26,6 +26,7 @@ interface ILocales { SHOW_DEVTOOLS: string FEEDBACK: string CURRENT_PICBED: string + CURRENT_SECOND_PICBED: string START_WATCH_CLIPBOARD: string STOP_WATCH_CLIPBOARD: string OPEN_TOOLBOX: string @@ -178,6 +179,8 @@ interface ILocales { SETTINGS_ADVANCED_RENAME: string SETTINGS_ADVANCED_RENAME_ENABLE: string SETTINGS_ADVANCED_RENAME_FORMAT: string + SETTINGS_ENABLE_SECOND_PICBED: string + SETTINGS_SET_SECOND_PICBED: string SETTINGS_OPEN_UPLOAD_TIPS: string SETTINGS_OPEN_UPLOAD_RESULT_TIPS: string SETTINGS_MINI_WINDOW_ON_TOP: string diff --git a/src/universal/types/view.d.ts b/src/universal/types/view.d.ts index 5a09793..5ef4d13 100644 --- a/src/universal/types/view.d.ts +++ b/src/universal/types/view.d.ts @@ -1,58 +1,59 @@ -interface ISettingForm { - showUpdateTip: boolean - autoStart: boolean - rename: boolean - autoRename: boolean - uploadNotification: boolean - uploadResultNotification: boolean - miniWindowOntop: boolean - autoCloseMiniWindow: boolean - autoCloseMainWindow: boolean - logLevel: string[] - autoCopy: boolean - useBuiltinClipboard: boolean - logFileSizeLimit: number - deleteCloudFile: boolean - isCustomMiniIcon: boolean - customMiniIcon: string - isHideDock: boolean - autoImport: boolean - autoImportPicBed: string[] - encodeOutputURL: boolean - isAutoListenClipboard: boolean - useShortUrl: boolean - shortUrlServer: string - c1nToken: string - yourlsDomain: string - yourlsSignature: string - cfWorkerHost: string - deleteLocalFile: boolean - serverKey: string - aesPassword: string - enableWebServer: boolean - webServerHost: string - webServerPort: number - webServerPath: string - registry: string - proxy: string - mainWindowWidth: number - mainWindowHeight: number -} - -interface IShortKeyMap { - [propName: string]: string -} - -interface IToolboxItem { - title: string - status: import('#/types/enum').IToolboxItemCheckStatus - msg?: string - value?: any // for handler - hasNoFixMethod?: boolean - handler?: (value: any) => Promise | void - handlerText?: string -} - -type IToolboxMap = { - [id in import('#/types/enum').IToolboxItemType]: IToolboxItem -} +interface ISettingForm { + showUpdateTip: boolean + autoStart: boolean + rename: boolean + autoRename: boolean + uploadNotification: boolean + uploadResultNotification: boolean + miniWindowOntop: boolean + autoCloseMiniWindow: boolean + autoCloseMainWindow: boolean + logLevel: string[] + autoCopy: boolean + useBuiltinClipboard: boolean + logFileSizeLimit: number + deleteCloudFile: boolean + isCustomMiniIcon: boolean + customMiniIcon: string + isHideDock: boolean + autoImport: boolean + autoImportPicBed: string[] + encodeOutputURL: boolean + isAutoListenClipboard: boolean + useShortUrl: boolean + shortUrlServer: string + c1nToken: string + yourlsDomain: string + yourlsSignature: string + cfWorkerHost: string + deleteLocalFile: boolean + serverKey: string + aesPassword: string + enableWebServer: boolean + webServerHost: string + webServerPort: number + webServerPath: string + registry: string + proxy: string + mainWindowWidth: number + mainWindowHeight: number + enableSecondUploader: boolean +} + +interface IShortKeyMap { + [propName: string]: string +} + +interface IToolboxItem { + title: string + status: import('#/types/enum').IToolboxItemCheckStatus + msg?: string + value?: any // for handler + hasNoFixMethod?: boolean + handler?: (value: any) => Promise | void + handlerText?: string +} + +type IToolboxMap = { + [id in import('#/types/enum').IToolboxItemType]: IToolboxItem +} diff --git a/src/universal/utils/common.ts b/src/universal/utils/common.ts index 7559dbc..fe96ebf 100644 --- a/src/universal/utils/common.ts +++ b/src/universal/utils/common.ts @@ -66,14 +66,15 @@ export function encodeFilePath(filePath: string) { export const getExtension = (fileName: string) => path.extname(fileName).slice(1) export const isImage = (fileName: string) => - ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico', 'svg'].includes(getExtension(fileName)) + ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico', 'svg', 'avif'].includes(getExtension(fileName)) -export const formatEndpoint = (endpoint: string, sslEnabled: boolean): string => - !/^https?:\/\//.test(endpoint) - ? `${sslEnabled ? 'https' : 'http'}://${endpoint}` - : sslEnabled - ? endpoint.replace('http://', 'https://') - : endpoint.replace('https://', 'http://') +export const formatEndpoint = (endpoint: string, sslEnabled: boolean): string => { + const hasProtocol = /^https?:\/\//.test(endpoint) + if (!hasProtocol) { + return `${sslEnabled ? 'https' : 'http'}://${endpoint}` + } + return sslEnabled ? endpoint.replace(/^http:\/\//, 'https://') : endpoint.replace(/^https:\/\//, 'http://') +} export const trimPath = (path: string) => path.replace(/^\/+|\/+$/g, '').replace(/\/+/g, '/') diff --git a/src/universal/utils/configPaths.ts b/src/universal/utils/configPaths.ts index 7283016..64cbb9d 100644 --- a/src/universal/utils/configPaths.ts +++ b/src/universal/utils/configPaths.ts @@ -107,6 +107,9 @@ export const configPaths = { picBed: { current: 'picBed.current', uploader: 'picBed.uploader', + secondUploader: 'picBed.secondUploader', + secondUploaderId: 'picBed.secondUploaderId', + secondUploaderConfig: 'picBed.secondUploaderConfig', proxy: 'picBed.proxy', transformer: 'picBed.transformer', list: 'picBed.list' @@ -165,7 +168,8 @@ export const configPaths = { useBuiltinClipboard: 'settings.useBuiltinClipboard', autoStart: 'settings.autoStart', autoImport: 'settings.autoImport', - autoImportPicBed: 'settings.autoImportPicBed' + autoImportPicBed: 'settings.autoImportPicBed', + enableSecondUploader: 'settings.enableSecondUploader' }, needReload: 'needReload', picgoPlugins: 'picgoPlugins', diff --git a/src/universal/utils/static.ts b/src/universal/utils/static.ts index 0dbd624..ab392f8 100644 --- a/src/universal/utils/static.ts +++ b/src/universal/utils/static.ts @@ -31,6 +31,7 @@ export const picBedsCanbeDeleted = [ export const picBedManualUrlList: IStringKeyMap = { zh_cn: { + advancedpiclist: 'https://piclist.cn/configure.html#%E9%AB%98%E7%BA%A7%E8%87%AA%E5%AE%9A%E4%B9%89', aliyun: 'https://piclist.cn/configure.html#%E9%98%BF%E9%87%8C%E4%BA%91oss', alistplist: 'https://piclist.cn/configure.html#alist', 'aws-s3': 'https://piclist.cn/configure.html#%E5%86%85%E7%BD%AEaws-s3', @@ -51,6 +52,7 @@ export const picBedManualUrlList: IStringKeyMap = { webdavplist: 'https://piclist.cn/configure.html#webdav' }, en: { + advancedpiclist: 'https://piclist.cn/en/configure.html#advanced', aliyun: 'https://piclist.cn/en/configure.html#alibaba-cloud', alistplist: 'https://piclist.cn/en/configure.html#alist', 'aws-s3': 'https://piclist.cn/en/configure.html#built-in-aws-s3', diff --git a/supported_format.md b/supported_format.md index 0672d10..a95e301 100644 --- a/supported_format.md +++ b/supported_format.md @@ -1,53 +1,54 @@ -# 支持预览的文件格式列表 - -### 图片 - -| 格式 | 描述 | 格式 | 描述 | -| :-----------------------------------------------------: | :----------: | :-------------------------------------------------------------: | :----------------: | -| [.bmp](https://en.wikipedia.org/wiki/BMP_file_format) | 位图文件格式 | [.jpeg/.jpg](https://en.wikipedia.org/wiki/JPEG) | 联合照片专家组格式 | -| [.gif](https://en.wikipedia.org/wiki/GIF) | 图形交换格式 | [.png](https://en.wikipedia.org/wiki/Portable_Network_Graphics) | 可移植网络图形格式 | -| [.ico](https://en.wikipedia.org/wiki/ICO_(file_format)) | 图标文件格式 | [.webp](https://developers.google.com/speed/webp/) | WebP格式 | - -### 文本 - -| 格式 | 描述 | 格式 | 描述 | -| :------------: | :-----------------: | :---------------: | :----------------: | -| .bat | 批处理文件 | .java | Java源代码文件 | -| .c | C语言源代码文件 | .js | JavaScript文件 | -| .cmd | Windows命令脚本文件 | .json | JSON文件 | -| .conf | 配置文件 | .log | 日志文件 | -| .config | 配置文件 | .php | PHP源代码文件 | -| .cpp | C++源代码文件 | .prop/.properties | 属性文件 | -| .css | 层叠样式表文件 | .py | Python源代码文件 | -| .csv | 逗号分隔值文件 | .rc | Windows资源文件 | -| .dart | Dart源代码文件 | .sh | Shell脚本文件 | -| .gitattributes | Git属性文件 | .tsv | 制表符分隔值文件 | -| .gitconfig | Git配置文件 | .txt | 纯文本文件 | -| .gitignore | Git忽略文件 | .xml | XML文件 | -| .gitkeep | Git保留文件 | .yaml/.yml | YAML文件 | -| .gitmodules | Git子模块文件 | .yarnrc | Yarn配置文件 | -| .go | Go源代码文件 | LICENSE | 许可证文件 | -| .h | 头文件 | .condarc | Conda配置文件 | -| .hpp | C++头文件 | .md | Markdown文件 | -| .htm/.html | HTML文件 | .jsx/.tsx/.vue | JSX文件等 | -| .applescript | AppleScript脚本文件 | .eslintignore | ESLint忽略文件 | -| .lock | 锁文件 | .ps1 | PowerShell脚本文件 | - -### 视频 - -| 格式 | 描述 | 格式 | 描述 | -| :---: | :-------------------: | :---: | :-----------------------------: | -| .aac | AAC音频文件 | .mpeg | MPEG视频文件 | -| .amv | AMV视频文件 | .mpg | MPEG视频文件 | -| .avi | AVI视频文件 | .mts | AVCHD视频文件 | -| .flac | FLAC音频文件 | .ogg | Ogg Vorbis音频文件 | -| .flv | Flash视频文件 | .ogv | Ogg Theora视频文件 | -| .m2ts | M2TS视频文件 | .vob | DVD视频文件 | -| .m4a | MPEG-4音频文件 | .wav | WAV音频文件 | -| .m4v | MPEG-4视频文件 | .webm | WebM视频文件 | -| .mp3 | MP3音频文件 | .mp4 | MPEG-4视频文件 | -| .mov | QuickTime视频文件 | .3g2 | 3GPP2视频文件 | -| .mp4 | MPEG-4视频文件 | .3gp | 3GPP视频文件 | -| .mxf | MXF视频文件 | .asf | Advanced Systems Format视频文件 | -| .rm | RealMedia视频文件 | .rmvb | RealMedia可变比特率视频文件 | -| .wmv | Windows Media视频文件 | .mkv | Matroska视频文件 | +# 支持预览的文件格式列表 + +### 图片 + +| 格式 | 描述 | 格式 | 描述 | +| :---: | :----------: | :--------: | :----------------: | +| .bmp | 位图文件格式 | .jpeg/.jpg | 联合照片专家组格式 | +| .gif | 图形交换格式 | .png | 可移植网络图形格式 | +| .ico | 图标文件格式 | .webp | WebP格式 | +| .svg | 可缩放矢量图 | .avif | AVIF格式 | + +### 文本 + +| 格式 | 描述 | 格式 | 描述 | +| :------------: | :-----------------: | :---------------: | :----------------: | +| .bat | 批处理文件 | .java | Java源代码文件 | +| .c | C语言源代码文件 | .js | JavaScript文件 | +| .cmd | Windows命令脚本文件 | .json | JSON文件 | +| .conf | 配置文件 | .log | 日志文件 | +| .config | 配置文件 | .php | PHP源代码文件 | +| .cpp | C++源代码文件 | .prop/.properties | 属性文件 | +| .css | 层叠样式表文件 | .py | Python源代码文件 | +| .csv | 逗号分隔值文件 | .rc | Windows资源文件 | +| .dart | Dart源代码文件 | .sh | Shell脚本文件 | +| .gitattributes | Git属性文件 | .tsv | 制表符分隔值文件 | +| .gitconfig | Git配置文件 | .txt | 纯文本文件 | +| .gitignore | Git忽略文件 | .xml | XML文件 | +| .gitkeep | Git保留文件 | .yaml/.yml | YAML文件 | +| .gitmodules | Git子模块文件 | .yarnrc | Yarn配置文件 | +| .go | Go源代码文件 | LICENSE | 许可证文件 | +| .h | 头文件 | .condarc | Conda配置文件 | +| .hpp | C++头文件 | .md | Markdown文件 | +| .htm/.html | HTML文件 | .jsx/.tsx/.vue | JSX文件等 | +| .applescript | AppleScript脚本文件 | .eslintignore | ESLint忽略文件 | +| .lock | 锁文件 | .ps1 | PowerShell脚本文件 | + +### 视频 + +| 格式 | 描述 | 格式 | 描述 | +| :---: | :-------------------: | :---: | :-----------------------------: | +| .aac | AAC音频文件 | .mpeg | MPEG视频文件 | +| .amv | AMV视频文件 | .mpg | MPEG视频文件 | +| .avi | AVI视频文件 | .mts | AVCHD视频文件 | +| .flac | FLAC音频文件 | .ogg | Ogg Vorbis音频文件 | +| .flv | Flash视频文件 | .ogv | Ogg Theora视频文件 | +| .m2ts | M2TS视频文件 | .vob | DVD视频文件 | +| .m4a | MPEG-4音频文件 | .wav | WAV音频文件 | +| .m4v | MPEG-4视频文件 | .webm | WebM视频文件 | +| .mp3 | MP3音频文件 | .mp4 | MPEG-4视频文件 | +| .mov | QuickTime视频文件 | .3g2 | 3GPP2视频文件 | +| .mp4 | MPEG-4视频文件 | .3gp | 3GPP视频文件 | +| .mxf | MXF视频文件 | .asf | Advanced Systems Format视频文件 | +| .rm | RealMedia视频文件 | .rmvb | RealMedia可变比特率视频文件 | +| .wmv | Windows Media视频文件 | .mkv | Matroska视频文件 | diff --git a/yarn.lock b/yarn.lock index 8856f7c..c87a922 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3494,6 +3494,13 @@ resolved "https://registry.npmjs.org/@types/node/-/node-16.11.18.tgz#39ed7c52943b0cee6d7299b717707bd51b1f90b9" integrity sha512-7N8AOYWWYuw0g+K+GKCmIwfU1VMHcexYNpLPYzFZ4Uq2W6C/ptfeC7XhXgy/4pcwhz/9KoS5yijMfnYQ0u0Udw== +"@types/node@^22.0.0": + version "22.4.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.4.1.tgz#9b595d292c65b94c20923159e2ce947731b6fdce" + integrity sha512-1tbpb9325+gPnKK0dMm+/LMriX0vKxf6RnB0SZUqfyVkQ4fMgUSySqhxE/y8Jvs4NyF1yHzTfG9KlnkIODxPKg== + dependencies: + undici-types "~6.19.2" + "@types/normalize-package-data@^2.4.0", "@types/normalize-package-data@^2.4.1": version "2.4.1" resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" @@ -11949,10 +11956,10 @@ performance-now@^2.1.0: resolved "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== -piclist@^1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/piclist/-/piclist-1.9.1.tgz#19be64573c06d824b43d8c4dab7e4819dbaca7f4" - integrity sha512-esSNT3tkIv3bi+78vmTsRdjmtIL71mP7vsEjadjQR9cuIulu0eN1+aovarAmNqf+RjdRLHB7XffxtPQEMuv4lQ== +piclist@^1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/piclist/-/piclist-1.9.3.tgz#3aa769237935a70fdb786a46f5ed46b762e38dd9" + integrity sha512-nWorUUyBmDJ6ZtHXHVa1dn4PHiKjION9izdj+xcgGkwgQj4xegKWLsivEgdMEV8e+iuulO6e+n1+pQcqOqqasg== dependencies: "@aws-sdk/client-s3" "3.421.0" "@aws-sdk/lib-storage" "3.421.0" @@ -13951,7 +13958,16 @@ strict-uri-encode@^1.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -14017,7 +14033,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -14045,6 +14061,13 @@ strip-ansi@^5.1.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -14707,6 +14730,11 @@ unbzip2-stream@^1.0.9: buffer "^5.2.1" through "^2.3.8" +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + unescape@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz#956e430f61cad8a4d57d82c518f5e6cc5d0dda96" @@ -15525,7 +15553,7 @@ wordwrap@^1.0.0: resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -15542,6 +15570,15 @@ wrap-ansi@^3.0.1: string-width "^2.1.1" strip-ansi "^4.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"