Merge branch 'dev' into release

This commit is contained in:
Kuingsmile 2023-10-14 19:30:45 +08:00
commit 7af7830f3c
20 changed files with 855 additions and 1092 deletions

View File

@ -1,3 +1,31 @@
## :tada: 2.6.4 (2023-10-14)
### :sparkles: Features
* add piclist itself as a picbed ([9f49fc0](https://github.com/Kuingsmile/piclist/commit/9f49fc0))
* **custom:** add tk analytic ([e8ea905](https://github.com/Kuingsmile/piclist/commit/e8ea905))
### :bug: Bug Fixes
* **custom:** fix bump version error ([6f8e4e1](https://github.com/Kuingsmile/piclist/commit/6f8e4e1))
* fix font file download logic ([32de515](https://github.com/Kuingsmile/piclist/commit/32de515))
* fix macos right click menu file bug ([75601e7](https://github.com/Kuingsmile/piclist/commit/75601e7))
* fix manage config file sync bug ([47b61e6](https://github.com/Kuingsmile/piclist/commit/47b61e6))
### :pencil: Documentation
* **custom:** update docs ([d1780f2](https://github.com/Kuingsmile/piclist/commit/d1780f2))
### :package: Chore
* **custom:** migrate to node-bump-version ([567af45](https://github.com/Kuingsmile/piclist/commit/567af45))
## :tada: 2.6.3 (2023-10-10)

View File

@ -100,6 +100,7 @@ In the community plugins, search for and install the Image auto upload Plugin. N
| Local | ✔️ | ✔️ |
| Built-in SFTP | ✔️ | ✔️ |
| Doge Cloud | ✔️ | ✔️ |
| PicList(Lasso-Doll) | ✔️ | ✔️ |
| Plugin | Album cloud deletion |
| :----------------------------------------------------------------------------------------: | :------------------: |

View File

@ -100,6 +100,7 @@ MacOS:
| 本地文件夹 | ✔️ | ✔️ |
| 内置SFTP | ✔️ | ✔️ |
| 多吉云 | ✔️ | ✔️ |
| PicList(套娃) | ✔️ | ✔️ |
| 插件 | 相册云删除 |
| :----------------------------------------------------------------------------------------: | :--------: |

View File

@ -1,11 +1,11 @@
✨ Features
- 现在当已经设置了水印字体文件路径或使用图片水印时,不再检查内置字体文件是否存在
- PicList和PicList-Core的内置服务器现在均支持通过`formData`的方式上传图片文件
- 内置服务器现在默认监听`0.0.0.0`,而不是`127.0.0.1`,以配合多电脑间使用
- 内置服务器现在支持设置鉴权密钥`key`参数通过url参数形式传递`?key=xxx`,避免被恶意利用
- PicList-Core现在支持通过`picgo-server`启动内置上传服务器使用方式与PicList的内置服务器相同
- 现在当设置了内置服务器鉴权密钥时图床设置界面复制api接口会自动添加密钥
- 添加了`PicList`自身作为套娃图床实现A电脑添加B电脑的`PicList`进行上传的功能
- 新增上传耗时等统计功能
🐛 Bug Fixes
- 修复了没有新建临时文件夹导致本地图床上传失败的问题
- 修复了电脑间同步管理配置文件时,无法正常进入图床,需要重新保存一次配置的问题
- 修复了arm mac平台缺失右键菜单的问题
- 修复了跳过水印字体下载没有对文件上传情景生效的问题

View File

@ -1,11 +1,11 @@
✨ Features
- Now that the watermark font file path has been set or the image watermark is used, the built-in font file is no longer checked
- The built-in server of PicList and PicList-Core now support uploading image files through `formData`
- PicList-Core now supports starting the built-in upload server through `picgo-server`, and the usage is the same as the built-in server of PicList
- The built-in server now supports setting the authentication key `key` parameter, which is passed in the form of url parameters `?key=xxx` to avoid being maliciously used
- PicList-Core now supports starting the built-in upload server through `picgo-server`, and the usage is the same as the built-in server of PicList
- Now when the built-in server authentication key is set, the copy API interface in the image bed setting interface will automatically add the key
- Added `PicList` itself as a nested image bed, which realizes the function of A computer adding B computer's `PicList` for uploading
- Added upload time consumption and other statistics functions
🐛 Bug Fixes
- Fix the problem that the local image bed upload fails due to not creating a new temporary folder
- Fixed the problem that when synchronizing and managing configuration files between computers, the image bed cannot be entered normally, and the configuration needs to be saved again
- Fixed the problem that the right-click menu is missing on the arm mac platform
- Fixed the problem that skipping the watermark font download does not take effect on file upload scenarios

View File

@ -1,6 +1,6 @@
{
"name": "piclist",
"version": "2.6.3",
"version": "2.6.4",
"author": {
"name": "Kuingsmile",
"email": "pkukuing@gmail.com"
@ -52,7 +52,7 @@
"cos-nodejs-sdk-v5": "^2.12.4",
"dexie": "^3.2.4",
"electron-updater": "^6.1.4",
"element-plus": "2.3.14",
"element-plus": "2.4.0",
"epipebomb": "^1.0.0",
"fast-xml-parser": "^4.3.2",
"form-data": "^4.0.0",
@ -68,8 +68,8 @@
"multer": "^1.4.5-lts.1",
"node-ssh-no-cpu-features": "^1.0.1",
"nodejs-file-downloader": "^4.12.1",
"piclist": "^1.3.4",
"pinia": "^2.1.6",
"piclist": "^1.6.0",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.0",
"qiniu": "^7.9.0",
"qrcode.vue": "^3.4.1",
@ -89,7 +89,6 @@
"devDependencies": {
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
"@electron/notarize": "^2.1.0",
"@picgo/bump-version": "^1.1.2",
"@types/ali-oss": "^6.16.9",
"@types/electron-devtools-installer": "^2.2.3",
"@types/fs-extra": "^11.0.2",
@ -105,8 +104,8 @@
"@types/upyun": "^3.4.1",
"@types/uuid": "^9.0.3",
"@types/write-file-atomic": "^4.0.1",
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-plugin-eslint": "^5.0.8",
"@vue/cli-plugin-router": "^5.0.8",
@ -128,8 +127,9 @@
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.17.0",
"husky": "^3.1.0",
"node-bump-version": "^1.0.2",
"node-loader": "^2.0.0",
"npm-check-updates": "^16.14.5",
"npm-check-updates": "^16.14.6",
"stylus": "^0.59.0",
"stylus-loader": "^7.1.3",
"typescript": "^4.9.5",
@ -137,7 +137,7 @@
},
"commitlint": {
"extends": [
"./node_modules/@picgo/bump-version/commitlint-picgo"
"./node_modules/node-bump-version/commitlint-node"
]
},
"config": {
@ -145,7 +145,7 @@
"path": "./node_modules/cz-customizable"
},
"cz-customizable": {
"config": "./node_modules/@picgo/bump-version/.cz-config.js"
"config": "./node_modules/node-bump-version/.cz-config.js"
}
},
"husky": {

View File

@ -6,6 +6,7 @@ import router from './renderer/router'
import ElementUI from 'element-plus'
import 'element-plus/dist/index.css'
import VueLazyLoad from 'vue3-lazyload'
import { initTalkingData } from './renderer/utils/analytic'
import vue3PhotoPreview from 'vue3-photo-preview'
import 'vue3-photo-preview/dist/index.css'
import VueVideoPlayer from '@videojs-player/vue'
@ -83,3 +84,5 @@ console.log(hljsCommon.highlightAuto('<h1>Highlight.js has been registered succe
app.use(hljsVuePlugin)
app.use(VueVideoPlayer)
app.mount('#app')
initTalkingData()

View File

@ -18,7 +18,7 @@ import {
import picgo from '@core/picgo'
import db from '~/main/apis/core/datastore'
import windowManager from 'apis/app/window/windowManager'
import { showNotification, getClipboardFilePath } from '~/main/utils/common'
import { showNotification, getClipboardFilePath, calcDurationRange } from '~/main/utils/common'
import logger from '@core/picgo/logger'
import { T } from '~/main/i18n'
import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static'
@ -30,7 +30,8 @@ import { IWindowList } from '#/types/enum'
import { IPicGo } from 'piclist'
import {
GET_RENAME_FILE_NAME,
RENAME_FILE_NAME
RENAME_FILE_NAME,
TALKING_DATA_EVENT
} from '~/universal/events/constants'
const waitForRename = (window: BrowserWindow, id: number): Promise<string|null> => {
@ -48,6 +49,20 @@ const waitForRename = (window: BrowserWindow, id: number): Promise<string|null>
})
}
const handleTalkingData = (webContents: WebContents, options: IAnalyticsData) => {
const data: ITalkingDataOptions = {
EventId: 'upload',
Label: options.type,
MapKv: {
by: options.fromClipboard ? 'clipboard' : 'files',
count: options.count,
duration: calcDurationRange(options.duration || 0),
type: options.type
}
}
webContents.send(TALKING_DATA_EVENT, data)
}
class Uploader {
private webContents: WebContents | null = null
// private uploading: boolean = false
@ -142,8 +157,17 @@ class Uploader {
async upload (img?: IUploadOption): Promise<ImgInfo[]|false> {
try {
const startTime = Date.now()
const output = await picgo.upload(img)
if (Array.isArray(output) && output.some((item: ImgInfo) => item.imgUrl)) {
if (this.webContents) {
handleTalkingData(this.webContents, {
fromClipboard: !img,
type: db.get('picBed.uploader') || db.get('picBed.current') || 'smms',
count: img ? img.length : 1,
duration: Date.now() - startTime
} as IAnalyticsData)
}
output.forEach((item: ImgInfo) => {
item.config = JSON.parse(JSON.stringify(db.get(`picBed.${item.type}`)))
})

View File

@ -16,6 +16,30 @@ function beforeOpen () {
resolveOtherI18nFiles()
}
function copyFileOutsideOfElectronAsar (
sourceInAsarArchive: string,
destOutsideAsarArchive: string
) {
if (fs.existsSync(sourceInAsarArchive)) {
// file will be copied
if (fs.statSync(sourceInAsarArchive).isFile()) {
const file = destOutsideAsarArchive
const dir = path.dirname(file)
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true })
}
fs.writeFileSync(file, fs.readFileSync(sourceInAsarArchive))
} else if (fs.statSync(sourceInAsarArchive).isDirectory()) {
fs.readdirSync(sourceInAsarArchive).forEach(function (fileOrFolderName) {
copyFileOutsideOfElectronAsar(
`${sourceInAsarArchive}/${fileOrFolderName}`,
`${destOutsideAsarArchive}/${fileOrFolderName}`
)
})
}
}
}
/**
* macOS
*/
@ -23,7 +47,7 @@ function resolveMacWorkFlow () {
const dest = `${os.homedir()}/Library/Services/Upload pictures with PicList.workflow`
if (fs.existsSync(dest)) return true
try {
fs.copySync(path.join(__static, 'Upload pictures with PicList.workflow'), dest)
copyFileOutsideOfElectronAsar(path.join(__static, 'Upload pictures with PicList.workflow'), dest)
} catch (e) {
console.log(e)
}

View File

@ -57,6 +57,30 @@ export const showMessageBox = (options: any) => {
})
}
export const calcDurationRange = (duration: number) => {
if (duration < 1000) {
return 500
} else if (duration < 1500) {
return 1000
} else if (duration < 3000) {
return 2000
} else if (duration < 5000) {
return 3000
} else if (duration < 7000) {
return 5000
} else if (duration < 10000) {
return 8000
} else if (duration < 12000) {
return 10000
} else if (duration < 20000) {
return 15000
} else if (duration < 30000) {
return 20000
}
// max range
return 100000
}
/**
* macOS public.file-url will get encoded file path,
* so we need to decode it

View File

@ -12,6 +12,7 @@ import WebdavApi from './webdav'
import DogeCloudApi from './dogecloud'
import HuaweicloudApi from './huaweiyun'
import AlistApi from './alist'
import PiclistApi from './piclist'
const apiMap: IStringKeyMap = {
aliyun: AliyunApi,
@ -27,7 +28,8 @@ const apiMap: IStringKeyMap = {
webdavplist: WebdavApi,
dogecloud: DogeCloudApi,
'huaweicloud-uploader': HuaweicloudApi,
alist: AlistApi
alist: AlistApi,
piclist: PiclistApi
}
export default class ALLApi {

View File

@ -0,0 +1,27 @@
import axios, { AxiosResponse } from 'axios'
export default class PiclistApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
const { config, fullResult } = configMap
const { host, port } = config
if (!host) {
console.error('PiclistApi.delete: invalid params')
return false
}
const url = `http://${host || '127.0.0.1'}:${port || 36677}/delete`
try {
const response: AxiosResponse = await axios.post(
url,
{
list: [fullResult]
}
)
return response.status === 200 && response.data?.success
} catch (error) {
console.error(error)
return false
}
}
}

View File

@ -569,6 +569,7 @@ function handleConfigImport (alias: string) {
}
async function getCurrentConfigList () {
await manageStore.refreshConfig()
const configList = await getPicBedsConfig<any>('uploader') ?? {}
const pbList = ['aliyun', 'aws-s3', 'github', 'imgur', 'local', 'qiniu', 'sftpplist', 'smms', 'tcyun', 'upyun', 'webdavplist']

View File

@ -242,6 +242,7 @@ async function handleCopyApi () {
if (host === '0.0.0.0') {
host = '127.0.0.1'
}
const serverKey = await getConfig('settings.serverKey') || ''
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)
@ -249,7 +250,10 @@ async function handleCopyApi () {
ElMessage.error('No config found')
return
}
const apiUrl = `http://${host}:${port}/upload?picbed=${$route.params.type}&configName=${picBedConfig?._configName}`
let apiUrl = `http://${host}:${port}/upload?picbed=${$route.params.type}&configName=${picBedConfig?._configName}`
if (serverKey) {
apiUrl += `&key=${serverKey}`
}
clipboard.writeText(apiUrl)
ElMessage.success($T('MANAGE_BUCKET_COPY_SUCCESS') + ' ' + apiUrl)
} catch (error) {

View File

@ -0,0 +1,23 @@
/* eslint-disable camelcase */
import {
TALKING_DATA_APPID, TALKING_DATA_EVENT
} from '~/universal/events/constants'
import pkg from 'root/package.json'
import { ipcRenderer } from 'electron'
import { handleTalkingDataEvent } from './common'
const { version } = pkg
export const initTalkingData = () => {
setTimeout(() => {
const talkingDataScript = document.createElement('script')
talkingDataScript.src = `http://sdk.talkingdata.com/app/h5/v1?appid=${TALKING_DATA_APPID}&vn=${version}&vc=${version}`
const head = document.getElementsByTagName('head')[0]
head.appendChild(talkingDataScript)
}, 0)
}
ipcRenderer.on(TALKING_DATA_EVENT, (_, data: ITalkingDataOptions) => {
handleTalkingDataEvent(data)
})

View File

@ -2,6 +2,16 @@ import { isReactive, isRef, toRaw, unref } from 'vue'
import { ipcRenderer } from 'electron'
import { OPEN_URL } from '~/universal/events/constants'
const isDevelopment = process.env.NODE_ENV !== 'production'
export const handleTalkingDataEvent = (data: ITalkingDataOptions) => {
const { EventId, Label = '', MapKv = {} } = data
MapKv.from = window.location.href
window.TDAPP.onEvent(EventId, Label, MapKv)
if (isDevelopment) {
console.log('talkingData', data)
}
}
/**
* get raw data from reactive or ref
*/

View File

@ -1,6 +1,8 @@
export const SHOW_INPUT_BOX = 'SHOW_INPUT_BOX'
export const SHOW_INPUT_BOX_RESPONSE = 'SHOW_INPUT_BOX_RESPONSE'
export const TOGGLE_SHORTKEY_MODIFIED_MODE = 'TOGGLE_SHORTKEY_MODIFIED_MODE'
export const TALKING_DATA_APPID = 'B743C16E2989419A9B02EDE9D1E6A530'
export const TALKING_DATA_EVENT = 'TALKING_DATA_EVENT'
export const C1N = 'WjJoeFdWWklhVTlXYVRKTU5EUmFOVkEwUlVRPQ=='
export const PICGO_SAVE_CONFIG = 'PICGO_SAVE_CONFIG'
export const PICGO_GET_CONFIG = 'PICGO_GET_CONFIG'

View File

@ -128,6 +128,12 @@ interface IBounds {
y: number
}
interface ITalkingDataOptions {
EventId: string
Label?: string
MapKv?: IStringKeyMap
}
// PicGo Types
type ICtx = import('piclist').PicGo
interface IPicGoPlugin {

View File

@ -6,4 +6,4 @@ export const RELEASE_URL_BACKUP = 'https://release.piclist.cn'
export const STABLE_RELEASE_URL = 'https://github.com/Kuingsmile/PicList/releases/latest'
export const C1 = Buffer.from(C1N, 'base64').toString()
export const picBedsCanbeDeleted = ['aliyun', 'aws-s3', 'github', 'imgur', 'local', 'sftpplist', 'smms', 'qiniu', 'tcyun', 'upyun', 'webdavplist', 'dogecloud', 'huaweicloud-uploader', 'alist']
export const picBedsCanbeDeleted = ['aliyun', 'aws-s3', 'github', 'imgur', 'local', 'sftpplist', 'smms', 'qiniu', 'tcyun', 'upyun', 'webdavplist', 'dogecloud', 'huaweicloud-uploader', 'alist', 'piclist']

1711
yarn.lock

File diff suppressed because it is too large Load Diff