diff --git a/CHANGELOG.md b/CHANGELOG.md index 310aedf..cb450a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +## :tada: 2.5.3 (2023-09-07) + + +### :sparkles: Features + +* add telegra.ph picbed support ([dd6bfe6](https://github.com/Kuingsmile/PicList/commit/dd6bfe6)) +* add vertically and horizontally flip treat options for image processing ([cb76a34](https://github.com/Kuingsmile/PicList/commit/cb76a34)) +* optimize api copy ([08b45bc](https://github.com/Kuingsmile/PicList/commit/08b45bc)) +* upload api now support url query picbed and configname ([2fcec70](https://github.com/Kuingsmile/PicList/commit/2fcec70)), closes [#93](https://github.com/Kuingsmile/PicList/issues/93) + + +### :pencil: Documentation + +* update readme ([f9a3f24](https://github.com/Kuingsmile/PicList/commit/f9a3f24)) + + + ## :tada: 2.5.2 (2023-09-04) diff --git a/README.md b/README.md index a1bf41c..4fab5a5 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ if you want to use PicList-core, please go to [https://github.com/Kuingsmile/Pic ## Features - Retains all the features of PicGo and is compatible with the vast majority of existing PicGo plugins, including integrations with software like Typora and Obsidian. -- Added multiple built-in image hosting platforms, such as WebDav, local image hosting, and SFTP. The original built-in imgur image host now also supports account login for uploading. +- Added multiple built-in image hosting platforms, such as WebDav, local image hosting, SFTP and Telegra.ph. The original built-in imgur image host now also supports account login for uploading. - Within the album, you can synchronize the deletion of cloud images. This is supported across all built-in image hosts and multiple plugins. - The album now offers advanced search and sorting features, as well as batch URL modification. - Built-in tools for adding watermarks, compressing images, scaling images, rotating images, and converting image formats are now available. Advanced renaming is also supported. diff --git a/README_cn.md b/README_cn.md index f2758bb..e3dadc1 100644 --- a/README_cn.md +++ b/README_cn.md @@ -34,7 +34,7 @@ PicList的内核使用的是原版PicGo-Core基础上修改的[PicList-core](htt ## 特色功能 - 保留了PicGo的所有功能,兼容绝大部分已有的PicGo插件,包括和Typora、Obsidian等软件的搭配 -- 新增了多个内置图床,如WebDav、本地图床和SFTP等,原内置imgur图床额外支持登录账号上传 +- 新增了多个内置图床,如WebDav、本地图床、SFTP和Telegra.ph等,原内置imgur图床额外支持登录账号上传 - 相册中可同步删除云端图片,支持所有内置图床和多个插件 - 相册新增了高级搜索和排序,批量修改URL等功能 - 内置水印添加、图片压缩、图片缩放、图片旋转和图片格式转换等功能,同时支持高级重命名 diff --git a/package.json b/package.json index d282149..037a204 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "piclist", - "version": "2.5.2", + "version": "2.5.3", "author": { "name": "Kuingsmile", "email": "pkukuing@gmail.com" @@ -68,7 +68,7 @@ "mitt": "^3.0.1", "node-ssh-no-cpu-features": "^1.0.1", "nodejs-file-downloader": "^4.12.1", - "piclist": "^1.0.1", + "piclist": "^1.0.3", "pinia": "^2.1.6", "pinia-plugin-persistedstate": "^3.2.0", "qiniu": "^7.9.0", diff --git a/public/i18n/en.yml b/public/i18n/en.yml index a892652..d7a66a2 100644 --- a/public/i18n/en.yml +++ b/public/i18n/en.yml @@ -99,6 +99,7 @@ GALLERY_SEARCH_FILENAME: Search by Filename GALLERY_SEARCH_URL: Search by URL GALLERY_MATCHED: ' Matched: ' +UPLOAD_PAGE_COPY_UPLOAD_API: Copy Upload API UPLOAD_PAGE_IMAGE_PROCESS_NAME: Image Processing UPLOAD_PAGE_IMAGE_PROCESS_DIALOG_TITLE: Image Processing Settings UPLOAD_PAGE_IMAGE_PROCESS_ISADDWM: Add Watermark @@ -117,6 +118,8 @@ UPLOAD_PAGE_IMAGE_PROCESS_ISREMOVEEXIF: Remove EXIF Info UPLOAD_PAGE_IMAGE_PROCESS_QUALITY: Compression Quality UPLOAD_PAGE_IMAGE_PROCESS_ISCONVERT: Convert Format UPLOAD_PAGE_IMAGE_PROCESS_CONVERTFORMAT: Destination Format +UPLOAD_PAGE_IMAGE_PROCESS_ISFLIP: Whether to flip vertically +UPLOAD_PAGE_IMAGE_PROCESS_ISFLOP: Whether to flip horizontally UPLOAD_PAGE_IMAGE_PROCESS_ISRESIZE: Resize to fixed size UPLOAD_PAGE_IMAGE_PROCESS_RESIZEWIDTH: Width(Set to 0 to scale by height) UPLOAD_PAGE_IMAGE_PROCESS_RESIZEHEIGHT: Height(Set to 0 to scale by width) diff --git a/public/i18n/zh-CN.yml b/public/i18n/zh-CN.yml index 3f2f1b7..bed1bae 100644 --- a/public/i18n/zh-CN.yml +++ b/public/i18n/zh-CN.yml @@ -99,6 +99,7 @@ GALLERY_SEARCH_FILENAME: 搜索文件名 GALLERY_SEARCH_URL: 搜索URL GALLERY_MATCHED: ' 匹配到: ' +UPLOAD_PAGE_COPY_UPLOAD_API: 复制上传API UPLOAD_PAGE_IMAGE_PROCESS_NAME: 图片处理 UPLOAD_PAGE_IMAGE_PROCESS_DIALOG_TITLE: 图片处理设置 UPLOAD_PAGE_IMAGE_PROCESS_ISADDWM: 是否添加水印 @@ -117,6 +118,8 @@ UPLOAD_PAGE_IMAGE_PROCESS_ISREMOVEEXIF: 是否移除EXIF信息 UPLOAD_PAGE_IMAGE_PROCESS_QUALITY: 压缩质量 UPLOAD_PAGE_IMAGE_PROCESS_ISCONVERT: 是否转换格式 UPLOAD_PAGE_IMAGE_PROCESS_CONVERTFORMAT: 转换目的格式 +UPLOAD_PAGE_IMAGE_PROCESS_ISFLIP: 是否进行垂直翻转 +UPLOAD_PAGE_IMAGE_PROCESS_ISFLOP: 是否进行水平翻转 UPLOAD_PAGE_IMAGE_PROCESS_ISRESIZE: 是否按固定尺寸调整图片 UPLOAD_PAGE_IMAGE_PROCESS_RESIZEWIDTH: 调整尺寸宽度(设为0则按高度等比缩放) UPLOAD_PAGE_IMAGE_PROCESS_RESIZEHEIGHT: 调整尺寸高度(设为0则按宽度等比缩放) diff --git a/public/i18n/zh-TW.yml b/public/i18n/zh-TW.yml index e2e4dc8..8a1b1fc 100644 --- a/public/i18n/zh-TW.yml +++ b/public/i18n/zh-TW.yml @@ -99,6 +99,7 @@ GALLERY_SEARCH_FILENAME: 搜尋文件名 GALLERY_SEARCH_URL: 搜尋URL GALLERY_MATCHED: ' 匹配到: ' +UPLOAD_PAGE_COPY_UPLOAD_API: 複製上傳API UPLOAD_PAGE_IMAGE_PROCESS_NAME: 圖片處理 UPLOAD_PAGE_IMAGE_PROCESS_DIALOG_TITLE: 圖片處理設置 UPLOAD_PAGE_IMAGE_PROCESS_ISADDWM: 是否添加水印 @@ -117,6 +118,8 @@ UPLOAD_PAGE_IMAGE_PROCESS_ISREMOVEEXIF: 是否移除EXIF信息 UPLOAD_PAGE_IMAGE_PROCESS_QUALITY: 壓縮質量 UPLOAD_PAGE_IMAGE_PROCESS_ISCONVERT: 是否轉換格式 UPLOAD_PAGE_IMAGE_PROCESS_CONVERTFORMAT: 轉換目的格式 +UPLOAD_PAGE_IMAGE_PROCESS_ISFLIP: 是否進行垂直翻轉 +UPLOAD_PAGE_IMAGE_PROCESS_ISFLOP: 是否進行水平翻轉 UPLOAD_PAGE_IMAGE_PROCESS_ISRESIZE: 是否按固定尺寸調整圖片 UPLOAD_PAGE_IMAGE_PROCESS_RESIZEWIDTH: 調整尺寸寬度(設為0則按高度等比縮放) UPLOAD_PAGE_IMAGE_PROCESS_RESIZEHEIGHT: 調整尺寸高度(設為0則按寬度等比縮放) diff --git a/src/main/events/remotes/menu.ts b/src/main/events/remotes/menu.ts index ff0ce82..6701501 100644 --- a/src/main/events/remotes/menu.ts +++ b/src/main/events/remotes/menu.ts @@ -144,7 +144,7 @@ const buildMainPageMenu = (win: BrowserWindow) => { { label: T('SHOW_DEVTOOLS'), click () { - win?.webContents?.openDevTools() + win?.webContents?.openDevTools({ mode: 'detach' }) } } ] diff --git a/src/main/server/index.ts b/src/main/server/index.ts index 32f78e5..a59b2a4 100644 --- a/src/main/server/index.ts +++ b/src/main/server/index.ts @@ -44,8 +44,9 @@ class Server { } if (request.method === 'POST') { - if (!routers.getHandler(request.url!)) { - logger.warn(`[PicList Server] don't support [${request.url}] url`) + const [url, query] = request.url!.split('?') + if (!routers.getHandler(url!)) { + logger.warn(`[PicList Server] don't support [${url}] url`) handleResponse({ response, statusCode: 404, @@ -73,10 +74,11 @@ class Server { }) } logger.info('[PicList Server] get the request', body) - const handler = routers.getHandler(request.url!) + const handler = routers.getHandler(url!)?.handler handler!({ ...postObj, - response + response, + urlparams: query ? new URLSearchParams(query) : undefined }) }) } diff --git a/src/main/server/router.ts b/src/main/server/router.ts index 4c984ae..1f5dc3e 100644 --- a/src/main/server/router.ts +++ b/src/main/server/router.ts @@ -1,12 +1,12 @@ class Router { - private router = new Map() + private router = new Map() - get (url: string, callback: routeHandler): void { - this.router.set(url, callback) + get (url: string, callback: routeHandler, urlparams?: URLSearchParams): void { + this.router.set(url, { handler: callback, urlparams }) } - post (url: string, callback: routeHandler): void { - this.router.set(url, callback) + post (url: string, callback: routeHandler, urlparams?: URLSearchParams): void { + this.router.set(url, { handler: callback, urlparams }) } getHandler (url: string) { diff --git a/src/main/server/routerManager.ts b/src/main/server/routerManager.ts index c21eed6..f391dd7 100644 --- a/src/main/server/routerManager.ts +++ b/src/main/server/routerManager.ts @@ -7,6 +7,8 @@ import windowManager from 'apis/app/window/windowManager' import { uploadChoosedFiles, uploadClipboardFiles, deleteChoosedFiles } from 'apis/app/uploader/apis' import path from 'path' import { dbPathDir } from 'apis/core/datastore/dbChecker' +import picgo from '@core/picgo' +import { changeCurrentUploader } from '../utils/handleUploaderConfig' const STORE_PATH = dbPathDir() const LOG_PATH = path.join(STORE_PATH, 'piclist.log') @@ -16,12 +18,39 @@ const deleteErrorMessage = `delete error. see ${LOG_PATH} for more detail.` router.post('/upload', async ({ response, - list = [] + list = [], + urlparams } : { response: IHttpResponse, - list?: string[] + list?: string[], + urlparams?: URLSearchParams }): Promise => { try { + const picbed = urlparams?.get('picbed') + let currentPicBedType = '' + let currentPicBedConfig = {} as IStringKeyMap + let currentPicBedConfigId = '' + let needRestore = false + if (picbed) { + const configName = urlparams?.get('configName') || 'Default' + const currentPicBed = picgo.getConfig('picBed') || {} as IStringKeyMap + currentPicBedType = currentPicBed?.current + currentPicBedConfig = currentPicBed?.[currentPicBedType] + currentPicBedConfigId = currentPicBedConfig?._id + if (picbed === currentPicBedType && configName === currentPicBedConfig._configName) { + // do nothing + } else { + needRestore = true + const picBeds = picgo.getConfig('uploader') + const currentPicBedList = picBeds?.[picbed]?.configList + if (currentPicBedList) { + const currentConfig = currentPicBedList?.find((item: any) => item._configName === configName) + if (currentConfig) { + changeCurrentUploader(picbed, currentConfig, currentConfig._id) + } + } + } + } if (list.length === 0) { // upload with clipboard logger.info('[PicList Server] upload clipboard file') @@ -83,6 +112,9 @@ router.post('/upload', async ({ }) } } + if (needRestore) { + changeCurrentUploader(currentPicBedType, currentPicBedConfig, currentPicBedConfigId) + } } catch (err: any) { logger.error(err) handleResponse({ diff --git a/src/renderer/pages/Gallery.vue b/src/renderer/pages/Gallery.vue index a7a9c12..8ab5503 100644 --- a/src/renderer/pages/Gallery.vue +++ b/src/renderer/pages/Gallery.vue @@ -682,59 +682,45 @@ async function copy (item: ImgInfo) { } function remove (item: ImgInfo) { - if (item.id) { - $confirm($T('TIPS_REMOVE_LINK'), $T('TIPS_NOTICE'), { - confirmButtonText: $T('CONFIRM'), - cancelButtonText: $T('CANCEL'), - type: 'warning' - }).then(async () => { - const file = await $$db.getById(item.id!) - if (await getConfig('settings.deleteCloudFile')) { - if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) { - const result = await ALLApi.delete(item) - if (result) { - ElNotification({ - title: $T('GALLERY_SYNC_DELETE_NOTICE_TITLE'), - message: `${item.fileName} ${$T('GALLERY_SYNC_DELETE_NOTICE_SUCCEED')}`, - type: 'success' - }) - await $$db.removeById(item.id!) - sendToMain('removeFiles', [file]) - const obj = { - title: $T('OPERATION_SUCCEED'), - body: '' - } - const myNotification = new Notification(obj.title, obj) - myNotification.onclick = () => { - return true - } - updateGallery() - } else { - ElNotification({ - title: $T('GALLERY_SYNC_DELETE_NOTICE_TITLE'), - message: `${item.fileName} ${$T('GALLERY_SYNC_DELETE_NOTICE_FAILED')}`, - type: 'error' - }) - } - } + if (!item.id) return + $confirm($T('TIPS_REMOVE_LINK'), $T('TIPS_NOTICE'), { + confirmButtonText: $T('CONFIRM'), + cancelButtonText: $T('CANCEL'), + type: 'warning' + }).then(async () => { + const file = await $$db.getById(item.id!) + if (await getConfig('settings.deleteCloudFile') && picBedsCanbeDeleted.includes(item?.type || 'placeholder')) { + const result = await ALLApi.delete(item) + if (result) { + ElNotification({ + title: $T('GALLERY_SYNC_DELETE_NOTICE_TITLE'), + message: `${item.fileName} ${$T('GALLERY_SYNC_DELETE_NOTICE_SUCCEED')}`, + type: 'success' + }) } else { - await $$db.removeById(item.id!) - sendToMain('removeFiles', [file]) - const obj = { - title: $T('OPERATION_SUCCEED'), - body: '' - } - const myNotification = new Notification(obj.title, obj) - myNotification.onclick = () => { - return true - } - updateGallery() + ElNotification({ + title: $T('GALLERY_SYNC_DELETE_NOTICE_TITLE'), + message: `${item.fileName} ${$T('GALLERY_SYNC_DELETE_NOTICE_FAILED')}`, + type: 'error' + }) + return true } - }).catch((e) => { - console.log(e) + } + await $$db.removeById(item.id!) + sendToMain('removeFiles', [file]) + const obj = { + title: $T('OPERATION_SUCCEED'), + body: '' + } + const myNotification = new Notification(obj.title, obj) + myNotification.onclick = () => { return true - }) - } + } + updateGallery() + }).catch((e) => { + console.log(e) + return true + }) } function handleDeleteCloudFile (val: ICheckBoxValueType) { diff --git a/src/renderer/pages/PicGoSetting.vue b/src/renderer/pages/PicGoSetting.vue index ec67b4b..106b445 100644 --- a/src/renderer/pages/PicGoSetting.vue +++ b/src/renderer/pages/PicGoSetting.vue @@ -1369,6 +1369,24 @@ /> + + + + + + @@ -1566,7 +1584,9 @@ const compressForm = reactive({ reSizePercent: 50, isRotate: false, rotateDegree: 0, - isRemoveExif: false + isRemoveExif: false, + isFlip: false, + isFlop: false }) function closeDialog () { @@ -1595,6 +1615,8 @@ async function initForm () { compressForm.isRotate = compress.isRotate ?? false compressForm.rotateDegree = compress.rotateDegree ?? 0 compressForm.isRemoveExif = compress.isRemoveExif ?? false + compressForm.isFlip = compress.isFlip ?? false + compressForm.isFlop = compress.isFlop ?? false } if (watermark) { waterMarkForm.isAddWatermark = watermark.isAddWatermark ?? false diff --git a/src/renderer/pages/Upload.vue b/src/renderer/pages/Upload.vue index 4026765..7b8cc44 100644 --- a/src/renderer/pages/Upload.vue +++ b/src/renderer/pages/Upload.vue @@ -300,6 +300,24 @@ /> + + + + + + @@ -486,7 +504,9 @@ const compressForm = reactive({ reSizePercent: 50, isRotate: false, rotateDegree: 0, - isRemoveExif: false + isRemoveExif: false, + isFlip: false, + isFlop: false }) function closeDialog () { @@ -515,6 +535,8 @@ async function initData () { compressForm.isRotate = compress.isRotate ?? false compressForm.rotateDegree = compress.rotateDegree ?? 0 compressForm.isRemoveExif = compress.isRemoveExif ?? false + compressForm.isFlip = compress.isFlip ?? false + compressForm.isFlop = compress.isFlop ?? false } if (watermark) { waterMarkForm.isAddWatermark = watermark.isAddWatermark ?? false diff --git a/src/renderer/pages/picbeds/index.vue b/src/renderer/pages/picbeds/index.vue index b2e317c..47acb44 100644 --- a/src/renderer/pages/picbeds/index.vue +++ b/src/renderer/pages/picbeds/index.vue @@ -10,14 +10,26 @@ >
- {{ picBedName }} {{ $T('SETTINGS') }} + + {{ picBedName }} {{ $T('SETTINGS') }} + + {{ $T('UPLOAD_PAGE_COPY_UPLOAD_API') }} +
([]) @@ -187,7 +200,7 @@ const handleReset = async () => { $router.back() } -const linkToLogInList = ['github', 'tcyun', 'aliyun', 'smms', 'qiniu', 'imgur', 'upyun', 'githubPlus'] +const linkToLogInList = ['GitHub', '腾讯云COS', '阿里云OSS', 'SM.MS', '七牛云', 'Imgur', '又拍云', 'githubPlus'] function handleNameClick () { switch ($route.params.type) { @@ -218,7 +231,30 @@ function handleNameClick () { } } -function getPicBeds (event: IpcRendererEvent, _config: IPicGoPluginConfig[], name: string) { +async function handleCopyApi () { + try { + const serverConfig = await getConfig('settings.server') || { + port: 36677, + host: '127.0.0.1' + } + const { port, host } = serverConfig + const uploader = await getConfig('uploader') as IStringKeyMap || {} + const picBedConfigList = uploader[$route.params.type as string].configList || [] + const picBedConfig = picBedConfigList.find((item: IUploaderConfigListItem) => item._id === $route.params.configId) + if (!picBedConfig) { + ElMessage.error('No config found') + return + } + const apiUrl = `http://${host}:${port}/upload?picbed=${$route.params.type}&configName=${picBedConfig?._configName}` + clipboard.writeText(apiUrl) + ElMessage.success($T('MANAGE_BUCKET_COPY_SUCCESS') + ' ' + apiUrl) + } catch (error) { + console.log(error) + ElMessage.error('Copy failed') + } +} + +function getPicBeds (_event: IpcRendererEvent, _config: IPicGoPluginConfig[], name: string) { config.value = _config picBedName.value = name } @@ -245,7 +281,7 @@ export default { height 100% overflow-y auto overflow-x hidden - .view-title + .view-title-text &:hover cursor pointer color #409EFF diff --git a/src/universal/types/i18n.d.ts b/src/universal/types/i18n.d.ts index 306081a..217745b 100644 --- a/src/universal/types/i18n.d.ts +++ b/src/universal/types/i18n.d.ts @@ -96,6 +96,7 @@ interface ILocales { GALLERY_SEARCH_FILENAME: string GALLERY_SEARCH_URL: string GALLERY_MATCHED: string + UPLOAD_PAGE_COPY_UPLOAD_API: string UPLOAD_PAGE_IMAGE_PROCESS_NAME: string UPLOAD_PAGE_IMAGE_PROCESS_DIALOG_TITLE: string UPLOAD_PAGE_IMAGE_PROCESS_ISADDWM: string @@ -114,6 +115,8 @@ interface ILocales { UPLOAD_PAGE_IMAGE_PROCESS_QUALITY: string UPLOAD_PAGE_IMAGE_PROCESS_ISCONVERT: string UPLOAD_PAGE_IMAGE_PROCESS_CONVERTFORMAT: string + UPLOAD_PAGE_IMAGE_PROCESS_ISFLIP: string + UPLOAD_PAGE_IMAGE_PROCESS_ISFLOP: string UPLOAD_PAGE_IMAGE_PROCESS_ISRESIZE: string UPLOAD_PAGE_IMAGE_PROCESS_RESIZEWIDTH: string UPLOAD_PAGE_IMAGE_PROCESS_RESIZEHEIGHT: string diff --git a/yarn.lock b/yarn.lock index f2daba6..c10fad5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12532,10 +12532,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.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/piclist/-/piclist-1.0.1.tgz#6d15ec44393de38b32ba34d041511324ec7dda55" - integrity sha512-c68ijE5Gj3E29KEc1B6F75pluldHLJvkvYmoWhNpYg1hOXGTlxepZCZm8Wp/a9NVjT8jh3zfX1fmpbFGjpOOug== +piclist@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/piclist/-/piclist-1.0.3.tgz#391c0a5fcdbed35a397c01a730711a4066a5511b" + integrity sha512-X9bBb3FbuyoYZx0BFriYU0lZdO1avbehUf7qhWMIwOdzTfY1eMtkJoNglVZ3pAfrugF2BofKco1NbUtKLfFGVA== dependencies: "@picgo/i18n" "^1.0.0" "@picgo/store" "^2.0.4"