Merge commit 'ee7747daae59b3ef46642cff2b6730b658a0892a' into release

This commit is contained in:
萌萌哒赫萝 2023-09-06 20:46:58 -07:00
commit 6f36c11d05
17 changed files with 208 additions and 79 deletions

View File

@ -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)

View File

@ -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.

View File

@ -34,7 +34,7 @@ PicList的内核使用的是原版PicGo-Core基础上修改的[PicList-core](htt
## 特色功能
- 保留了PicGo的所有功能兼容绝大部分已有的PicGo插件包括和Typora、Obsidian等软件的搭配
- 新增了多个内置图床如WebDav、本地图床和SFTP原内置imgur图床额外支持登录账号上传
- 新增了多个内置图床如WebDav、本地图床、SFTP和Telegra.ph原内置imgur图床额外支持登录账号上传
- 相册中可同步删除云端图片,支持所有内置图床和多个插件
- 相册新增了高级搜索和排序批量修改URL等功能
- 内置水印添加、图片压缩、图片缩放、图片旋转和图片格式转换等功能,同时支持高级重命名

View File

@ -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",

View File

@ -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)

View File

@ -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则按宽度等比缩放)

View File

@ -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則按寬度等比縮放)

View File

@ -144,7 +144,7 @@ const buildMainPageMenu = (win: BrowserWindow) => {
{
label: T('SHOW_DEVTOOLS'),
click () {
win?.webContents?.openDevTools()
win?.webContents?.openDevTools({ mode: 'detach' })
}
}
]

View File

@ -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
})
})
}

View File

@ -1,12 +1,12 @@
class Router {
private router = new Map<string, routeHandler>()
private router = new Map<string, {handler: routeHandler, urlparams?: URLSearchParams}>()
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) {

View File

@ -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<void> => {
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<IStringKeyMap>('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<IStringKeyMap>('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({

View File

@ -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) {

View File

@ -1369,6 +1369,24 @@
/>
</el-select>
</el-form-item>
<el-form-item
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISFLIP')"
>
<el-switch
v-model="compressForm.isFlip"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISFLOP')"
>
<el-switch
v-model="compressForm.isFlop"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISRESIZE')"
>
@ -1566,7 +1584,9 @@ const compressForm = reactive<any>({
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

View File

@ -300,6 +300,24 @@
/>
</el-select>
</el-form-item>
<el-form-item
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISFLIP')"
>
<el-switch
v-model="compressForm.isFlip"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISFLOP')"
>
<el-switch
v-model="compressForm.isFlop"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<el-form-item
:label="$T('UPLOAD_PAGE_IMAGE_PROCESS_ISRESIZE')"
>
@ -486,7 +504,9 @@ const compressForm = reactive<any>({
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

View File

@ -10,14 +10,26 @@
>
<div
class="view-title"
@click="handleNameClick"
>
{{ picBedName }} {{ $T('SETTINGS') }}
<span
class="view-title-text"
@click="handleNameClick"
>
{{ picBedName }} {{ $T('SETTINGS') }}</span>
<el-icon
v-if="linkToLogInList.includes(picBedName)"
>
<Link />
</el-icon>
<el-button
type="primary"
round
size="small"
style="margin-left: 6px"
@click="handleCopyApi"
>
{{ $T('UPLOAD_PAGE_COPY_UPLOAD_API') }}
</el-button>
</div>
<config-form
v-if="config.length > 0"
@ -95,7 +107,7 @@ import { ref, onBeforeUnmount, onBeforeMount } from 'vue'
import { T as $T } from '@/i18n/index'
//
import { sendToMain, triggerRPC } from '@/utils/dataSender'
import { getConfig, sendToMain, triggerRPC } from '@/utils/dataSender'
// Vue Router
import { useRoute, useRouter } from 'vue-router'
@ -105,6 +117,7 @@ import ConfigForm from '@/components/ConfigForm.vue'
// Electron
import {
clipboard,
ipcRenderer,
IpcRendererEvent
} from 'electron'
@ -119,7 +132,7 @@ import { Link } from '@element-plus/icons-vue'
import dayjs from 'dayjs'
// Element Plus
import { ElDropdown } from 'element-plus'
import { ElDropdown, ElMessage } from 'element-plus'
const type = ref('')
const config = ref<IPicGoPluginConfig[]>([])
@ -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<IStringKeyMap>('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

View File

@ -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

View File

@ -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"